/*
 * Copyright 2025 KylinSoft Co., Ltd.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */

#include "aisubsystem.h"

#include <QLabel>
#include <QTranslator>
#include <QCoreApplication>
#include <QFileInfo>
#include <QDir>
#include <QLibraryInfo>
#include <QString>
#include <QStringList>
#include <ukui-log4qt.h>
#include <kysdk/applications/klistwidget.h>
#include <kysdk/applications/kmessagebox.h>
#include <QtCore/qprocessordetection.h>


static CloudModelConfigWidget *g_cloudModelConfigPage = nullptr;

static LocalModelConfigWidget *g_localModelConfigWidget = nullptr;

static PrivateModelConfigWidget *g_privateModelConfigWidget = nullptr;


TestAiSubSystem::TestAiSubSystem(QObject *parent) : QObject(parent)
{

}

CloudModelConfigWidget* TestAiSubSystem::getCloudModelConfigPage()
{
    return g_cloudModelConfigPage;
}

LocalModelConfigWidget *TestAiSubSystem::getLocalModelConfigPage()
{
    return g_localModelConfigWidget;
}

PrivateModelConfigWidget *TestAiSubSystem::getPrivateModelConfigPage()
{
    return g_privateModelConfigWidget;
}

QStringList translationsPaths() {
    QString binaryPath = QFileInfo(qApp->applicationDirPath()).absoluteFilePath();

    QString trPath = QDir::toNativeSeparators(binaryPath + "/translations") ;
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
    return QStringList()
            << QStringLiteral(APP_PREFIX) + "/share/kylin-ai-subsystem-plugin/kylin-ai-subsystem-modelconfig/translations"
            << trPath
            << QStringLiteral("/usr/share/kylin-ai-subsystem-plugin/kylin-ai-subsystem-modelconfig/translations")
            << QStringLiteral("/usr/local/share/kylin-ai-subsystem-plugin/kylin-ai-subsystem-modelconfig/translations");
#elif defined(Q_OS_WIN)
    return QStringList()
            << trPath;
#endif
}

QWidget* TestAiSubSystem::createModelConfigWidget() {

    initUkuiLog4qt("ukui-control-center");

    // 日志输出在 ~/.log/ukui-control-center.log
    KyInfo() << "Init AI model config.";

    m_translator = new QTranslator;
    QStringList trPaths = translationsPaths();

    for (const QString &path: trPaths) {
        KyInfo() << "binaryPath" << path;
        bool match = m_translator->load(QLocale(),
                                     QStringLiteral("Internationalization"), QStringLiteral(
                                         "_"),
                                     path);
        if (match) {
            break;
        }
    }

    QCoreApplication::installTranslator(m_translator);

    m_mainWidget = new QWidget();
    m_mainWidget->setAccessibleName("kylin-ai-subsystem-modelconfig_QWidget_m_mainWidget");
    m_mainWidget->setContentsMargins(0, 0, 0, 0);

    // 模型配置
    m_modelConfigLabel = new QLabel(m_mainWidget);
    m_modelConfigLabel->setAccessibleName("kylin-ai-subsystem-modelconfig_QLabel_m_modelConfigLabel");
    m_modelConfigLabel->setContentsMargins(16, 8, 0, 8);
    m_modelConfigLabel->setText(tr("Model Configuration"));

    // 检查AI应用是否符合版本要求
    m_tipsFrame = new QFrame;
    m_tipsFrame->setAccessibleName("kylin-ai-subsystem-modelconfig_QFrame_m_tipsFrame");
    m_tipsFrame->setMinimumSize(QSize(495, 56));
    m_tipsFrame->setMaximumSize(QSize(16777215, 56));
    m_tipsFrame->setFrameShape(QFrame::Box);
    m_tipsFrame->setContentsMargins(0, 0, 0, 0);
    m_appTipsWidget =  new AppVersionErrorWarningWidget(m_mainWidget);
    m_appTipsWidget->setFixedHeight(56);
    m_appTipsWidget->setMinimumSize(QSize(495,56));
    m_appTipsWidget->setMaximumSize(QSize(16777215, 56));
    QHBoxLayout *tipsHLayout = new QHBoxLayout(m_tipsFrame);
    tipsHLayout->setContentsMargins(0, 0, 0, 0);
    tipsHLayout->setSpacing(0);
    tipsHLayout->addWidget(m_appTipsWidget);

    m_msgWidget = new QWidget(m_mainWidget);
    m_msgWidget->setFixedHeight(56);
    m_msgWidget->setMinimumSize(QSize(495,56));
    m_msgWidget->setMaximumSize(QSize(16777215, 56));
    m_msgWidget->setStyleSheet("background:rgba(255, 125, 0, 0.1);border-radius:6px;");
    m_msgWidget->setLayout(tipsHLayout);
    QString warningTips = ModelDownload::getInstance()->isAppversionNeedUpdate() ;

    //提示语为空时无需显示提示
    //v11版本麒麟速记、助手与子系统没有版本兼容问题,不需要显示提示
    if(warningTips.isEmpty() || curSystemVersion() == SystemVersion::Version_V11) {
        m_msgWidget->setVisible(false);
    } else {
        m_msgWidget->setVisible(true);
        m_appTipsWidget->updateTips(warningTips);
    }

    // 云端模型
    m_publicCloudModel = new ModelWidget(
        tr("Cloud Model (Kylin Certification)"),
        tr("Configure cloud models certified by Kylin (Deployed on the cloud server, access and use over the network)"),
        DeployType::PublicCloud);
    m_publicCloudModel->setAccessibleName("kylin-ai-subsystem-modelconfig_ModelWidget_m_publicCloudModel");
    // 设置父窗口为插件窗口类，然后调用exec实现模态窗口
    g_cloudModelConfigPage = new CloudModelConfigWidget(m_mainWidget);
    g_cloudModelConfigPage->setAccessibleName("kylin-ai-subsystem-modelconfig_CloudModelConfigWidget_g_cloudModelConfigPage");


    // 本地模型
    bool shouldShowLocalModel = hasLocalModel();

    if (shouldShowLocalModel == true) {
        m_ondeviceModel = new ModelWidget(
            tr("Local Model (Kylin Certification)"),
            tr("Configure a local model certified by Kylin (Installed on local equipment, it can run without network)"),
            DeployType::Ondevice);
        m_ondeviceModel->setAccessibleName("kylin-ai-subsystem-modelconfig_ModelWidget_m_ondeviceModel");
        // 设置父窗口为插件窗口类，然后调用exec实现模态窗口
        g_localModelConfigWidget = new LocalModelConfigWidget(m_mainWidget);
        g_localModelConfigWidget->setAccessibleName("kylin-ai-subsystem-modelconfig_LocalModelConfigWidget_g_localModelConfigWidget");
    }

    //自定义模型
    m_privateModel = new ModelWidget(
        tr("Custom Model"),
        tr("Configure local model files, LAN, and public cloud model configurations without "
           "Kylin authentication (we apologize for any inconvenience causeds.)"),
        DeployType::Custom);
    // 设置父窗口为插件窗口类， 然后调用exec实现模态窗口
    g_privateModelConfigWidget = new PrivateModelConfigWidget(m_mainWidget);


    m_modelGroup = new KBackgroundGroup;
    m_modelGroup->setMinimumWidth(495);
    m_modelGroup->setMaximumWidth(16777215);

    // 模型调度优先级
    m_modelCallPriorityFrame = new QFrame();
    m_modelCallPriorityFrame->setMinimumSize(QSize(495, 60));
    m_modelCallPriorityFrame->setMaximumSize(QSize(16777215, 60));
    m_modelCallPriorityFrame->setFrameShape(QFrame::Box);
    m_modelCallPriorityFrame->setAccessibleName("kylin-ai-subsystem-modelconfig_QFrame_modelCallPriorityFrame");
    m_modelCallPriorityWidget = new ModelCallPriority(hasLocalModel(), m_modelCallPriorityFrame);


    m_mainVLayout = new QVBoxLayout();
    m_mainVLayout->setContentsMargins(0, 0, 0, 0);
    m_mainVLayout->setSpacing(0);

    m_mainVLayout->addWidget(m_modelConfigLabel);
    m_mainVLayout->addWidget(m_msgWidget);
    m_mainVLayout->addWidget(m_modelGroup);
    m_mainVLayout->addSpacing(8);
    m_mainVLayout->addWidget(m_modelCallPriorityFrame);
    m_mainVLayout->addStretch();

    m_mainWidget->setLayout(m_mainVLayout);

    initConnect();
    initModelGroup();

    KyInfo() << "End AI model config.";

    return m_mainWidget;
}

QWidget* TestAiSubSystem::createComputePowerSharingWidget()
{
    return nullptr;
}

void TestAiSubSystem::initModelGroup() {
    ModelConfig mc;
    int publicCloudValue  = mc.getModelSchedulingPriority(DeployType::PublicCloud);
    int ondeviceValue = mc.getModelSchedulingPriority(DeployType::Ondevice);
    int customValue = mc.getModelSchedulingPriority(DeployType::Custom);

    m_modelPriorityList.clear();
    m_modelPriorityList.append({publicCloudValue, DeployType::PublicCloud, m_publicCloudModel});
    if (hasLocalModel()) {
        m_modelPriorityList.append({ondeviceValue, DeployType::Ondevice, m_ondeviceModel});
    }
    m_modelPriorityList.append({customValue, DeployType::Custom, m_privateModel});

    sortItemsByPriority();
    updateUIOrder();
}

void TestAiSubSystem::initConnect()
{
    // 云端模型
    connect(m_publicCloudModel, &ModelWidget::configClicked, this, [=]{
        //重新初始化云端模型对话框界面
        g_cloudModelConfigPage->deleteLater();
        g_cloudModelConfigPage = nullptr;
        g_cloudModelConfigPage = new CloudModelConfigWidget(m_mainWidget);
        g_cloudModelConfigPage->setAccessibleName("kylin-ai-subsystem-modelconfig_CloudModelConfigWidget_g_cloudModelConfigPage");
        g_cloudModelConfigPage->showCentered();
        TestAiSubSystem::getCloudModelConfigPage()->exec();
    });

    connect(m_publicCloudModel, &ModelWidget::sortClicked, this, [=] {
        moveItemUp(DeployType::PublicCloud);
    });

    // 本地模型
    if (hasLocalModel() == true) {
        connect(m_ondeviceModel, &ModelWidget::configClicked, this, [=]{
            //重新初始化本地模型对话框界面
            g_localModelConfigWidget->deleteLater();
            g_localModelConfigWidget = nullptr;
            g_localModelConfigWidget = new LocalModelConfigWidget(m_mainWidget);
            g_localModelConfigWidget->setAccessibleName("kylin-ai-subsystem-modelconfig_LocalModelConfigWidget_g_localModelConfigWidget");
            g_localModelConfigWidget->showCentered();
            TestAiSubSystem::getLocalModelConfigPage()->exec();
        });

        connect(m_ondeviceModel, &ModelWidget::sortClicked, this, [=] {
           moveItemUp(DeployType::Ondevice);
        });
    }

    // 自定义模型
    connect(m_privateModel,&ModelWidget::configClicked,this, [=]{
        //重新初始化自定义模型对话框界面
        g_privateModelConfigWidget->deleteLater();
        g_privateModelConfigWidget = nullptr;
        g_privateModelConfigWidget = new PrivateModelConfigWidget(m_mainWidget);
        g_privateModelConfigWidget->showCentered();
        TestAiSubSystem::getPrivateModelConfigPage()->exec();
    });

    connect(m_privateModel, &ModelWidget::sortClicked, this, [=] {
        moveItemUp(DeployType::PrivateCloud);
    });

    connect(m_modelCallPriorityWidget, &ModelCallPriority::topModelPriorityChanged,
            this, &TestAiSubSystem::onModelPriorityChanged);
}

void TestAiSubSystem::moveItemUp(DeployType deployType) {
    int currentIndex = -1;
    for (int i = 0; i < m_modelPriorityList.size(); i++) {
        if (m_modelPriorityList[i].deployType == deployType) {
            currentIndex = i;
            break;
        }
    }
    if (currentIndex > 0) {
        // 交换优先级值
        std::swap(m_modelPriorityList[currentIndex].priority, m_modelPriorityList[currentIndex-1].priority);
        // 重新排序
        sortItemsByPriority();
        // 更新UI
        updateUIOrder();
        saveModelPriority();
    }
}

void TestAiSubSystem::updateUIOrder() {
    QList<QWidget*> modelUIList;
    bool isFirstItem = true;
    for (const PriorityItem &item : m_modelPriorityList) {
        if (isFirstItem) {
            // 更新按钮状态
            item.modelWidget->m_sortButton->setEnabled(false);
            // 更新模型调度优先级
            m_modelCallPriorityWidget->setModelCallPriority(item.deployType);
            isFirstItem = false;
        } else {
            item.modelWidget->m_sortButton->setEnabled(true);
        }
        modelUIList.append(item.modelWidget);
    }
    m_modelGroup->removeWidgetList(m_modelGroup->widgetList());
    m_modelGroup->addWidgetList(modelUIList);
}

void TestAiSubSystem::onModelPriorityChanged(DeployType topPriorityModelType) {
    PriorityItem itemToMove;
    int index = -1;
    for (int i = 0; i < m_modelPriorityList.size(); i++) {
        if (m_modelPriorityList[i].deployType == topPriorityModelType) {
            itemToMove = m_modelPriorityList[i];
            index = i;
            break;
        }
    }
    if (index <= 0 || index >= m_modelPriorityList.size()) {
        return;
    }
    for (int i = index; i > 0; i--) {
        m_modelPriorityList[i] = m_modelPriorityList[i-1];
        m_modelPriorityList[i].priority++; // 优先级递增
    }

    itemToMove.priority = 1;
    m_modelPriorityList[0] = itemToMove;

    // 更新UI
    updateUIOrder();
    saveModelPriority();
}

void TestAiSubSystem::saveModelPriority() {
    QMap<DeployType, int> priorityMap;
    for (const PriorityItem &item : m_modelPriorityList) {
        priorityMap.insert(item.deployType, item.priority);
    }
    updateModelPriority(priorityMap);
}

void TestAiSubSystem::updateModelPriority(const QMap<DeployType, int> &priorityMap)
{
    bool ret = false;
    bool shouldShowLocalModel = hasLocalModel();

    // 遍历 priorityMap，设置每个模型的优先级
    for (auto it = priorityMap.begin(); it != priorityMap.end(); ++it) {
        DeployType type = it.key();
        int priority = it.value();

        // 如果本地模型隐藏，则跳过
        if (shouldShowLocalModel == false && type == DeployType::Ondevice) {
            continue;
        }

        ModelConfig mc;
        ret = mc.setModelSchedulingPriority(type, priority);
        if (ret == false) {
            switch (type) {
                case DeployType::PublicCloud:
                    KyInfo() << "Failed to set the call priority for DeployType: PublicCloud with priority:" << priority;
                    showErrorMessage(tr("Failed to set cloud model priority"),m_mainWidget);
                    break;
                case DeployType::Ondevice:
                    if (shouldShowLocalModel == true) {
                        KyInfo() << "Failed to set the call priority for DeployType: Ondevice with priority:" << priority;
                        showErrorMessage(tr("Failed to set local model priority"),m_mainWidget);
                    }
                    break;
                case DeployType::Custom:
                    KyInfo() << "Failed to set the call priority for DeployType: Custom with priority:" << priority;
                    showErrorMessage(tr("Failed to set custom model priority"),m_mainWidget);
                    break;
                default:
                    KyInfo() << "Unknown DeployType";
                    break;
            }
        } else {
            // 设置成功
            switch (type) {
                case DeployType::PublicCloud:
                    KyInfo() << "Successfully set the call priority for DeployType: PublicCloud with priority:" << priority;
                    break;
                case DeployType::Ondevice:
                    if (shouldShowLocalModel == true) {
                        KyInfo() << "Successfully set the call priority for DeployType: Ondevice with priority:" << priority;
                    }
                    break;
                case DeployType::Custom:
                    KyInfo() << "Successfully set the call priority for DeployType: Custom with priority:" << priority;
                    break;
                default:
                    KyInfo() << "Successfully set the call priority for Unknown DeployType with priority:" << priority;
                    break;
            }
        }
    }
}

void TestAiSubSystem::sortItemsByPriority() {
    std::sort(m_modelPriorityList.begin(), m_modelPriorityList.end(),
              [](const PriorityItem& a, const PriorityItem& b) {
        return a.priority < b.priority;
    });
}

bool TestAiSubSystem::hasLocalModel()
{
#if (defined(Q_PROCESSOR_X86) || (defined(Q_PROCESSOR_ARM)))
    return true;
#else
    return false;
#endif
}
