#include <filesystem>
#include <iostream>
#include <wx/app.h>
#include <wx/arrstr.h>
#include <wx/filename.h>
#include <wx/log.h>
#include <wx/stdpaths.h>
#include <wx/utils.h>
#include <wx/xml/xml.h>

namespace fs = std::filesystem;

struct Configure {
    wxString name;
    wxString work_dir;
    wxArrayString exclude;
};

static wxString work_path;
static wxString cw_work_path;

bool parse_xml(const wxString& filepath, const wxString& name,
               Configure& config)
{
    wxXmlDocument xmlDoc;
    if (!xmlDoc.Load(filepath)) {
        return false;
    }

    wxXmlNode* root = xmlDoc.GetRoot();
    auto c = root->GetChildren();
    if (!c) {
        wxLogMessage("解析Xml失败。");
        return false;
    }
    bool find = false;
    while (c) {
        if (c->GetName() != "Item") {
            c = c->GetNext();
            continue;
        }
        if (c->GetAttribute("Name") != name) {
            c = c->GetNext();
            continue;
        }
        find = true;
        config.name = name;
#ifdef _WIN32
        config.work_dir = c->GetAttribute("WinWorkPath");
#else
        config.work_dir = c->GetAttribute("UnixWorkPath");
#endif
        auto p = c->GetChildren();
        while (p) {
            config.exclude.push_back(p->GetNodeContent());
            p = p->GetNext();
        }
        break;
    }
    if (!find) {
        wxLogMessage(wxT("未找到%s的配置。"), name);
        return false;
    } else {
        wxLogMessage(wxT("找到%s的配置。"), name);
    }
    return true;
}

wxString ConvertToCygwinPath(const wxString& path)
{
#ifdef _WIN32
    // 提取驱动器字母
    wxString drive = path.BeforeFirst('\\').Upper();
    drive.erase(1, 1);
    wxString restPath = path.AfterFirst('\\');

    // 替换为 Cygwin 格式
    wxString cygwinPath = "/cygdrive/" + drive.Lower();
    if (!restPath.empty()) {
        cygwinPath.append("/" + restPath);
    }
    cygwinPath.Replace("\\", "/");
    return cygwinPath;
#else
    return path;
#endif
}

wxString get_cmd(Configure& config, bool to_cur)
{
    wxString cmd_str;

#if _WIN32
    wxString cmd = work_path + "cwrsync\\bin\\rsync.exe ";
    cmd_str.append(cmd);
#else
    cmd_str.append("rsync ");
#endif

    cmd_str.append("-av");
    wxString dir_str;

    if (to_cur) {
        fs::path path(config.work_dir.ToStdString());
        path.append(config.name.ToStdString());
        dir_str.append(ConvertToCygwinPath(wxString(path.string())));
        dir_str.append(" " + cw_work_path);
    } else {
        fs::path path(cw_work_path.ToStdString());
        path.append(config.name.ToStdString());
        dir_str.append(wxString(path.string()));
        dir_str.append(" " + ConvertToCygwinPath(config.work_dir));
    }

    for (const auto& data : config.exclude) {
        cmd_str.append(" --exclude=" + data);
    }
    cmd_str.append(" ");
    cmd_str.append(dir_str);
    wxLogMessage(cmd_str);
    return cmd_str;
}

int main(int argc, char* argv[])
{
    // 确保当前程序能够与所使用的 wxWidgets 库兼容
    wxApp::CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE, "program");
    wxInitializer initializer;
    if (!initializer) {
        std::cout << "初始化失败。" << std::endl;
        return -2;
    }

    if (argc < 3) {
        std::cout << "需要传入文件夹名称[XXX]及方向[From/To]。" << std::endl;
        return 0;
    }

    wxString oper_dir(argv[1]);
    wxString direct(argv[2]);

    if (direct != "From" && direct != "To") {
        std::cout << "方向不合法,必须是[From/To]。";
        return -3;
    }

    // 读取配置文件 msync.xml
    const wxStandardPaths& stdpath = wxStandardPaths::Get();
    wxString exe_path = stdpath.GetExecutablePath();
    wxFileName file_name(exe_path);
    work_path = file_name.GetPathWithSep();
    cw_work_path = ConvertToCygwinPath(work_path);
    wxString config_path = work_path + "msync.xml";

    Configure config;
    if (!parse_xml(config_path, oper_dir, config)) {
        return -1;
    }

    auto command = get_cmd(config, direct == "From");
    wxArrayString output;
    // 使用 wxExecute 执行命令
    long result = wxExecute(command, output, wxEXEC_SYNC);
    wxLogMessage(wxT("命令执行结果:%ld"), result);
    wxString out_str;
    for (const auto& data : output) {
        out_str.append(data + "\n");
    }
    wxLogMessage(wxT("命令输出:\n%s\n"), out_str);
    return 0;
}