package com.njcn.filesync.sftp;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
import com.njcn.filesync.config.FileSyncState;
import com.njcn.filesync.config.ServerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
import java.util.Objects;
import java.util.Vector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Description:
 * Date: 2025/10/16  下午 3:02【需求编号】
 *
 * @author clam
 * @version V1.0.0
 */
public class IncrementalFileSync {

    private static final Logger logger = LoggerFactory.getLogger(IncrementalFileSync.class);

    private ServerConfig sourceConfig;
    private ServerConfig targetConfig;
    private FileSyncState syncState;
//    private ScheduledExecutorService scheduler;
    private WatchService watchService;
    private List<String> ipList;
    private List<String> pathList;
    private boolean isMonitoring = false;

    public IncrementalFileSync(ServerConfig sourceConfig, ServerConfig targetConfig, String stateFilePath,List<String> ipList,List<String> pathList) {
        this.sourceConfig = sourceConfig;
        this.targetConfig = targetConfig;
        this.syncState = new FileSyncState(stateFilePath);
//        this.scheduler = Executors.newScheduledThreadPool(2);
        this.ipList = ipList;
        this.pathList = pathList;
    }

    /**
     * 执行一次增量同步
     */
    public void syncOnce() {
         logger.info("Starting incremental synchronization...");

        try (SftpClient sourceClient = new SftpClient();
             SftpClient targetClient = new SftpClient()) {

            // 连接到源服务器和目标服务器
            sourceClient.connect(sourceConfig);
            logger.info("sourceClient concet succss");
            targetClient.connect(targetConfig);
            logger.info("targetClient concet succss");

            // 同步文件
            syncDirectory("", sourceClient, targetClient);

            logger.info("Incremental synchronization completed successfully");

        } catch (Exception e) {
            logger.error("Synchronization failed", e);
        } finally {
            syncState.saveState();
        }
    }

    public void syncOnceByPathList() {
        logger.info("Starting incremental synchronization...");

        try (SftpClient sourceClient = new SftpClient();
             SftpClient targetClient = new SftpClient()) {

            // 连接到源服务器和目标服务器
            sourceClient.connect(sourceConfig);
            logger.info("sourceClient concet succss");
            targetClient.connect(targetConfig);
            logger.info("targetClient concet succss");

            // 同步文件
            syncPathList( sourceClient, targetClient,pathList);

            logger.info("Incremental synchronization completed successfully");

        } catch (Exception e) {
            logger.error("Synchronization failed", e);
        } finally {
            syncState.saveState();
        }
    }

    private void syncPathList(SftpClient sourceClient, SftpClient targetClient, List<String> pathList) throws SftpException {

        ChannelSftp destSftp = targetClient.getChannel();
        ChannelSftp sourceSftp = sourceClient.getChannel();
        logger.info("-----------------------------------------------beginsyncByPathList----------------------");

        for (String path : pathList) {
            String sourceFilePath="";
            if(sourceConfig.getBasePath().endsWith("/")){
                sourceFilePath  = sourceConfig.getBasePath()  + path;
            }else {
                sourceFilePath  = sourceConfig.getBasePath() + "/" + path;
            }

            String destFilePath = targetConfig.getBasePath() + "/" + path;
            boolean flag = safeFileExists(sourceSftp, sourceFilePath);


            if(flag){
                boolean needSync = safeFileExists(destSftp, destFilePath);
                if(!needSync){
                    logger.info(sourceFilePath+"同步成功");
                    // 上传文件

                    try (InputStream inputStream = sourceSftp.get(sourceFilePath)) {
                        int lastSlashIndex = destFilePath.lastIndexOf('/');
                        String directoryPath = destFilePath.substring(0, lastSlashIndex);
                        targetClient.createRemoteDirectory(directoryPath);

                        destSftp.put(inputStream, destFilePath);
//                            System.out.println("Synced: " + sourceFilePath);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

            }else {
                continue;
            }
        }

    }

    public boolean safeFileExists(ChannelSftp sftpChannel, String remotePath) {
        // 1. 基础检查
        if (remotePath == null || remotePath.trim().isEmpty()) {
            return false;
        }

        // 2. 检查连接 (根据你的JSch版本和封装方式)
        if (sftpChannel == null || !sftpChannel.isConnected()) {
            logger.warn("SFTP channel is not connected.");
            return false;
        }

        // 3. 尝试获取属性判断存在性
        try {
            sftpChannel.lstat(remotePath);
            return true;
        } catch (SftpException e) {
            if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
                return false;
            } else {
                // 记录非“文件不存在”的其他异常（如权限问题）
                logger.error("SFTP error while checking file existence: " + remotePath, e);
                // 根据业务逻辑决定：返回false或抛出异常
                return false;
            }
        } catch (Exception e) {
            // 处理其他意外异常，如网络中断
            logger.error("Unexpected error checking file existence: " + remotePath, e);
            return false;
        }
    }

    /**
     * 开始定时同步
     */
//    public void startScheduledSync(long interval, TimeUnit timeUnit) {
//        logger.info("Starting scheduled synchronization every {} {}", interval, timeUnit);
//
//        scheduler.scheduleAtFixedRate(() -> {
//            try {
//                syncOnce();
//            } catch (Exception e) {
//                logger.error("Scheduled synchronization failed", e);
//            }
//        }, 0, interval, timeUnit);
//    }

    /**
     * 开始文件监控同步（仅当源服务器是本地文件系统时）
     */
//    public void startFileWatchSync() throws IOException {
//        if (!isLocalServer(sourceConfig)) {
//            throw new IllegalStateException("File watching is only supported for local source servers");
//        }
//
//        watchService = FileSystems.getDefault().newWatchService();
//        Path sourcePath = Paths.get(sourceConfig.getBasePath());
//
//        // 注册目录监听
//        sourcePath.register(watchService,
//                StandardWatchEventKinds.ENTRY_CREATE,
//                StandardWatchEventKinds.ENTRY_MODIFY,
//                StandardWatchEventKinds.ENTRY_DELETE);
//
//        isMonitoring = true;
//        logger.info("Starting file watch synchronization for: {}", sourcePath);
//
//        scheduler.execute(() -> {
//            while (isMonitoring) {
//                try {
//                    WatchKey key = watchService.take();
//
//                    for (WatchEvent<?> event : key.pollEvents()) {
//                        WatchEvent.Kind<?> kind = event.kind();
//
//                        if (kind == StandardWatchEventKinds.OVERFLOW) {
//                            continue;
//                        }
//
//                        @SuppressWarnings("unchecked")
//                        WatchEvent<Path> ev = (WatchEvent<Path>) event;
//                        Path fileName = ev.context();
//                        Path fullPath = sourcePath.resolve(fileName);
//
//                        logger.info("File change detected: {} - {}", kind.name(), fullPath);
//
//                        // 延迟一下，确保文件操作完成
//                        Thread.sleep(1000);
//                        syncOnce();
//                    }
//
//                    key.reset();
//
//                } catch (InterruptedException e) {
//                    Thread.currentThread().interrupt();
//                    break;
//                } catch (Exception e) {
//                    logger.error("File watch error", e);
//                }
//            }
//        });
//    }

//    /**
//     * 停止所有同步任务
//     */
//    public void stop() {
//        isMonitoring = false;
//        scheduler.shutdown();
//
//        if (watchService != null) {
//            try {
//                watchService.close();
//            } catch (IOException e) {
//                logger.error("Error closing watch service", e);
//            }
//        }
//
//        logger.info("File synchronization stopped");
//    }

    private void syncDirectory(String relativePath, SftpClient sourceClient, SftpClient targetClient) {
//        String sourceDir = getFullPath(sourceConfig.getBasePath(), relativePath);
//        String targetDir = getFullPath(targetConfig.getBasePath(), relativePath);
        try {
            // 如果是本地文件系统，使用Java NIO
            if (isLocalServer(sourceConfig)) {
                syncLocalDirectory(relativePath, sourceClient, targetClient);
            } else {
                // 远程服务器同步逻辑（简化实现）
                syncRemoteDirectory(sourceClient, targetClient, sourceConfig.getBasePath(),targetConfig.getBasePath());
            }

        } catch (Exception e) {
            logger.error("Error syncing directory: {}", relativePath, e);
        }
    }

    private void syncLocalDirectory(String relativePath, SftpClient sourceClient, SftpClient targetClient)
            throws IOException {

        Path sourcePath = Paths.get(sourceConfig.getBasePath(), relativePath);

        Files.walkFileTree(sourcePath, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                if (Files.isRegularFile(file)) {

                    String relativeFile = sourcePath.relativize(file).toString();
                    // 检查文件路径是否包含ipList中的任意IP
                    boolean shouldSync = ipList.stream().anyMatch(ip -> {
                        // 检查相对路径是否以IP地址开头
                        return relativeFile.startsWith(ip + File.separator) ||
                                relativeFile.startsWith(ip + "/") ||
                                relativeFile.startsWith(ip + "\\");
                    });
                    if (shouldSync){
                        syncFileIfNeeded(relativeFile, sourceClient, targetClient);
                    }
                }
                return FileVisitResult.CONTINUE;
            }
        });




    }
    private void syncRemoteDirectory(SftpClient sourceClient, SftpClient destClient, String sourceDir, String destDir) throws SftpException {
        ChannelSftp destSftp = destClient.getChannel();
        ChannelSftp sourceSftp = sourceClient.getChannel();
        logger.info("-----------------------------------------------beginsyncRemoteDirectory----------------------");
        // 获取源目录下的文件列表
        Vector<ChannelSftp.LsEntry> files = sourceSftp.ls(sourceDir);

        for (ChannelSftp.LsEntry entry : files) {
            String filename = entry.getFilename();
            if (".".equals(filename) || "..".equals(filename)) {
                continue;
            }

            String sourceFilePath = sourceDir + "/" + filename;
            String destFilePath = destDir + "/" + filename;
            boolean shouldSync = ipList.stream().anyMatch(ip -> {
                // 检查路径是否包含设备ip
                return sourceFilePath.contains(ip ) ;

            });
            if(shouldSync){
                if (entry.getAttrs().isDir()) {
                    // 如果是目录，建目录递归同步

                    destClient.createRemoteDirectory(destFilePath);
                    syncRemoteDirectory(sourceClient, destClient, sourceFilePath, destFilePath);
                } else {
                    // 如果是文件，判断是否需要同步
                    if (needSync(sourceSftp, destSftp, sourceFilePath, destFilePath, entry)) {

                        // 传输文件
                        try (InputStream inputStream = sourceSftp.get(sourceFilePath)) {
                            destSftp.put(inputStream, destFilePath);
//                            System.out.println("Synced: " + sourceFilePath);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                    }
                }
            }

        }

    }

    private boolean needSync(ChannelSftp sourceSftp, ChannelSftp destSftp, String sourcePath, String destPath, ChannelSftp.LsEntry sourceEntry) throws SftpException {
        // 判断目标文件是否存在
        SftpATTRS destAttrs;
        long sourceMTime = sourceEntry.getAttrs().getMTime();
        long currentTimeSeconds = System.currentTimeMillis() / 1000;
        long halfYearSeconds = 100L * 24 * 60 * 60; // 假设半年为180天
        if (sourceMTime < currentTimeSeconds - halfYearSeconds) {
                return false;
        }
        try {
            destAttrs = destSftp.lstat(destPath);
        } catch (SftpException e) {
            // 如果目标文件不存在，肯定需要同步
            return true;
        }

        // 比较文件的修改时间
        long destMTime = destAttrs.getMTime();

        // 如果源文件的修改时间晚于目标文件，则需要同步
        if (sourceMTime > destMTime) {
            return true;
        }

        // 你也可以选择性地比较文件大小
        // return sourceEntry.getAttrs().getSize() != destAttrs.getSize();

        return false;
    }

    private void syncFileIfNeeded( String relativeFile, SftpClient sourceClient, SftpClient targetClient) {
        try {
            String sourceFullPath = getFullPath(sourceConfig.getBasePath(), relativeFile);
            FileSyncState.FileMetadata currentMetadata = syncState.getFileMetadata(sourceFullPath);

            if (syncState.isFileChanged(relativeFile, currentMetadata)) {
                logger.info("Syncing changed file: {}", relativeFile);

                // 上传文件
                targetClient.uploadFile(sourceFullPath,
                        getFullPath(targetConfig.getBasePath(),
                                new File(relativeFile).getParent() != null ?
                                        new File(relativeFile).getParent() : ""));

                // 更新同步状态
                syncState.updateFileState(relativeFile, currentMetadata);
            } else {
                logger.debug("File unchanged, skipping: {}", relativeFile);
            }

        } catch (Exception e) {
            logger.error("Error syncing file: {}", relativeFile, e);
        }
    }

    private String getFullPath(String basePath, String relativePath) {
        if (relativePath == null || relativePath.isEmpty()) {
            return basePath;
        }

        if (basePath.endsWith("/") || basePath.endsWith("\\")) {
            return basePath + relativePath;
        } else {
            if(basePath.contains("/")){
                return basePath + "/" + relativePath;
            }else if(basePath.contains("\\")){
                return basePath + "\\" + relativePath;
            }

        }
        return basePath;
    }

    private boolean isLocalServer(ServerConfig config) {
        // 简单的本地服务器检测逻辑
        return "localhost".equals(config.getHost()) ||
                "127.0.0.1".equals(config.getHost());
    }
}
