#include "KMPluginSynchronizer.h"
#include "KMLogger.h"
#include <fstream>
#include <iostream>
#include <set>

bool KMPluginSynchronizer::syncPlugins(const fs::path& versionDataPath,
                                   const std::vector<std::string>& exportPlugins,
                                   const fs::path& targetBaseDir) {

    fs::path pluginsListFile = targetBaseDir / "plugins.list";
    std::set<std::string> allPlugins;

    try {
        if (!fs::exists(targetBaseDir)) {
            fs::create_directories(targetBaseDir);
        }

        if (fs::exists(pluginsListFile)) {
            if (!readExistingPluginsList(pluginsListFile, allPlugins)) {
                return false;
            }
        }

        // 处理 exportPlugins，支持 ':' 分割的路径
        for (const auto& plugin : exportPlugins) {
            if (plugin.empty()) continue;

            std::string targetPluginPath = plugin;
            std::string sourcePluginPath = plugin;

            size_t colonPos = plugin.find(':');
            if (colonPos != std::string::npos) {
                sourcePluginPath = plugin.substr(0, colonPos);
                targetPluginPath = plugin.substr(colonPos + 1);
                kmlogger.info("Split path - source: %s, target: %s", sourcePluginPath.c_str(), targetPluginPath.c_str());
            }

            // 将目标路径添加到 allPlugins（用于记录和后续处理）
            if (!targetPluginPath.empty()) {
                allPlugins.insert(targetPluginPath);
            }

            std::string sourceRel = sourcePluginPath;
            std::string targetRel = targetPluginPath;

            if(!sourceRel.empty() && sourceRel[0] == '/') {
                sourceRel.erase(0, 1);
            }
            if(!targetRel.empty() && targetRel[0] == '/') {
                targetRel.erase(0, 1);
            }

            fs::path sourcePluginDir = versionDataPath / sourceRel;
            fs::path targetPluginDir = targetBaseDir / targetRel;

            kmlogger.info("Plugin syncing from: %s to: %s", sourcePluginDir.string().c_str(), targetPluginDir.string().c_str());

            if (!syncSinglePlugin(sourcePluginDir, targetPluginDir)) {
                kmlogger.error("Failed to sync plugin: %s", plugin.c_str());
                return false;
            }
        }

        // 将原有的插件也同步一次（确保完整性）
        for (const auto& plugin : allPlugins) {
            // 跳过已经在上面处理过的插件
            bool alreadyProcessed = false;
            for (const auto& exported : exportPlugins) {
                size_t colonPos = exported.find(':');
                std::string targetPath = (colonPos != std::string::npos) ? exported.substr(colonPos + 1) : exported;
                if (targetPath == plugin) {
                    alreadyProcessed = true;
                    break;
                }
            }
            if (alreadyProcessed) continue;

            // 处理原有的插件（没有在本次 exportPlugins 中的）
            std::string pluginRel = plugin;
            if(!pluginRel.empty() && pluginRel[0] == '/') {
                pluginRel.erase(0, 1);
            }

            fs::path sourcePluginDir = versionDataPath / pluginRel;
            fs::path targetPluginDir = targetBaseDir / pluginRel;

            kmlogger.info("Existing plugin syncing from: %s to: %s", sourcePluginDir.string().c_str(), targetPluginDir.string().c_str());

            if (!syncSinglePlugin(sourcePluginDir, targetPluginDir)) {
                kmlogger.error("Failed to sync existing plugin: %s", plugin.c_str());
            }
        }

        if (!writePluginsList(pluginsListFile, allPlugins)) {
            return false;
        }

        return true;

    } catch (const fs::filesystem_error& e) {
        kmlogger.error("Filesystem error: %s", std::string(e.what()).c_str());
        return false;
    } catch (const std::exception& e) {
        kmlogger.error("FError: %s", std::string(e.what()).c_str());
        return false;
    }
}

bool KMPluginSynchronizer::readExistingPluginsList(const fs::path& pluginsListFile, std::set<std::string>& allPlugins) {
    try {
        std::ifstream inFile(pluginsListFile);
        if (!inFile.is_open()) {
            kmlogger.error("Failed to open plugins list file for reading: %s", pluginsListFile.string().c_str());
            return false;
        }
        
        std::string line;
        while (std::getline(inFile, line)) {
            if (!line.empty()) {
                allPlugins.insert(line);
            }
        }
        inFile.close();
        return true;
        
    } catch (const std::exception& e) {
        kmlogger.error("Error reading plugins list: %s", std::string(e.what()).c_str());
        return false;
    }
}

bool KMPluginSynchronizer::writePluginsList(const fs::path& pluginsListFile, const std::set<std::string>& allPlugins) {
    try {
        std::ofstream outFile(pluginsListFile);
        if (!outFile.is_open()) {
            kmlogger.error("Failed to open plugins list file for writing: %s", pluginsListFile.string().c_str());
            return false;
        }
        
        for (const auto& plugin : allPlugins) {
            outFile << plugin << std::endl;
        }
        outFile.close();
        return true;
        
    } catch (const std::exception& e) {
        kmlogger.error("Error writing plugins list: %s", std::string(e.what()).c_str());
        return false;
    }
}

bool KMPluginSynchronizer::syncSinglePlugin(const fs::path& sourcePluginDir, const fs::path& targetPluginDir) {
    try {
        if (!fs::exists(sourcePluginDir)) {
            kmlogger.error("Source path does not exist: %s", sourcePluginDir.string().c_str());
            return false;
        }

        fs::create_directories(targetPluginDir.parent_path());

        std::string src = sourcePluginDir.string();
        std::string dst = targetPluginDir.string();

        if (fs::is_directory(sourcePluginDir)) {
            if (src.back() != '/') src += '/';
        }

        // -a: Archive mode; enables recursive copying while preserving symbolic links, permissions, timestamps, etc.
        // --links: Preserve symbolic links
        std::string cmd = "rsync -a --links " + src + " " + dst;

        kmlogger.info("Executing rsync: %s", cmd.c_str());
        int ret = std::system(cmd.c_str());
        if (ret != 0) {
            kmlogger.error("rsync failed with code %d", ret);
            return false;
        }

        kmlogger.info("rsync completed: %s -> %s", sourcePluginDir.string().c_str(), targetPluginDir.string().c_str());
        return true;
    }
    catch (const std::exception& e) {
        kmlogger.error("Exception during syncSinglePlugin: %s", e.what());
        return false;
    }
}