package com.jwipc.job.util;

import cn.hutool.core.map.MapUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.*;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author shenyang.ou
 * @date 2025/11/5 15:39
 * @desc
 */
@Slf4j
public class FtpMultiThreadDownloader {
    private final FTPClient ftpClient;
    private final ExecutorService executor;
    private final String localBaseDir;
    private final Date startTime;
    private final Date endTime;
    private final int maxThreads;
    private final AtomicInteger downloadCount = new AtomicInteger(0);
    private final Object lock = new Object();

    public FtpMultiThreadDownloader(
            String ftpHost, int ftpPort, String ftpUser, String ftpPassword,
            String localBaseDir, Date startTime, Date endTime, int maxThreads) {

        // 初始化FTP客户端
        ftpClient = new FTPClient();
        ftpClient.configure(new FTPClientConfig(FTPClientConfig.SYST_UNIX));
        try {
            ftpClient.connect(ftpHost, ftpPort);
            ftpClient.login(ftpUser, ftpPassword);
            ftpClient.enterLocalPassiveMode();
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
        } catch (IOException e) {
            throw new RuntimeException("FTP connection failed", e);
        }

        this.localBaseDir = localBaseDir;
        this.startTime = startTime;
        this.endTime = endTime;
        this.maxThreads = Math.max(1, maxThreads);
        this.executor = Executors.newFixedThreadPool(maxThreads);
    }

    public List<Map<String,String>> getAllDateFiles(List<String> ftpDirectories) {
        // 2. 构建待下载文件列表（筛选时间范围+文件名检查）
        List<Map<String,String>> filesToDownload = new ArrayList<>();
        for (String dir : ftpDirectories) {
            List<Map<String,String>> filesInDir = listFtpFiles(dir);
            filesToDownload.addAll(filesInDir);
        }
        return filesToDownload;
    }

    public void downloadFiles(List<Map<String,String>> needSaveFileList) {

        // 3. 多线程下载
        List<Future<?>> futures = new ArrayList<>();
        for (Map<String, String> fileInfo : needSaveFileList) {
            futures.add(executor.submit(() -> {
                String filePath = fileInfo.get("filePath");
                try {
                    downloadFile(filePath);
                } catch (Exception e) {
                    System.err.println("Failed to download " + filePath + ": " + e.getMessage());
                }
            }));
        }

        // 4. 等待所有任务完成
        for (Future<?> future : futures) {
            try {
                future.get();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        executor.shutdown();
    }

    private List<String> listFilesInDirectory(String directory, Set<String> existingFiles) {
        List<String> files = new ArrayList<>();
        try {
            FTPFile[] ftpFiles = ftpClient.listFiles(directory);
            if (ftpFiles == null) return files;

            for (FTPFile file : ftpFiles) {
                if (!file.isFile()) continue;

                // 时间范围筛选
                Date modifyTime = file.getTimestamp().getTime();
                if (modifyTime.before(startTime) || modifyTime.after(endTime)) continue;

                // 文件名存在性检查
                String fileName = file.getName();
                if (!existingFiles.contains(fileName)) {
                    files.add(directory + "/" + fileName);
                }
            }
        } catch (IOException e) {
            System.err.println("Error listing directory: " + directory);
        }
        return files;
    }

    private List<Map<String,String>> listFtpFiles(String directory) {
        List<Map<String,String>> files = new ArrayList<>();
        try {
            FTPFile[] ftpFiles = ftpClient.listFiles(directory);
            if (ftpFiles == null) return files;

            for (FTPFile file : ftpFiles) {
                if (!file.isFile()) continue;

                // 时间范围筛选
                Date modifyTime = file.getTimestamp().getTime();
                if (modifyTime.before(startTime) || modifyTime.after(endTime)) continue;
                String fileName = file.getName();
                Map<String,String> map = new HashMap<>();
                map.put("fileName",fileName);
                map.put("filePath",directory+ "/" + fileName);
                files.add(map);
            }
        } catch (IOException e) {
            System.err.println("Error listing directory: " + directory);
        }
        return files;
    }

    private void downloadFile(String ftpPath) throws IOException {
        String fileName = new File(ftpPath).getName();
        String localPath = localBaseDir + File.separator + fileName;
        File localFile = new File(localPath);

        // 1. 创建本地目录
        if (!localFile.getParentFile().exists()) {
            localFile.getParentFile().mkdirs();
        }

        //获取ftpPath上级目录
        String remotePath = ftpPath.substring(0, ftpPath.lastIndexOf("/"));
        // 切换到文件所在目录
        if (!ftpClient.changeWorkingDirectory(remotePath)) {
            log.warn("无法切换至目录: {}", remotePath);
            return;
        }

        // 2. 下载文件
        try (OutputStream out = new FileOutputStream(localFile)) {
            if (ftpClient.retrieveFile(ftpPath, out)) {
                System.out.printf("Downloaded: %-50s [%.2f MB]%n",
                        ftpPath, localFile.length() / 1024.0 / 1024.0);
            } else {
                System.err.println("Download failed: " + ftpPath);
            }
        }
    }

    private Set<String> fetchExistingFileNamesFromDB() {
        // 实际项目中替换为你的数据库查询
        // 示例：使用JDBC或JPA查询
        Set<String> existingFiles = new HashSet<>();
        // 模拟数据库查询（实际替换）
        try (Connection conn = DriverManager.getConnection("jdbc:...")) {
            try (PreparedStatement stmt = conn.prepareStatement("SELECT filename FROM download_table")) {
                try (ResultSet rs = stmt.executeQuery()) {
                    while (rs.next()) {
                        existingFiles.add(rs.getString("filename"));
                    }
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return existingFiles;
    }


    public void shutdown() {
        try {
            ftpClient.logout();
            ftpClient.disconnect();
            executor.shutdown();
            executor.awaitTermination(5, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
