package com.jsc.dsp.utils;

import com.jsc.dsp.service.ConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.Date;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Component
@ConditionalOnProperty(name = "switch.auto-export-and-upload", havingValue = "true", matchIfMissing = true)
public class AutoExportAndUpload {

    @Resource
    DatabaseConnector databaseConnector;

    @Resource
    FTPConnector ftpConnector;

    @Resource
    ConfigService configService;

    private final Logger logger = LoggerFactory.getLogger(this.getClass().getName());

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


    @Value("${custom.excelOutputPath}")
    String excelOutputPath;

    @Value("${custom.backupFilePath}")
    String backupFilePath;

    @Value("${custom.pagesOutputPath}")
    String pagesOutputPath;

    @Value("${custom.ftpUploadPath}")
    String ftpUploadPath;

    /**
     * 每周一、三、五的早上8点，执行导出数据的任务
     */
    @Scheduled(cron = "${custom.exportTaskSchedule}")
    public void exportDataAndUpload() {
        logger.info("开始导出excel和pdf数据...");
        String lastLoadTime = configService.getConfigValueByName("last_loadtime");
        String currentLoadTime = StringUtils.DateToString(new Date());
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        databaseConnector.exportToXlsx(lastLoadTime);
        copyPagesFiles(lastLoadTime, currentLoadTime);
        configService.setConfigValueByName("last_loadtime", currentLoadTime);
        String zipFileName = "data_news-" + timestamp + "-001.zip";
        String zipFileFullName = backupFilePath + File.separator + zipFileName;
        String remoteZipPath = ftpUploadPath + "/" + zipFileName;
        zipAndUploadDirectory(excelOutputPath, zipFileFullName, remoteZipPath);
    }

    /**
     * 将指定目录打包成 ZIP 文件（保存到指定本地路径），并上传到 FTP 服务器
     *
     * @param sourceDirPath 本地要打包的源目录路径（如：/data/reports）
     * @param localZipPath  本地 ZIP 文件保存路径（如：/backup/archives/reports_20251224.zip）
     * @param remoteZipPath FTP 上的目标路径（如：/ftp/backups/reports_20251224.zip）
     */
    public void zipAndUploadDirectory(String sourceDirPath, String localZipPath, String remoteZipPath) {
        Path sourceDir = Paths.get(sourceDirPath);
        if (!Files.exists(sourceDir) || !Files.isDirectory(sourceDir)) {
            logger.error("源目录不存在或不是一个目录: {}", sourceDirPath);
            return;
        }

        Path localZipFile = Paths.get(localZipPath);
        Path zipParent = localZipFile.getParent();
        if (zipParent != null && !Files.exists(zipParent)) {
            try {
                Files.createDirectories(zipParent);
                logger.debug("创建 ZIP 父目录: {}", zipParent);
            } catch (IOException e) {
                logger.error("无法创建 ZIP 父目录: {}", zipParent, e);
                return;
            }
        }

        // 打包目录到指定本地 ZIP 路径
        try {
            zipDirectory(sourceDir, localZipFile.toFile());
        } catch (IOException e) {
            logger.error("打包目录失败: {}", sourceDirPath, e);
            return;
        }

        // 上传 ZIP 文件
        try (InputStream zipInputStream = Files.newInputStream(localZipFile)) {
            boolean uploaded = ftpConnector.uploadFile(zipInputStream, remoteZipPath);
            if (uploaded) {
                logger.info("ZIP 文件上传成功 - 本地: {}, FTP: {}", localZipPath, remoteZipPath);
            } else {
                logger.error("ZIP 文件上传失败 - FTP: {}", remoteZipPath);
            }
        } catch (IOException e) {
            logger.error("读取本地 ZIP 文件失败: {}", localZipPath, e);
        }

        // 注意：此处不再删除 localZipFile，由调用方决定是否保留或清理
    }


    /**
     * 将目录递归打包成 ZIP 文件
     *
     * @param sourceDir 要打包的源目录
     * @param zipFile   输出的 ZIP 文件
     * @throws IOException
     */
    private void zipDirectory(Path sourceDir, File zipFile) throws IOException {
        try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile))) {
            Files.walk(sourceDir)
                    .filter(path -> !Files.isDirectory(path)) // 只处理文件
                    .forEach(path -> {
                        ZipEntry zipEntry = new ZipEntry(sourceDir.relativize(path).toString());
                        try {
                            zipOut.putNextEntry(zipEntry);
                            Files.copy(path, zipOut);
                            zipOut.closeEntry();
                        } catch (IOException e) {
                            throw new RuntimeException("打包文件失败: " + path, e);
                        }
                    });
        }
        logger.info("目录打包完成: {} -> {}", sourceDir, zipFile.getAbsolutePath());
        try {
            Files.walk(sourceDir)
                    .sorted(Comparator.reverseOrder()) // 先处理子文件/子目录，再处理父目录（但这里只删文件）
                    .filter(path -> !Files.isDirectory(path)) // 只删除文件
                    .forEach(path -> {
                        try {
                            Files.delete(path);
                            logger.debug("已删除文件: {}", path);
                        } catch (IOException e) {
                            logger.warn("无法删除文件: {}", path, e);
                        }
                    });
            logger.info("源目录已清空（仅删除文件，保留目录结构）: {}", sourceDir);
        } catch (IOException e) {
            logger.error("清空源目录时发生错误", e);
            // 注意：即使清理失败，ZIP 已生成并会继续上传，根据业务决定是否抛异常
            // 如果要求“必须清理成功才算成功”，可在此 throw 异常
        }
    }

    public void copyPagesFiles(String startTime, String endTime) {
        try {
            logger.info("开始复制PDF...");
            // 解析时间范围
            Date start = sdf.parse(startTime);
            Date end = sdf.parse(endTime);

            // 源目录
            Path sourceDir = Paths.get(pagesOutputPath);
            if (!Files.exists(sourceDir) || !Files.isDirectory(sourceDir)) {
                logger.error("源目录不存在或不是目录: " + pagesOutputPath);
                return;
            }

            // 目标目录：在 excelOutputPath 下创建 pdf 子目录
            Path targetBaseDir = Paths.get(excelOutputPath);
            Path targetPdfDir = targetBaseDir.resolve("pdf");

            // 确保目标目录存在
            if (!Files.exists(targetPdfDir)) {
                Files.createDirectories(targetPdfDir);
            }

            // 遍历源目录中的所有 PDF 文件
            Files.walk(sourceDir)
                    .filter(path -> !Files.isDirectory(path))
                    .filter(path -> path.toString().toLowerCase().endsWith(".pdf"))
                    .forEach(path -> {
                        try {
                            // 获取文件创建时间（注意：Linux/macOS 可能不支持 creationTime）
                            BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
                            FileTime creationTime = attrs.creationTime();
                            Date fileCreationDate = new Date(creationTime.toMillis());

                            // 如果 creationTime 在某些系统上不可靠，可替换为 lastModifiedTime：
                            // Date fileCreationDate = new Date(Files.getLastModifiedTime(path).toMillis());

                            // 判断文件时间是否在指定范围内
                            if (!fileCreationDate.before(start) && !fileCreationDate.after(end)) {
                                // 构建目标路径（保留相对结构，或直接放平？这里按原相对路径保留）
                                Path relativePath = sourceDir.relativize(path);
                                Path targetPath = targetPdfDir.resolve(relativePath);

                                // 确保目标子目录存在
                                Path targetParent = targetPath.getParent();
                                if (targetParent != null && !Files.exists(targetParent)) {
                                    Files.createDirectories(targetParent);
                                }

                                // 复制文件
                                Files.copy(path, targetPath, StandardCopyOption.REPLACE_EXISTING);
                                logger.info("已复制文件: " + path + " -> " + targetPath);
                            }
                        } catch (IOException e) {
                            logger.error("处理文件时出错: " + path + " - " + e.getMessage());
                        }
                    });

            logger.info("PDF 文件复制完成，目标目录: " + targetPdfDir.toAbsolutePath());

        } catch (ParseException e) {
            logger.error("时间格式解析错误，请确保使用格式: " + DATE_FORMAT);
            e.printStackTrace();
        } catch (IOException e) {
            logger.error("IO 错误: " + e.getMessage());
            e.printStackTrace();
        }
    }


}
