package com.jwipc.order.util;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jwipc.order.dto.FtpResultDto;
import com.jwipc.sys.entity.BusinessAttachment;
import com.jwipc.sys.service.IBusinessAttachmentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
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.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * <p>
 *  ftp服务器工具类
 * </p>
 *
 * @author Chen Tianshi
 * @since 2025/8/20 17:07
 */

@Slf4j
@Component
public class FtpUtils {

    @Value("${sys.ftp.host}")
    private String host;

    @Value("${sys.ftp.port}")
    private int port;

    @Value("${sys.ftp.userName}")
    private String username;

    @Value("${sys.ftp.password}")
    private String password;

    @Value("${sys.ftp.timeDifference}")
    private int timeDifference;
    @Autowired
    private IBusinessAttachmentService businessAttachmentService;
    // 定义内部类 DirectoryPair
    private static class DirectoryPair {
        final String remotePath;
        final Path localPath;

        DirectoryPair(String remotePath, Path localPath) {
            this.remotePath = remotePath;
            this.localPath = localPath;
        }
    }

    /**
     * 文件任务类
     */
    private static class FileTask {
        final String remotePath;
        final String fileName;
        final Path localPath;
        final Date fileDate; // 文件修改时间

        FileTask(String remotePath, String fileName, Path localPath, Date fileDate) {
            this.remotePath = remotePath;
            this.fileName = fileName;
            this.localPath = localPath;
            this.fileDate = fileDate;
        }
    }

    @FunctionalInterface
    public interface FileProcessor {
        void process(File file) throws IOException;
    }

    /**
     * 获取单个文件对象
     * @param remoteDir 目标文件夹
     * @param fileName 目标文件
     * @return 文件对象
     * @throws IOException IOException
     */
    public FtpResultDto getFile(String remoteDir, String fileName) throws IOException {
        FTPClient ftpClient = null;
        File tempFile = null;
        FtpResultDto result = new FtpResultDto();

        try {
            // 1. 连接FTP
            ftpClient = getFTPClient();

            // 2. 处理远程目录路径
            String normalizedRemoteDir = remoteDir.replace("\\", "/").trim();
            normalizedRemoteDir = normalizedRemoteDir.replaceAll("/+$", "");
            String targetDir = new String(normalizedRemoteDir.getBytes("GBK"), StandardCharsets.ISO_8859_1);

            // 3. 切换目录
            boolean changed = ftpClient.changeWorkingDirectory(targetDir);
            if (!changed) {
                throw new IOException("远程目录不存在或无法访问：" + normalizedRemoteDir);
            }

            // 4. 获取文件修改时间
            FTPFile[] ftpFiles = ftpClient.listFiles(fileName);
            if (ftpFiles == null || ftpFiles.length == 0) {
                throw new IOException("文件不存在：" + fileName);
            }
            FTPFile ftpFile = ftpFiles[0];
            LocalDateTime modifyTime = convertToLocalDateTime(ftpFile.getTimestamp());
            result.setModifyTime(modifyTime);

            // 5. 创建临时文件
            tempFile = Files.createTempFile("ftp_", "_" + fileName).toFile();
            try (FileOutputStream outputStream = new FileOutputStream(tempFile)) {
                // 下载文件
                boolean success = ftpClient.retrieveFile(fileName, outputStream);
                if (!success) {
                    throw new IOException("文件获取失败,服务器响应： " + ftpClient.getReplyString());
                }
            } // 自动关闭流
            result.setFile(tempFile);

            return result;
        } catch (IOException e) {
            log.error("获取文件失败", e);
            return null;
        } finally {
            // 删除临时文件
            safeDeleteTempFile(tempFile);
            closeConnection(ftpClient);
        }
    }

    /**
     * 下载FTP文件到指定文件夹
     * @param remoteDir 远程文件路径（如：/files）
     * @param localDir  本地保存路径（如：C:/downloads）
     * @param fileName 目标文件（如：test.txt）
     * @return 是否下载成功
     */
    public boolean downloadFile(String remoteDir, String localDir, String fileName) throws IOException {
        FTPClient ftpClient = null;
        FileOutputStream outputStream = null;

        try {
            // 连接
            ftpClient = getFTPClient();

            // 创建本地目录（如果不存在）
            File localDirectory = new File(localDir);
            if (!localDirectory.exists()) {
                boolean isCreated = localDirectory.mkdirs();
                if (isCreated) {
                    log.info("本地目录不存在，已自动创建：{}", localDir);
                }
            }

            // 2. 处理远程目录路径
            // 处理路径格式（统一用 / 分隔，兼容Windows和Linux）
            String normalizedRemoteDir = remoteDir.replace("\\", "/").trim();
            // 去掉路径末尾多余的 / 防止切换失败
            normalizedRemoteDir = normalizedRemoteDir.replaceAll("/+$", "");
            // 把远程路径按 GBK 编码转成字节，再用 ISO-8859-1 重新构建字符串
            String targetDir = new String(normalizedRemoteDir.getBytes("GBK"), StandardCharsets.ISO_8859_1);

            // 切换到远程目录
            boolean changed = ftpClient.changeWorkingDirectory(targetDir);

            // 检测是否切换成功，如果未切换成功则抛出异常
            if (!changed) {
                throw new IOException("远程目录不存在或无法访问：" + normalizedRemoteDir);
            }

            // 构建本地文件路径（兼容windows和linux）
            String localFilePath = localDir + File.separator + fileName;

            // 定义输出文件流
            outputStream = new FileOutputStream(localFilePath);

            // ***通过ftp连接和输出流将文件下载到本地***
            boolean success = ftpClient.retrieveFile(fileName, outputStream);

            // 判断是否下载失败
            if (!success) {
                throw new IOException("文件下载失败,服务器响应：" + ftpClient.getReplyString());
            }

            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } finally {
            // 关闭输出流
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error("关闭输出流失败", e);
                }
            }
            // 流程结束，关闭FTP连接
            closeConnection(ftpClient);
        }
    }

    /**
     * 下载整个文件夹到本地目录
     * @param remoteDir 远程文件夹路径
     * @param localDir 本地保存目录
     * @return 下载的文件总数
     * @throws IOException IOException
     */
    public int downloadFolder(String remoteDir, String localDir) throws IOException {
        FTPClient ftpClient = null;
        AtomicInteger fileCount = new AtomicInteger(0);
        long startTime = System.currentTimeMillis();

        try {
            // 1. 连接FTP
            ftpClient = getFTPClient();

            // 2. 处理远程目录路径
            String normalizedRemoteDir = remoteDir.replace("\\", "/").trim();
            normalizedRemoteDir = normalizedRemoteDir.replaceAll("/+$", "");
            String targetDir = new String(normalizedRemoteDir.getBytes("GBK"), StandardCharsets.ISO_8859_1);

            // 3. 切换到目标目录
            if (!ftpClient.changeWorkingDirectory(targetDir)) {
                throw new IOException("远程目录不存在或无法访问：" + normalizedRemoteDir);
            }

            // 4. 创建本地根目录
            Path localRootPath = Paths.get(localDir);
            Files.createDirectories(localRootPath);
            log.info("创建本地目录: " + localRootPath);

            // 5. 使用队列进行非递归遍历（避免栈溢出）
            Queue<DirectoryPair> queue = new LinkedList<>();
            queue.add(new DirectoryPair(normalizedRemoteDir, localRootPath));

            while (!queue.isEmpty()) {
                DirectoryPair current = queue.poll();
                processDirectory(ftpClient, current.remotePath, current.localPath, queue, fileCount);
            }

            long duration = System.currentTimeMillis() - startTime;
            log.info("文件夹下载完成! 文件总数: {}, 耗时: {} ms", fileCount.get(), duration);
            return fileCount.get();

        } finally {
            closeConnection(ftpClient);
        }
    }

    /**
     * 流式处理文件夹下载（多线程版）
     * @param remoteDir 远程目录路径
     * @param processor 文件处理器
     * @param threadCount 线程数量
     * @throws IOException IOException
     */
    public void threadDownloadFolder(String remoteDir, String localDir, FileProcessor processor, int threadCount,StringBuilder stringBuilder) throws IOException {
        FTPClient ftpClient = null;
        Path tempRootDir = null;
        ExecutorService executor = null;

        // 计算时间范围（今天之前一周）
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_YEAR, -7); // 一周前
        Date oneWeekAgo = calendar.getTime();
        log.info("将下载 {} 之后的文件", new SimpleDateFormat("yyyy-MM-dd").format(oneWeekAgo));

        // 开始计时
        long startTime = System.currentTimeMillis();

        try {
            // 1. 连接FTP
            ftpClient = getFTPClient();

            // 2. 处理远程目录路径
            String normalizedRemoteDir = remoteDir.replace("\\", "/").trim();
            normalizedRemoteDir = normalizedRemoteDir.replaceAll("/+$", "");
            String targetDir = new String(normalizedRemoteDir.getBytes("GBK"), StandardCharsets.ISO_8859_1);

            // 3. 切换到目标目录
            if (!ftpClient.changeWorkingDirectory(targetDir)) {
                throw new IOException("远程目录不存在或无法访问：" + normalizedRemoteDir);
            }

            // 4. 创建临时根目录
            tempRootDir = Paths.get(localDir);
            Files.createDirectories(tempRootDir);
            log.info("创建本地目录: " + tempRootDir);
            tempRootDir.toFile().deleteOnExit();

            // 5. 收集所有需要下载的文件
            List<FileTask> fileTasks = new ArrayList<>();
            Queue<DirectoryPair> queue = new LinkedList<>();
            queue.add(new DirectoryPair(normalizedRemoteDir, tempRootDir));

            // 遍历目录，收集文件任务
            while (!queue.isEmpty()) {
                DirectoryPair current = queue.poll();
                collectFileTasks(ftpClient, current.remotePath, current.localPath, queue, fileTasks, oneWeekAgo);
            }

            // 6. 使用线程池并发下载文件
            executor = Executors.newFixedThreadPool(threadCount);
            CountDownLatch latch = new CountDownLatch(fileTasks.size());

            for (FileTask task : fileTasks) {
                executor.submit(() -> {
                    try {
                        downloadAndProcessFile(task, processor,stringBuilder);
                        latch.countDown();
                    } catch (IOException e) {
                        log.error("文件下载失败: {}", task.remotePath, e);
                        latch.countDown();
                    }
                });
            }

            // 等待所有任务完成
            latch.await();

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException("下载被中断", e);
        } finally {
            // 计算总耗时
            long endTime = System.currentTimeMillis();
            long totalTime = endTime - startTime;
            log.info("下载总耗时: {}ms", totalTime);
            // 清理临时目录
            if (tempRootDir != null) {
                safeDeleteTempFile(tempRootDir.toFile());
            }
            closeConnection(ftpClient);
            if (executor != null) {
                executor.shutdown();
            }
        }
    }

    /**
     * 多线程下载指定时间范围内的文件
     * @param remoteDir 远程目录路径
     * @param localDir 本地目录路径
     * @param processor 文件处理器
     * @param threadCount 线程数量
     * @param startDate 开始时间（包含）
     * @param endDate 结束时间（包含）
     * @throws IOException IOException
     */
    public void threadDownloadFilesByDateRange(String remoteDir, String localDir, FileProcessor processor,
                                               int threadCount, Date startDate, Date endDate,StringBuilder stringBuilder) throws IOException {
        FTPClient ftpClient = null;
        Path tempRootDir = null;
        ExecutorService executor = null;

        // 格式化时间用于日志输出
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        log.info("将下载 {} 至 {} 时间范围内的文件", sdf.format(startDate), sdf.format(endDate));

        // 开始计时
        long startTime = System.currentTimeMillis();

        try {
            // 1. 连接FTP
            ftpClient = getFTPClient();

            // 2. 处理远程目录路径
            String normalizedRemoteDir = remoteDir.replace("\\", "/").trim();
            normalizedRemoteDir = normalizedRemoteDir.replaceAll("/+$", "");
            String targetDir = new String(normalizedRemoteDir.getBytes("GBK"), StandardCharsets.ISO_8859_1);

            // 3. 切换到目标目录
            if (!ftpClient.changeWorkingDirectory(targetDir)) {
                throw new IOException("远程目录不存在或无法访问：" + normalizedRemoteDir);
            }

            // 4. 创建临时根目录
            tempRootDir = Paths.get(localDir);
            Files.createDirectories(tempRootDir);
            log.info("创建本地目录: " + tempRootDir);
            tempRootDir.toFile().deleteOnExit();

            // 5. 收集指定时间范围内的文件
            List<FileTask> fileTasks = new ArrayList<>();
            Queue<DirectoryPair> queue = new LinkedList<>();
            queue.add(new DirectoryPair(normalizedRemoteDir, tempRootDir));

            // 遍历目录，收集文件任务
            while (!queue.isEmpty()) {
                DirectoryPair current = queue.poll();
                collectFilesByDateRange(ftpClient, current.remotePath, current.localPath,
                        queue, fileTasks, startDate, endDate);
            }

            if (fileTasks.isEmpty()) {
                log.warn("未找到指定时间范围内的文件");
                return;
            }

            log.info("找到 {} 个符合条件的文件", fileTasks.size());

            // 6. 使用线程池并发下载文件
            executor = Executors.newFixedThreadPool(threadCount);
            CountDownLatch latch = new CountDownLatch(fileTasks.size());

            for (FileTask task : fileTasks) {
                executor.submit(() -> {
                    try {
                        downloadAndProcessFile(task, processor,stringBuilder);
                        latch.countDown();
                    } catch (IOException e) {
                        log.error("文件下载失败: {}", task.remotePath, e);
                        latch.countDown();
                    }
                });
            }

            // 等待所有任务完成
            latch.await();

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException("下载被中断", e);
        } finally {
            // 计算总耗时
            long endTime = System.currentTimeMillis();
            long totalTime = endTime - startTime;
            log.info("下载总耗时: {}ms", totalTime);

            // 清理临时目录
            if (tempRootDir != null) {
                // safeDeleteTempFile(tempRootDir.toFile());
            }
            closeConnection(ftpClient);
            if (executor != null) {
                executor.shutdown();
            }
        }
    }

    public void threadDownloadFilesByDateRangeList(List<String> remoteDirList, String localDir, FileProcessor processor,
                                               int threadCount, Date startDate, Date endDate,StringBuilder stringBuilder) throws IOException {
        for (String remoteDir : remoteDirList){
            FTPClient ftpClient = null;
            Path tempRootDir = null;
            ExecutorService executor = null;

            // 格式化时间用于日志输出
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            log.info("将下载 {} 至 {} 时间范围内的文件", sdf.format(startDate), sdf.format(endDate));

            // 开始计时
            long startTime = System.currentTimeMillis();

            try {
                // 1. 连接FTP
                ftpClient = getFTPClient();

                // 2. 处理远程目录路径
                String normalizedRemoteDir = remoteDir.replace("\\", "/").trim();
                normalizedRemoteDir = normalizedRemoteDir.replaceAll("/+$", "");
                String targetDir = new String(normalizedRemoteDir.getBytes("GBK"), StandardCharsets.ISO_8859_1);

                // 3. 切换到目标目录
                if (!ftpClient.changeWorkingDirectory(targetDir)) {
                    log.info("远程目录不存在或无法访问：" + normalizedRemoteDir);
                    continue;
//                    throw new IOException("远程目录不存在或无法访问：" + normalizedRemoteDir);
                }

                // 4. 创建临时根目录
                tempRootDir = Paths.get(localDir);
                Files.createDirectories(tempRootDir);
                log.info("创建本地目录: " + tempRootDir);
                tempRootDir.toFile().deleteOnExit();

                // 5. 收集指定时间范围内的文件
                List<FileTask> fileTasks = new ArrayList<>();
                Queue<DirectoryPair> queue = new LinkedList<>();
                queue.add(new DirectoryPair(normalizedRemoteDir, tempRootDir));

                // 遍历目录，收集文件任务
                while (!queue.isEmpty()) {
                    DirectoryPair current = queue.poll();
                    collectFilesByDateRange(ftpClient, current.remotePath, current.localPath,
                            queue, fileTasks, startDate, endDate);
                }

                if (fileTasks.isEmpty()) {
                    log.warn("未找到指定时间范围内的文件");
                    return;
                }

                log.info("找到 {} 个符合条件的文件", fileTasks.size());

                // 6. 使用线程池并发下载文件
                executor = Executors.newFixedThreadPool(threadCount);
                CountDownLatch latch = new CountDownLatch(fileTasks.size());

                for (FileTask task : fileTasks) {
                    executor.submit(() -> {
                        try {
                            downloadAndProcessFile(task, processor,stringBuilder);
                            latch.countDown();
                        } catch (IOException e) {
                            e.printStackTrace();
                            log.error("文件下载失败: {}", task.remotePath, e);
                            latch.countDown();
                        }
                    });
                }

                // 等待所有任务完成
                latch.await();

            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new IOException("下载被中断", e);
            } finally {
                // 计算总耗时
                long endTime = System.currentTimeMillis();
                long totalTime = endTime - startTime;
                log.info("下载总耗时: {}ms", totalTime);

                // 清理临时目录
                if (tempRootDir != null) {
                    // safeDeleteTempFile(tempRootDir.toFile());
                }
                closeConnection(ftpClient);
                if (executor != null) {
                    executor.shutdown();
                }
            }
        }

    }

    /**
     * 创建FTPClient连接
     */
    private FTPClient getFTPClient() throws IOException {
        FTPClient ftpClient = new FTPClient();

        // 关闭UTF-8自动检测
        ftpClient.setAutodetectUTF8(false);

        try {
            // 连接ftp服务器
            ftpClient.connect(host, port);

            // 检查连接响应
            int replyCode = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                throw new IOException("FTP服务器拒绝连接，响应码: " + replyCode);
            }

            // 登陆ftp服务器
            boolean loginSuccess = ftpClient.login(username, password);
            if (!loginSuccess) {
                throw new IOException("FTP服务器登录失败，请稍后再试");
            }

            //配置连接的参数
            ftpClient.enterLocalPassiveMode();
            // 控制编码设置为GBK
            ftpClient.setControlEncoding("GBK");
            // 二进制传输模式
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);

            return ftpClient;

        } catch (IOException e) {
            log.error("ftp连接失败: {}", e.getMessage());
            // 在连接失败时断开连接
            if (ftpClient.isConnected()) {
                ftpClient.disconnect();
            }
            throw e;
        }
    }

    /**
     * 关闭ftp连接
     */
    private void closeConnection(FTPClient ftpClient) {
        if (ftpClient != null && ftpClient.isConnected()) {
            try {
                ftpClient.logout();
                ftpClient.disconnect();
            } catch (IOException e) {
                log.error("关闭FTP连接失败", e);
            }
        }
    }

    /**
     * 日期转换 Calendar → LocalDateTime
     * @param calendar Calendar
     * @return LocalDateTime
     */
    private LocalDateTime convertToLocalDateTime(Calendar calendar) {
        // 1. 获取Calendar对象（需检查空值）
        if (calendar == null) {
            return null;
        }
        // 2. 将Calendar转换为Instant（UTC时间）
        Instant utcInstant = calendar.toInstant();

        // 2. 解析服务器时区
        ZoneOffset serverOffset = ZoneOffset.of("+16:00"); // TODO 暂时不清楚为什么获取到的FTP服务器时间比本地少了16个时区

        // 3. 转换为服务器本地时间
        return LocalDateTime.ofInstant(utcInstant, serverOffset);
    }

    /**
     * 安全删除工具方法
     * @param file 删除文件对象
     */
    private void safeDeleteTempFile(File file) {
        if (file == null) return;

        try {
            // 使用NIO API删除更可靠
            Files.deleteIfExists(file.toPath());
        } catch (IOException e) {
            log.warn("删除临时文件失败，尝试标记删除: {}", file.getAbsolutePath());
            file.deleteOnExit(); // JVM退出时删除
        }
    }

    /**
     * 收集文件任务而不立即下载
     */
    private void collectFileTasks(FTPClient ftpClient, String remotePath,
                                  Path localPath, Queue<DirectoryPair> queue,
                                  List<FileTask> fileTasks, Date oneWeekAgo) throws IOException {
        // 处理远程路径编码
        String encodedRemotePath = new String(remotePath.getBytes("GBK"), StandardCharsets.ISO_8859_1);

        // 切换到当前远程目录
        if (!ftpClient.changeWorkingDirectory(encodedRemotePath)) {
            log.warn("无法访问目录: {}", remotePath);
            return;
        }

        // 创建本地目录
        Files.createDirectories(localPath);

        // 列出当前目录内容
        FTPFile[] ftpFiles = ftpClient.listFiles();
        for (FTPFile ftpFile : ftpFiles) {
            String fileName = ftpFile.getName();

            if (ftpFile.isDirectory()) {
                // 添加到队列处理子目录
                if (!".".equals(fileName) && !"..".equals(fileName)) {
                    String subRemotePath = remotePath + "/" + fileName;
                    Path subLocalPath = localPath.resolve(fileName);
                    queue.add(new DirectoryPair(subRemotePath, subLocalPath));
                }
            } else {
                // 检查文件修改时间
                Date fileDate = ftpFile.getTimestamp().getTime();
                if (fileDate.after(oneWeekAgo)) {
                    // 只收集符合条件的文件
                    fileTasks.add(new FileTask(remotePath, fileName, localPath.resolve(fileName), fileDate));
                }
            }
        }
    }

    /**
     * 处理单个目录
     */
    private void processDirectory(FTPClient ftpClient, String remotePath,
                                  Path localPath, Queue<DirectoryPair> queue,
                                  AtomicInteger fileCount) throws IOException {
        // 处理远程路径编码
        String encodedRemotePath = new String(remotePath.getBytes("GBK"), StandardCharsets.ISO_8859_1);

        // 切换到当前远程目录
        if (!ftpClient.changeWorkingDirectory(encodedRemotePath)) {
            log.error("无法访问目录: " + remotePath);
            return;
        }

        // 创建本地目录
        Files.createDirectories(localPath);
        log.info("创建本地子目录: " + localPath);

        // 列出当前目录内容
        FTPFile[] ftpFiles = ftpClient.listFiles();
        for (FTPFile ftpFile : ftpFiles) {
            String fileName = ftpFile.getName();

            if (ftpFile.isDirectory()) {
                // 添加到队列处理子目录
                if (!".".equals(fileName) && !"..".equals(fileName)) {
                    String subRemotePath = remotePath + "/" + fileName;
                    Path subLocalPath = localPath.resolve(fileName);
                    queue.add(new DirectoryPair(subRemotePath, subLocalPath));
                }
            } else {
                // 下载文件
                Path localFilePath = localPath.resolve(fileName);
                try (OutputStream outputStream = Files.newOutputStream(localFilePath)) {
                    if (ftpClient.retrieveFile(fileName, outputStream)) {
                        fileCount.incrementAndGet();
                        if (fileCount.get() % 100 == 0) {
                            log.info("已下载 " + fileCount.get() + " 个文件...");
                        }
                    } else {
                        log.warn("文件下载失败: " + remotePath + "/" + fileName);
                    }
                }
            }
        }
    }

    /**
     * 下载并处理单个文件
     */
    private void downloadAndProcessFile(FileTask task, FileProcessor processor,StringBuilder stringBuilder) throws IOException {
        // 为每个下载任务创建独立的FTP连接
        try {
            FTPClient ftpClient = getFTPClient();
            // 切换到文件所在目录
            String encodedRemotePath = new String(task.remotePath.getBytes("GBK"), StandardCharsets.ISO_8859_1);
            if (!ftpClient.changeWorkingDirectory(encodedRemotePath)) {
                log.warn("无法切换至目录: {}", task.remotePath);
                return;
            }
            log.info("找到文件: {}/{}", task.remotePath, task.fileName);
            stringBuilder.append(StrUtil.format("找到文件: {}/{},", task.remotePath, task.fileName));
            BusinessAttachment attachment = businessAttachmentService.getOne(new LambdaQueryWrapper<BusinessAttachment>().eq(BusinessAttachment::getFileName, task.fileName).eq(BusinessAttachment::getBusinessTypeCode, "delivery_order").eq(BusinessAttachment::getDeleteFlag, 0).last(" LIMIT 1"));
            if (ObjectUtil.isNull(attachment)) {
                stringBuilder.append("需要下载，");
                // 下载文件
                if (!ftpClient.isConnected()) {
                    ftpClient = getFTPClient(); // 重新建立连接
                }
                try (OutputStream outputStream = Files.newOutputStream(task.localPath)) {
                    if (ftpClient.retrieveFile(task.fileName, outputStream)) {
                        // 处理文件
                        processor.process(task.localPath.toFile());
                        stringBuilder.append("下载成功！\n");
                        // 立即删除临时文件
//                    Files.delete(task.localPath);
                    } else {

                        stringBuilder.append(StrUtil.format("文件下载失败: {}/{},错误信息：{}", task.remotePath, task.fileName,ftpClient.getReplyString()));
                        log.error("文件下载失败: {}/{},错误信息：{}\n", task.remotePath, task.fileName,ftpClient.getReplyString());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 收集指定时间范围内的文件任务
     */
    private void collectFilesByDateRange(FTPClient ftpClient, String remotePath,
                                         Path localPath, Queue<DirectoryPair> queue,
                                         List<FileTask> fileTasks, Date startDate, Date endDate) throws IOException {
        // 处理远程路径编码
        String encodedRemotePath = new String(remotePath.getBytes("GBK"), StandardCharsets.ISO_8859_1);

        // 切换到当前远程目录
        if (!ftpClient.changeWorkingDirectory(encodedRemotePath)) {
            log.warn("无法访问目录: {}", remotePath);
            return;
        }

        // 创建本地目录
        Files.createDirectories(localPath);

        // 列出当前目录内容
        FTPFile[] ftpFiles = ftpClient.listFiles();
        for (FTPFile ftpFile : ftpFiles) {
            String fileName = ftpFile.getName();

            if (ftpFile.isDirectory()) {
                // 添加到队列处理子目录
                if (!".".equals(fileName) && !"..".equals(fileName)) {
                    String subRemotePath = remotePath + "/" + fileName;
                    Path subLocalPath = localPath.resolve(fileName);
                    queue.add(new DirectoryPair(subRemotePath, subLocalPath));
                }
            } else {
                // 检查文件修改时间是否在指定范围内
                LocalDateTime fileDateTime = convertToLocalDateTime(ftpFile.getTimestamp());
                LocalDateTime corrected = fileDateTime.minusHours(timeDifference);
                Date fileDate = Date.from(corrected.atZone(ZoneId.systemDefault()).toInstant());
                if (isDateInRange(fileDate, startDate, endDate)) {
                    // 只收集符合条件的文件
                    fileTasks.add(new FileTask(remotePath, fileName, localPath.resolve(fileName), fileDate));
                    log.debug("添加文件: {} (修改时间: {})", fileName,
                            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(fileDate));
                }
            }
        }
    }

    /**
     * 检查日期是否在指定范围内
     */
    private boolean isDateInRange(Date fileDate, Date startDate, Date endDate) {
        // 如果开始时间为null，表示无开始时间限制
        boolean afterStart = (startDate == null) || fileDate.after(startDate) || fileDate.equals(startDate);
        // 如果结束时间为null，表示无结束时间限制
        boolean beforeEnd = (endDate == null) || fileDate.before(endDate) || fileDate.equals(endDate);

        return afterStart && beforeEnd;
    }
}
