package com.spider.quartz.task;

import com.microsoft.playwright.*;
import com.microsoft.playwright.options.LoadState;
import com.microsoft.playwright.options.WaitUntilState;
import com.spider.quartz.domain.ExcelDownloadLog;
import com.spider.quartz.mapper.ExcelDownloadLogMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 美国CPSC不合格商品爬取任务 - 主要负责网站接入和CSV下载
 */
@Component
public class CpscTask {

    @Autowired
    private ExcelDownloadLogMapper excelDownloadLogMapper;

    @Autowired
    private CpscCsvProcessor cpscCsvProcessor;

    // ===================== 配置常量 =====================
    private static final String RECALL_LIST_URL = "https://www.cpsc.gov/zh-CN/Recalls";
    private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36";

    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static final SimpleDateFormat FILE_DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");

    // 从配置文件中获取存储路径
    @Value("${ruoyi.profile}")
    private String profileDir;

    // 网络配置
    private static final int LIST_PAGE_TIMEOUT = 180000;
    private static final int MAX_RETRIES = 5;

    // 浏览器实例管理
    private Playwright playwright;
    private Browser browser;

    /**
     * 启动爬取任务 - 主要负责网站交互和CSV下载
     */
    public void startCrawl(boolean isManual) {
        String triggerType = isManual ? "手动触发" : "定时触发";
        System.out.println("【" + triggerType + "】开始执行CPSC不合格商品数据爬取任务");

        ExcelDownloadLog downloadLog = null;

        try {
            // 1. 初始化存储目录
            initSaveDirs();

            // 2. 初始化Playwright和浏览器
            initPlaywright();

            // 3. 创建下载日志记录
            downloadLog = createDownloadLog();
            if (downloadLog == null) {
                throw new RuntimeException("创建下载日志记录失败，无法继续执行");
            }

            // 4. 下载CSV文件（最多重试5次）
            File csvFile = downloadCsvWithRetry();

            if (csvFile != null) {
                // 5. 更新下载日志为成功
                updateDownloadLogSuccess(downloadLog, csvFile.getAbsolutePath());

                // 6. 调用处理器解析并保存数据
                cpscCsvProcessor.processCsvFile(csvFile);
            } else {
                // 下载失败，更新下载日志
                updateDownloadLogFailure(downloadLog, "CSV文件下载失败，重试" + MAX_RETRIES + "次后仍失败");
            }

            System.out.println("\n==================== 爬取完成 ====================");
            System.out.println("触发类型: " + triggerType);

        } catch (Exception e) {
            System.err.println("【" + triggerType + "】爬取过程异常：" + e.getMessage());
            e.printStackTrace();

            // 更新下载日志为失败
            if (downloadLog != null) {
                updateDownloadLogFailure(downloadLog, "爬取过程异常: " + e.getMessage());
            }
        } finally {
            // 关闭资源
            cleanupResources();
        }
    }

    /**
     * 创建下载日志记录
     */
    private ExcelDownloadLog createDownloadLog() {
        ExcelDownloadLog log = new ExcelDownloadLog();
        log.setType("美国");
        log.setDownloadTime(new Date());
        log.setStatus(1L); // 默认设为失败，下载成功后再更新
        log.setIsDeleted(0L); // 未删除

        // 设置创建人和创建部门
        log.setCreateUser("system");
        log.setCreateDept("system");

        try {
            int result = excelDownloadLogMapper.insertExcelDownloadLog(log);
            if (result > 0) {
                System.out.println("创建下载日志记录成功，ID: " + log.getId());
                return log;
            } else {
                System.err.println("创建下载日志记录失败");
                return null;
            }
        } catch (Exception e) {
            System.err.println("创建下载日志记录异常: " + e.getMessage());
            return null;
        }
    }

    /**
     * 更新下载日志为成功
     */
    private void updateDownloadLogSuccess(ExcelDownloadLog log, String csvPath) {
        if (log == null) {
            System.err.println("下载日志记录为空，无法更新");
            return;
        }

        log.setStatus(0L); // 成功
        log.setExcelPath(csvPath); // 保存CSV文件路径到excel_path字段

        try {
            int result = excelDownloadLogMapper.updateExcelDownloadLog(log);
            if (result > 0) {
                System.out.println("更新下载日志为成功状态，CSV路径: " + csvPath);
                // 打印日志确认路径已设置
                System.out.println("日志ID: " + log.getId() + ", ExcelPath: " + log.getExcelPath());
            } else {
                System.err.println("更新下载日志失败，影响行数: " + result);
            }
        } catch (Exception e) {
            System.err.println("更新下载日志异常: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 更新下载日志为失败
     */
    private void updateDownloadLogFailure(ExcelDownloadLog log, String errorMessage) {
        if (log == null) {
            System.err.println("下载日志记录为空，无法更新");
            return;
        }

        log.setStatus(1L); // 失败

        try {
            int result = excelDownloadLogMapper.updateExcelDownloadLog(log);
            if (result > 0) {
                System.out.println("更新下载日志为失败状态: " + errorMessage);
            } else {
                System.err.println("更新下载日志失败");
            }
        } catch (Exception e) {
            System.err.println("更新下载日志异常: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 带重试的CSV文件下载
     */
    private File downloadCsvWithRetry() {
        int retryCount = 0;

        while (retryCount < MAX_RETRIES) {
            try {
                System.out.println("开始下载CSV文件，尝试次数: " + (retryCount + 1));

                File csvFile = downloadCsvFile();

                if (csvFile != null && csvFile.exists()) {
                    System.out.println("文件下载成功:");
                    System.out.println("  文件路径: " + csvFile.getAbsolutePath());
                    System.out.println("  文件大小: " + csvFile.length() + " bytes");
                    System.out.println("  文件存在: " + csvFile.exists());
                    System.out.println("  可读取: " + csvFile.canRead());

                    return csvFile;
                } else {
                    System.err.println("文件下载失败: csvFile=" + csvFile +
                            ", exists=" + (csvFile != null && csvFile.exists()));
                }

            } catch (Exception e) {
                System.err.println("第 " + (retryCount + 1) + " 次下载失败: " + e.getMessage());
                e.printStackTrace();
            }

            retryCount++;
            if (retryCount < MAX_RETRIES) {
                try {
                    Thread.sleep(5000); // 等待5秒后重试
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }

        System.err.println("所有重试次数已用完，下载失败");
        return null;
    }

    /**
     * 下载CSV文件 - 使用传统方法避免lambda问题
     */
    private File downloadCsvFile() {
        BrowserContext context = null;
        Page page = null;

        try {
            context = browser.newContext();
            page = context.newPage();
            setEnhancedBrowserConfig(page);

            System.out.println("导航到CPSC召回列表页面: " + RECALL_LIST_URL);
            page.navigate(RECALL_LIST_URL, new Page.NavigateOptions()
                    .setTimeout(LIST_PAGE_TIMEOUT)
                    .setWaitUntil(WaitUntilState.NETWORKIDLE));

            // 等待页面加载完成
            page.waitForLoadState(LoadState.NETWORKIDLE);
            Thread.sleep(5000);

            System.out.println("页面加载完成，开始查找Export CSV标签...");

            // 等待Export CSV标签出现
            page.waitForSelector("label[for='tab2']",
                    new Page.WaitForSelectorOptions().setTimeout(30000));

            // 第一步：点击Export CSV标签
            System.out.println("点击Export CSV标签...");
            page.click("label[for='tab2']");

            // 等待选项卡内容加载
            Thread.sleep(3000);

            // 等待下载链接出现
            page.waitForSelector("a.feed-icon[href*='recalls_recall_listing-zh-hans.csv']",
                    new Page.WaitForSelectorOptions().setTimeout(30000));

            // 获取下载链接URL
            String downloadUrl = page.getAttribute("a.feed-icon[href*='recalls_recall_listing-zh-hans.csv']", "href");

            if (downloadUrl != null && !downloadUrl.isEmpty()) {
                // 如果是相对路径，转换为绝对路径
                if (downloadUrl.startsWith("/")) {
                    downloadUrl = "https://www.cpsc.gov" + downloadUrl;
                }

                System.out.println("下载链接: " + downloadUrl);

                // 直接下载文件
                File csvFile = downloadFileDirectly(downloadUrl);
                if (csvFile != null && csvFile.exists()) {
                    System.out.println("CSV文件下载成功: " + csvFile.getAbsolutePath());
                    return csvFile;
                }
            } else {
                System.err.println("无法获取下载链接");
            }

            return null;

        } catch (Exception e) {
            System.err.println("下载CSV文件失败: " + e.getMessage());

            // 保存页面截图用于调试
            if (page != null) {
                try {
                    String screenshotPath = getDataSaveDir() + File.separator + "debug_screenshot_" + System.currentTimeMillis() + ".png";
                    page.screenshot(new Page.ScreenshotOptions().setPath(new File(screenshotPath).toPath()));
                    System.out.println("已保存调试截图: " + screenshotPath);
                } catch (Exception ex) {
                    System.err.println("保存截图失败: " + ex.getMessage());
                }
            }

            return null;
        } finally {
            closeResources(page, context);
        }
    }

    /**
     * 直接下载文件的方法
     */
    private File downloadFileDirectly(String fileUrl) {
        try {
            // 生成保存路径
            String timestamp = FILE_DATE_FORMAT.format(new Date()) + "_" + System.currentTimeMillis();
            String csvFileName = "CPSC_Recalls_" + timestamp + ".csv";
            String csvFilePath = getCsvSaveDir() + File.separator + csvFileName;

            System.out.println("开始直接下载文件: " + fileUrl);
            System.out.println("保存路径: " + csvFilePath);

            // 使用URLConnection下载文件
            java.net.URL url = new java.net.URL(fileUrl);
            java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
            connection.setRequestProperty("User-Agent", USER_AGENT);
            connection.setConnectTimeout(30000);
            connection.setReadTimeout(30000);

            try (java.io.InputStream in = connection.getInputStream();
                 java.io.FileOutputStream out = new java.io.FileOutputStream(csvFilePath)) {

                byte[] buffer = new byte[8192];
                int bytesRead;
                while ((bytesRead = in.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesRead);
                }
            }

            connection.disconnect();

            File csvFile = new File(csvFilePath);
            if (csvFile.exists() && csvFile.length() > 0) {
                System.out.println("CSV文件下载成功，文件大小: " + csvFile.length() + " 字节");
                return csvFile;
            } else {
                System.err.println("CSV文件下载失败，文件不存在或为空");
                return null;
            }

        } catch (Exception e) {
            System.err.println("直接下载文件失败: " + e.getMessage());
            return null;
        }
    }

    // ===================== 辅助方法 =====================

    /**
     * 获取数据存储目录
     */
    private String getDataSaveDir() {
        return profileDir + File.separator + "US";
    }

    /**
     * 获取CSV保存目录
     */
    private String getCsvSaveDir() {
        return getDataSaveDir() + File.separator + "CSV";
    }

    /**
     * 初始化存储目录
     */
    private void initSaveDirs() {
        String dataSaveDir = getDataSaveDir();
        File dataDir = new File(dataSaveDir);
        if (!dataDir.exists() && !dataDir.mkdirs()) {
            System.err.println("数据目录创建失败：" + dataSaveDir);
            throw new RuntimeException("数据目录创建失败: " + dataSaveDir);
        }

        String csvSaveDir = getCsvSaveDir();
        File csvDir = new File(csvSaveDir);
        if (!csvDir.exists() && !csvDir.mkdirs()) {
            System.err.println("CSV目录创建失败：" + csvSaveDir);
            throw new RuntimeException("CSV目录创建失败: " + csvSaveDir);
        }

        System.out.println("CPSC数据存储目录初始化完成：" + dataSaveDir);
        System.out.println("CPSC CSV存储目录初始化完成：" + csvSaveDir);
    }

    /**
     * 初始化Playwright和浏览器
     */
    private void initPlaywright() {
        try {
            playwright = Playwright.create();
            List<String> browserArgs = Arrays.asList(
                    "--disable-gpu",
                    "--disable-extensions",
                    "--no-sandbox",
                    "--disable-dev-shm-usage",
                    "--lang=en-US",
                    "--disable-blink-features=AutomationControlled",
                    "--user-agent=" + USER_AGENT
            );

            BrowserType.LaunchOptions launchOptions = new BrowserType.LaunchOptions()
                    .setHeadless(true)
                    .setArgs(browserArgs)
                    .setTimeout(180000);

            browser = playwright.chromium().launch(launchOptions);
            System.out.println("Playwright和浏览器初始化完成");
        } catch (Exception e) {
            System.err.println("Playwright初始化失败：" + e.getMessage());
            throw new RuntimeException("Playwright初始化失败", e);
        }
    }

    /**
     * 配置浏览器
     */
    private void setEnhancedBrowserConfig(Page page) {
        Map<String, String> headers = new HashMap<>();
        headers.put("User-Agent", USER_AGENT);
        headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
        headers.put("Accept-Language", "en-US,en;q=0.9");
        headers.put("Accept-Encoding", "gzip, deflate, br");
        headers.put("Referer", "https://www.cpsc.gov/");
        page.setExtraHTTPHeaders(headers);

        page.addInitScript("() => {\n" +
                "  Object.defineProperty(navigator, 'webdriver', { get: () => undefined });\n" +
                "  delete navigator.__proto__.webdriver;\n" +
                "  Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5] });\n" +
                "  Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });\n" +
                "}");

        // 设置视口大小
        page.setViewportSize(1920, 1080);
    }

    /**
     * 清理资源
     */
    private void cleanupResources() {
        if (browser != null) {
            try {
                browser.close();
                System.out.println("浏览器已关闭");
            } catch (Exception e) {
                System.err.println("关闭浏览器时出错：" + e.getMessage());
            }
        }

        if (playwright != null) {
            try {
                playwright.close();
                System.out.println("Playwright 已关闭");
            } catch (Exception e) {
                System.err.println("关闭 Playwright 时出错：" + e.getMessage());
            }
        }
    }

    /**
     * 安全关闭资源
     */
    private void closeResources(Page page, BrowserContext context) {
        if (page != null) {
            try {
                page.close();
            } catch (Exception e) {
                // 静默处理
            }
        }
        if (context != null) {
            try {
                context.close();
            } catch (Exception e) {
                // 静默处理
            }
        }
    }

    /**
     * 定时任务调用的方法
     */
    public void startCrawlBySchedule() {
        try {
            System.out.println("========== 定时任务开始执行 CPSC不合格商品数据爬取 ==========");
            System.out.println("执行时间: " + DATE_FORMAT.format(new Date()));

            startCrawl(false);

            System.out.println("========== 定时任务执行完成 ==========");
        } catch (Exception e) {
            System.err.println("定时任务执行异常: " + e.getMessage());
            e.printStackTrace();
        }
    }
}