#include "KMParseSummaryJson.h"

#include "common/KMLogger.h"
#include "common/semver.hpp"
#include "common/KMFormatter.h"

class KMParseSummaryJson::Private {
public:
    Private();
    ~Private();

    json m_jsonData;
    SummaryInfo m_summaryInfo;
    string completeRef;
    std::shared_ptr<KMFormatter> m_format;
};

KMParseSummaryJson::Private::Private()
{


}

KMParseSummaryJson::Private::~Private()
{
    
}

KMParseSummaryJson::KMParseSummaryJson()
    : d(make_shared<Private>())
{
    d->m_format = shared_ptr<KMFormatter>(new KMFormatter());
}

KMParseSummaryJson::KMParseSummaryJson(const std::string &filePath)
    : d(make_shared<Private>())
{
    std::ifstream inputFile(filePath);

    if (inputFile.is_open())
    {
        std::string jsonContent((std::istreambuf_iterator<char>(inputFile)), std::istreambuf_iterator<char>());
        std::string cleanedJson = removeComments(jsonContent); // 移除注释
        std::cout << cleanedJson << std::endl;

        // 使用 nlohmann::json 解析
        d->m_jsonData =  json::parse(cleanedJson);

        // d->m_jsonData = json::parse(inputFile); // 解析带注释的 json 文件会报错，需要直接赋值，否则会报错
        inputFile.close();
    }
    else
    {
        throw std::runtime_error("Unable to open json file");
    }
}

KMParseSummaryJson::~KMParseSummaryJson()
{
}

std::string KMParseSummaryJson::removeComments(const std::string &jsonString)
{
    std::regex commentPattern(R"(\/\/[^\n]*|\/\*[\s\S]*?\*\/)");
    return std::regex_replace(jsonString, commentPattern, "");
}

bool KMParseSummaryJson::loadFile(const std::string &filePath)
{
    std::ifstream inputFile(filePath);

    if (inputFile.is_open())
    {
        d->m_jsonData = json::parse(inputFile); // 需要直接赋值，否则会报错
        inputFile.close();
        return true;
    }
    else
    {
        return false;
    }
}

bool KMParseSummaryJson::findMatchMaxVesion(KMPMRef pmRef, string moduleKey, ModuleInfo moduleData, string &maxVersionStr)
{
    vector<string> versionVector; // 保存符合条件的版本号

    for (const auto &[versionKey, versionData] : moduleData.versionInfo)
    {
        if (!pmRef.ref.version.empty())
        {
            if (pmRef.ref.version != versionKey)
            {
                if (KMUtil::startsWith(versionKey, pmRef.ref.version))
                {
                    versionVector.push_back(versionKey);
                }
            }
            else
            {
                versionVector.push_back(versionKey);
            }
        }
        else
        {
            versionVector.push_back(versionKey);
        }
    }

    if (versionVector.size() > 0)
    {
        Semver::KMVersion maxVersion = Semver::KMVersion::parse(versionVector.at(0));
        for (const auto &version : versionVector)
        {
            Semver::KMVersion ver = Semver::KMVersion::parse(version);

            if (maxVersion < ver)
            {
                maxVersion = ver;
            }
        }

        maxVersionStr = maxVersion.str();
        return true;
    }
    else
    {
        return false;
    }
}


void KMParseSummaryJson::from_json(const json &j, VersionInfo &version)
{
    if (j.contains("installed-size"))
    {
        j.at("installed-size").get_to(version.installedSize);
    }

    if (j.contains("extensions"))
    {
        j.at("extensions").get_to(version.extensions);
    }

    if (j.contains("base"))
    {
        j.at("base").get_to(version.base);
    }

    if (j.contains("runtime"))
    {
        j.at("runtime").get_to(version.runtime);
    }
}

void KMParseSummaryJson::from_json(const json &j, ModuleInfo &module)
{
    for (auto &item : j.items())
    {
        if (KMUtil::startsWith(item.key(), "name"))
        {
            module.nameInfo[item.key()] = item.value();
        }
        else if (KMUtil::startsWith(item.key(), "description"))
        {
            module.descriptionInfo[item.key()] = item.value();
        }
        else
        {
            VersionInfo versionData;
            from_json(item.value(), versionData);
            module.versionInfo[item.key()] = versionData;
        }
    }
}

void KMParseSummaryJson::from_json(const json &j, IdInfo &id)
{
    for (auto &module : j.items())
    {
        ModuleInfo moduleData;
        from_json(module.value(), moduleData);
        id.moduleInfo[module.key()] = moduleData;
    }
}

void KMParseSummaryJson::from_json(const json &j, KindInfo &kind)
{
    for (auto &id : j.items())
    {
        IdInfo idData;
        from_json(id.value(), idData);
        kind.idInfo[id.key()] = idData;
    }
}

void KMParseSummaryJson::from_json(const json &j, ArchInfo &arch)
{
   for (auto &kind : j.items())
    {
        KindInfo kindData;
        from_json(kind.value(), kindData);
        arch.kindInfo[kind.key()] = kindData;
    }
}

void KMParseSummaryJson::from_json(const json &j, ChannelInfo &channel)
{
    for (auto &arch : j.items())
    {
        // a.archInfo[arch.key()] = arch.value().get<TypeInfo>(); // 此种方式不行
        ArchInfo archData;
        from_json(arch.value(), archData);
        channel.archInfo[arch.key()] = archData;
    }
}

void KMParseSummaryJson::from_json(const json &j, SummaryInfo &summary)
{
    for (auto &channel : j.items())
    {
        kmlogger.debug("arch: %s value: %s", channel.key().c_str(), channel.value());

        ChannelInfo channelData;
        from_json(channel.value(), channelData);
        summary.channelInfo[channel.key()] = channelData;

    }
}

void KMParseSummaryJson::printJson()
{
    kmlogger.debug("summary.json: %s", d->m_jsonData.dump(4).c_str());

    // 第一层遍历 Json 数据
    for (auto &item : d->m_jsonData.items())
    {
        kmlogger.debug("item: %s value: %s", item.key().c_str(), item.value());
    }
}

void KMParseSummaryJson::parseSummaryJson()
{
    from_json(d->m_jsonData, d->m_summaryInfo);
    printSummaryJson(d->m_summaryInfo);
}

void KMParseSummaryJson::printSummaryJson(const SummaryInfo &data)
{
    for (const auto &[channelKey, channelData] : data.channelInfo)
    {
        kmlogger.debug("channelKey: %s", channelKey.c_str()); // main, stable
        for (const auto &[archKey, archData] : channelData.archInfo)
        {
            kmlogger.debug("archKey: %s", archKey.c_str()); // x86_64, arm64
            for (const auto &[kindKey, kindData] : archData.kindInfo)
            {
                kmlogger.debug("kindKey: %s", kindKey.c_str()); // app, runtime, base, extension
                for (const auto &[idKey, idData] : kindData.idInfo)
                {
                    kmlogger.debug("idKey: %s", idKey.c_str()); // top.openkylin.Music, top.openkylin.base, top.ukui.runtime
                    for (const auto &[moduleKey, moduleData] : idData.moduleInfo)
                    {
                        kmlogger.debug("moduleKey: %s", moduleKey.c_str());
                        {
                            for (const auto &[nameKey, nameData] : moduleData.nameInfo)
                            {
                                if (KMUtil::startsWith(nameKey, "name"))
                                {
                                    kmlogger.debug("nameKey: %s", nameKey.c_str());
                                }
                            }

                            for (const auto &[descriptionKey, descriptionData] : moduleData.descriptionInfo)
                            {
                                if (KMUtil::startsWith(descriptionKey, "name"))
                                {
                                    kmlogger.debug("descriptionKey: %s", descriptionKey.c_str());
                                }
                            }
                        }

                        {
                            for (const auto &[versionKey, versionData] : moduleData.versionInfo)
                            {
                                kmlogger.debug("versionKey: %s", versionKey.c_str()); // 2.0.0.0

                                // 打印每个 version
                                kmlogger.debug("installedSize: %ld base: %s runtime: %s", versionData.installedSize, versionData.base.empty() ? "" : versionData.base.c_str(),
                                              versionData.runtime.empty() ? "" : versionData.runtime.c_str());

                                if (!versionData.extensions.empty())
                                {
                                    kmlogger.debug(" Extension: ");
                                    for (const auto &ext : versionData.extensions)
                                    {
                                        if (!ext.empty())
                                        {
                                            kmlogger.debug("ext: %s", ext.c_str());
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

string KMParseSummaryJson::toLowerUtf8(const std::string& str) {
    wstring_convert<std::codecvt_utf8<wchar_t>> converter;
    wstring wstr = converter.from_bytes(str);
    transform(wstr.begin(), wstr.end(), wstr.begin(), 
                   [](wchar_t c) { return std::towlower(c); });
    return converter.to_bytes(wstr);
}

string KMParseSummaryJson::printSearchJson(const string &searchId, const string &specifyArch, bool isPrint)
{   
    if(isPrint)
    {
        d->m_format->setColumnWidth(35, 35, 15, 10, 15, 25, 30, 25);
        d->m_format->setShowArch(false);
        d->m_format->setShowChannel(true);
        d->m_format->printHeader();
    }
        
    KMEntry entry;
    KMUtil m_localeLanguage;
    std::string localeName = m_localeLanguage.getCurrentLocale();
    for (auto &channel : d->m_jsonData.items())
    {
        kmlogger.debug("channel: %s", channel.key().c_str());
        entry.channel = channel.key();
        for (auto &arch : channel.value().items())
        {
            kmlogger.debug("arch: %s", arch.key().c_str());
            entry.arch = arch.key();
            if(!specifyArch.empty() && arch.key() != specifyArch)
            {
                continue;
            }
            for (auto &kind : arch.value().items())
            {
                
                for (auto &id : kind.value().items())
                {
                    string fid = id.key();
                
                    string fidLower = toLowerUtf8(fid);
                    string idLower = toLowerUtf8(searchId);
                    if (fidLower.find(idLower) != std::string::npos)
                    {
                        entry.id = fid;
                        for (auto &module : id.value().items())
                        {
                            entry.module = module.key();
                            if (module.value().contains("name") && module.value().contains("description"))
                            {
                                entry.name  = !module.value()["name[" + localeName + "]"].empty() ? module.value()["name[" + localeName + "]"] : module.value()["name"];
                                
                                entry.description = !module.value()["description[" + localeName + "]"].empty() ? module.value()["description[" + localeName + "]"] : module.value()["description"];
                                vector<string> versionVector;
                                for (auto &version : module.value().items())
                                {
                                    if (version.key() != "name" && version.key() != "description" && version.key() != "name[" + localeName + "]" && version.key() !="description[" + localeName + "]" )
                                    {
                                        entry.version = version.key();
                                        if(searchId == id.key() && entry.module == "binary")
                                        {
                                            versionVector.push_back(entry.version);
                                        }
                                        string installedSize = KMUtil::formatInstalledSize((double)version.value()["installed-size"]);
                                        entry.size = installedSize ; 
                                        if(isPrint)
                                        {
                                            d->m_format->printEntry(entry); 
                                        }                                                                                 
                                    }
                                }
                                if (versionVector.size() > 0)
                                {
                                    Semver::KMVersion maxVersion = Semver::KMVersion::parse(versionVector.at(0));
                                    for (const auto &version : versionVector)
                                    {
                                        Semver::KMVersion ver = Semver::KMVersion::parse(version);

                                        if (maxVersion < ver)
                                        {
                                            maxVersion = ver;
                                        }
                                    }
                                    d->completeRef = entry.channel;
                                    d->completeRef.append("/").append(entry.arch).append("/")
                                                .append(kind.key()).append("/")
                                                .append(entry.id).append("/")
                                                .append(entry.module).append("/")
                                                .append(maxVersion.str());
                                    versionVector.clear();
                                }

                            }
                        }
                    }
                }
            }
        }
    }
    d->m_format->printFooter();
    return d->completeRef;
}

bool KMParseSummaryJson::getSummaryInfo(KMPMRef &pmRef)
{
    string sortSearchRef;
    bool isSearched = false;

    for (const auto &[channelKey, channelData] : d->m_summaryInfo.channelInfo)
    {
        kmlogger.debug("channelKey: %s", channelKey.c_str());
        if (!pmRef.ref.channel.empty() && channelKey != pmRef.ref.channel)
        {
            continue;
        }

        for (const auto &[archKey, archData] : channelData.archInfo)
        {
            kmlogger.debug("archKey: %s", archKey.c_str());
            if (!pmRef.ref.arch.empty() && pmRef.ref.arch != archKey)
            {
                continue;
            }

            for (const auto &[kindKey, kindData] : archData.kindInfo)
            {
                kmlogger.debug("kindKey: %s", kindKey.c_str());
                if (!pmRef.ref.kind.empty() && pmRef.ref.kind != kindKey)
                {
                    continue;
                }

                for (const auto &[idKey, idData] : kindData.idInfo)
                {
                    kmlogger.debug("idKey: %s", idKey.c_str());
                    if (!pmRef.ref.id.empty() && pmRef.ref.id != idKey)
                    {
                        continue;
                    }


                    for (const auto &[moduleKey, moduleData] : idData.moduleInfo)
                    {
                        kmlogger.debug("moduleKey: %s", moduleKey.c_str());
                        if (!pmRef.ref.module.empty() && pmRef.ref.module != moduleKey)
                        {
                            continue;
                        }

                        // 获取 name 和 description 信息
                        getSummaryNameInfo(pmRef, moduleData);

                        {
                            string maxVersionStr;

                            bool getMaxVersionStrFlag = false;
                            getMaxVersionStrFlag = findMatchMaxVesion(pmRef, moduleKey, moduleData, maxVersionStr);

                            if (!getMaxVersionStrFlag)
                            {
                                return isSearched;
                            }

                            for (const auto &[versionKey, versionData] : moduleData.versionInfo)
                            {
                                kmlogger.debug("versionKey: %s", versionKey.c_str());
                                if (maxVersionStr != versionKey)
                                {
                                    continue;
                                }

                                isSearched = true;

                                pmRef.installedSize = versionData.installedSize;

                                // 打印每个module
                                kmlogger.debug("installedSize: %ld base: %s runtime: %s", versionData.installedSize, versionData.base.empty() ? "" : versionData.base.c_str(),
                                              versionData.runtime.empty() ? "" : versionData.runtime.c_str());
                            }
                        }
                    }

                }
            }
        }
    }

    return isSearched;
}

bool KMParseSummaryJson::getSummaryNameInfo(KMPMRef &pmRef, ModuleInfo moduleInfo)
{
    string locale = KMUtil::getCurrentLocale();
    string nameStr;
    string descriptionStr;

    for (const auto &[nameKey, nameData] : moduleInfo.nameInfo)
    {
        if (KMUtil::startsWith(nameKey, "name"))
        {
            kmlogger.debug("nameKey: %s", nameKey.c_str());
            if (nameKey == "name" || locale == "C")
            {
                nameStr = nameData;
            }
            else if (KMUtil::contains(nameKey, locale))
            {
                pmRef.name = nameData;
            }
        }
    }

    if (pmRef.name.empty())
    {
        pmRef.name = nameStr;
    }

    for (const auto &[descriptionKey, descriptionData] : moduleInfo.descriptionInfo)
    {
        if (KMUtil::startsWith(descriptionKey, "description"))
        {
            kmlogger.debug("descriptionKey: %s", descriptionKey.c_str());
            if (descriptionKey == "description" || locale == "C")
            {
                descriptionStr = descriptionData;
                KMUtil::removeTrailingNewline(descriptionStr);
            }
            else if (KMUtil::contains(descriptionKey, locale))
            {
                pmRef.description  = descriptionData;
                KMUtil::removeTrailingNewline(pmRef.description);
            }
        }
    }

    if (pmRef.description.empty())
    {
        pmRef.description = descriptionStr;
    }

    return true;
}

bool KMParseSummaryJson::fuzzyMatchCompletedRef(KMPMRef pmRef, vector<string> &fuzzyMatchRefs)
{
    string searchRef;
    string sortSearchRef;
    bool isSearched = false;

    for (const auto &[channelKey, channelData] : d->m_summaryInfo.channelInfo)
    {
        searchRef.clear();
        kmlogger.debug("channelKey: %s", channelKey.c_str());
        if (!pmRef.ref.channel.empty() && channelKey != pmRef.ref.channel)
        {
            continue;
        }
        string channelStr = searchRef.append(channelKey).append("/");

        for (const auto &[archKey, archData] : channelData.archInfo)
        {
            searchRef = channelStr;
            kmlogger.debug("archKey: %s", archKey.c_str());
            if (!pmRef.ref.arch.empty() && pmRef.ref.arch != archKey)
            {
                continue;
            }
            string archStr = searchRef.append(archKey).append("/");

            for (const auto &[kindKey, kindData] : archData.kindInfo)
            {
                searchRef = archStr;
                kmlogger.debug("kindKey: %s", kindKey.c_str());
                if (!pmRef.ref.kind.empty() && pmRef.ref.kind != kindKey)
                {
                    continue;
                }
                string kindStr = searchRef.append(kindKey).append("/");

                for (const auto &[idKey, idData] : kindData.idInfo)
                {
                    searchRef = kindStr;
                    kmlogger.debug("idKey: %s", idKey.c_str());
                    if (!pmRef.ref.id.empty() && pmRef.ref.id != idKey)
                    {
                        continue;
                    }
                    string idStr = searchRef.append(idKey).append("/");

                    for (const auto &[moduleKey, moduleData] : idData.moduleInfo)
                    {
                        searchRef = idStr;
                        kmlogger.debug("moduleKey: %s", moduleKey.c_str());
                        if (!pmRef.ref.module.empty() && pmRef.ref.module != moduleKey)
                        {
                            continue;
                        }

                        // module 为空时, 匹配所有 binary 模块
                        if (pmRef.ref.module.empty() && moduleKey != "binary")
                        {
                            continue;
                        }

                        string moduleStr = searchRef.append(moduleKey).append("/");

                        isSearched = matchVersionData(pmRef, moduleKey, moduleData, moduleStr, fuzzyMatchRefs);
                    }

                }
            }
        }
    }

    return isSearched;
}

bool KMParseSummaryJson::matchVersionData(KMPMRef pmRef, string moduleKey, ModuleInfo moduleData, string searchRef, vector<string> &fuzzyMatchRefs)
{
    bool isSearched = false;
    string tmpSearchRef = searchRef;

    {
        string maxVersionStr;

        bool getMaxVersionStrFlag = false;
        getMaxVersionStrFlag = findMatchMaxVesion(pmRef, moduleKey, moduleData, maxVersionStr);

        if (!getMaxVersionStrFlag)
        {
            return isSearched;
        }

        for (const auto &[versionKey, versionData] : moduleData.versionInfo)
        {
            searchRef = tmpSearchRef;
            kmlogger.debug("versionKey: %s", versionKey.c_str());
            if (maxVersionStr != versionKey)
            {
                continue;
            }
            string versionStr = searchRef.append(versionKey);

            isSearched = true;

            bool isMatch = false;
            for (const auto &version : fuzzyMatchRefs)
            {
                if (version.find(versionStr) != std::string::npos)
                {
                    isMatch = true;
                    break;
                }
            }

            if (isMatch)
            {
                continue;
            }

            fuzzyMatchRefs.push_back(versionStr);

            // base 获取队列
            if (!versionData.base.empty())
            {
                KMPMRef pmBaseRef = KMUtil::parseSummaryKMPMRef(versionData.base);
                pmBaseRef.ref.kind = BASE_TYPE_BASE;
                fuzzyMatchCompletedRef(pmBaseRef, fuzzyMatchRefs);
            }

            // runtime 获取队列
            if (!versionData.runtime.empty())
            {
                KMPMRef pmRuntimeRef = KMUtil::parseSummaryKMPMRef(versionData.runtime);
                pmRuntimeRef.ref.kind = BASE_TYPE_RUNTIME;
                fuzzyMatchCompletedRef(pmRuntimeRef, fuzzyMatchRefs);
            }

            // 打印每个module
            kmlogger.debug("installedSize: %ld base: %s runtime: %s", versionData.installedSize, versionData.base.empty() ? "" : versionData.base.c_str(),
                          versionData.runtime.empty() ? "" : versionData.runtime.c_str());

            // extension 获取队列
            if (!versionData.extensions.empty())
            {
                kmlogger.debug(" Extension: ");
                for (const auto &ext : versionData.extensions)
                {
                    if (!ext.empty())
                    {
                        kmlogger.debug("ext: %s", ext.c_str());
                        KMPMRef pmExtensionRef = KMUtil::parseSummaryKMPMRef(ext);
                        pmExtensionRef.ref.kind = BASE_TYPE_EXTENSION;
                        fuzzyMatchCompletedRef(pmExtensionRef, fuzzyMatchRefs);
                    }
                }
            }
        }
    }

    return isSearched;
}
