#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() ;
    //提示语为空时无需显示提示
    if(warningTips.isEmpty())
    {
        m_msgWidget->setVisible(false);
    }else //提示语不为空时显示提示
    {
        m_msgWidget->setVisible(true);
        m_appTipsWidget->updateTips(warningTips);
    }

    // 云端模型
    m_publicCloudFrame = new QFrame;
    m_publicCloudFrame->setAccessibleName("kylin-ai-subsystem-modelconfig_QFrame_m_publicCloudFrame");
    m_publicCloudFrame->setMinimumSize(QSize(495, 56));
    m_publicCloudFrame->setMaximumSize(QSize(16777215, 56));
    m_publicCloudFrame->setFrameShape(QFrame::Box);
    m_publicCloudFrame->setContentsMargins(0, 0, 0, 0);

    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_publicCloudFrame);
    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");

    QHBoxLayout *publicCloudHLayout = new QHBoxLayout(m_publicCloudFrame);
    publicCloudHLayout->setContentsMargins(0, 0, 0, 0);
    publicCloudHLayout->setSpacing(0);
    publicCloudHLayout->addWidget(m_publicCloudModel);

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

    if (shouldShowLocalModel == true) {
        m_ondeviceFrame = new QFrame;
        m_ondeviceFrame->setAccessibleName("kylin-ai-subsystem-modelconfig_QFrame_m_ondeviceFrame");
        m_ondeviceFrame->setMinimumSize(QSize(495, 56));
        m_ondeviceFrame->setMaximumSize(QSize(16777215, 56));
        m_ondeviceFrame->setFrameShape(QFrame::Box);
        m_ondeviceFrame->setContentsMargins(0, 0, 0, 0);

        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_ondeviceFrame);
        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");

        QHBoxLayout *ondeviceHLayout = new QHBoxLayout(m_ondeviceFrame);
        ondeviceHLayout->setContentsMargins(0, 0, 0, 0);
        ondeviceHLayout->setSpacing(0);
        ondeviceHLayout->addWidget(m_ondeviceModel);
    }

    //自定义模型
    m_privateFrame = new QFrame;
    m_privateFrame->setMinimumSize(QSize(495,56));
    m_privateFrame->setMaximumSize(QSize(16777215, 56));
    m_privateFrame->setFrameShape(QFrame::Box);
    m_privateFrame->setContentsMargins(0, 0, 0, 0);

    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,m_privateFrame);
    // 设置父窗口为插件窗口类， 然后调用exec实现模态窗口
    g_privateModelConfigWidget = new PrivateModelConfigWidget(m_mainWidget);

    QHBoxLayout *privateHLayout = new QHBoxLayout(m_privateFrame);
    privateHLayout->setContentsMargins(0,0,0,0);
    privateHLayout->setSpacing(0);
    privateHLayout->addWidget(m_privateModel);

    m_modelVLayout = new QVBoxLayout();
    m_modelVLayout->setContentsMargins(0, 0, 0, 0);
    m_modelVLayout->setSpacing(4);
    m_modelVLayout->addWidget(m_publicCloudFrame);
    if (shouldShowLocalModel == true) {
        m_modelVLayout->addWidget(m_ondeviceFrame);
    }
    m_modelVLayout->addWidget(m_privateFrame);

    m_modelWidget = new QWidget;

    if (shouldShowLocalModel == true) {
        m_modelWidget->setFixedHeight(176);
    } else {
        m_modelWidget->setFixedHeight(116);
    }
    m_modelWidget->setLayout(m_modelVLayout);

    m_mainVLayout = new QVBoxLayout();
    m_mainVLayout->setContentsMargins(0, 0, 0, 0);
    m_mainVLayout->addWidget(m_modelConfigLabel);
    m_mainVLayout->addSpacing(0);
    m_mainVLayout->addWidget(m_msgWidget);
    m_mainVLayout->addWidget(m_modelWidget);
    m_mainVLayout->addStretch();

    m_mainWidget->setLayout(m_mainVLayout);

    initConnect();
    updateModelLayout();

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

    return m_mainWidget;
}

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

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, [=] {
        int index = m_modelVLayout->indexOf(m_publicCloudFrame);
        KyInfo() << "public index" << index;
        if (index > 0) { // 如果不是第一个，交换位置
            // 获取当前的优先级映射
            QMap<DeployType, int> priorityMap = getCurrentProrityMap();

            // 交换优先级值
            DeployType currentType = getDeployTypeByFrame(m_publicCloudFrame);
            DeployType previousType = getDeployTypeByFrame(static_cast<QFrame*>(m_modelVLayout->itemAt(index - 1)->widget()));

            int currentPriority = priorityMap[currentType];
            int previousPriority = priorityMap[previousType];
            priorityMap[currentType] = previousPriority;
            priorityMap[previousType] = currentPriority;

            // 更新 SDK 中的优先级
            updateModelPriority(priorityMap);

            updateModelLayout();
        }
    });

    // 本地模型
    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, [=] {
            int index = m_modelVLayout->indexOf(m_ondeviceFrame);
            KyInfo() << "ondevice index" << index;
            if (index > 0) {
                // 获取当前的优先级映射
                QMap<DeployType, int> priorityMap = getCurrentProrityMap();

                // 交换优先级值
                DeployType currentType = getDeployTypeByFrame(m_ondeviceFrame);
                DeployType previousType = getDeployTypeByFrame(static_cast<QFrame*>(m_modelVLayout->itemAt(index - 1)->widget()));

                int currentPriority = priorityMap[currentType];
                int previousPriority = priorityMap[previousType];
                priorityMap[currentType] = previousPriority;
                priorityMap[previousType] = currentPriority;

                // 更新 SDK 中的优先级
                updateModelPriority(priorityMap);

                updateModelLayout();
            }
        });
    }

    // 自定义模型
    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, [=] {
        int index = m_modelVLayout->indexOf(m_privateFrame);
        KyInfo() << "custom index" << index;
        if (index > 0) { // 如果不是第一个，交换位置
            // 获取当前的优先级映射
            QMap<DeployType, int> priorityMap = getCurrentProrityMap();

            // 交换优先级值
            DeployType currentType = getDeployTypeByFrame(m_privateFrame);
            DeployType previousType = getDeployTypeByFrame(static_cast<QFrame*>(m_modelVLayout->itemAt(index - 1)->widget()));

            int currentPriority = priorityMap[currentType];
            int previousPriority = priorityMap[previousType];
            priorityMap[currentType] = previousPriority;
            priorityMap[previousType] = currentPriority;

            // 更新 SDK 中的优先级
            updateModelPriority(priorityMap);

            updateModelLayout();
        }
    });
}

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::updateModelLayout()
{
    ModelConfig mc;
    int  publicCloudValue  = mc.getModelSchedulingPriority(DeployType::PublicCloud);
    int ondeviceValue = mc.getModelSchedulingPriority(DeployType::Ondevice);
    int customValue = mc.getModelSchedulingPriority(DeployType::Custom);

    bool shouldShowLocalModel = hasLocalModel();

    // 根据当前的优先级更新priorityMap
    m_priorityMap.clear();
    m_priorityMap.insert(DeployType::PublicCloud,publicCloudValue);
    KyInfo() << "publicCloud Priority" << publicCloudValue;

    if (shouldShowLocalModel == true) {
        m_priorityMap.insert(DeployType::Ondevice, ondeviceValue);
        KyInfo() << "ondevice Priority" << ondeviceValue;
    }

    m_priorityMap.insert(DeployType::Custom,customValue);
    KyInfo() << "custom Priority" << customValue;

    // 清空当前的布局
    while (m_modelVLayout->count() > 0) {
        QLayoutItem *item = m_modelVLayout->takeAt(0);
        if (item->widget()) {
            item->widget()->setParent(nullptr);
        }
        delete item;
    }

    // 按照优先级排序
    QList<QFrame *> frames;
    frames << m_publicCloudFrame;

    if (shouldShowLocalModel == true) {
        frames << m_ondeviceFrame;
    }

    frames << m_privateFrame;

    std::sort(frames.begin(), frames.end(), [this](QFrame *frame1, QFrame *frame2) {
        DeployType type1 = getDeployTypeByFrame(frame1);
        DeployType type2 = getDeployTypeByFrame(frame2);
        return m_priorityMap.value(type1) < m_priorityMap.value(type2);
    });

    for (QFrame *frame : frames) {
        m_modelVLayout->addWidget(frame);
    }

    // 更新按钮状态
    int index1 = m_modelVLayout->indexOf(m_publicCloudFrame);
        m_publicCloudModel->m_sortButton->setEnabled(index1 != 0);

    if (shouldShowLocalModel == true) {
        int index2 = m_modelVLayout->indexOf(m_ondeviceFrame);
        m_ondeviceModel->m_sortButton->setEnabled(index2 != 0);
    }

    int index3 = m_modelVLayout->indexOf(m_privateFrame);
    m_privateModel->m_sortButton->setEnabled(index3 != 0);

}

DeployType TestAiSubSystem::getDeployTypeByFrame(QFrame *frame)
{
    if (frame == m_publicCloudFrame) {
        return DeployType::PublicCloud;
    } else if (frame == m_ondeviceFrame) {
        return DeployType::Ondevice;
    } else if (frame == m_privateFrame) {
        return DeployType::Custom;
    }
    return DeployType::PublicCloud; // 默认返回云端模型
}

QMap<DeployType, int> TestAiSubSystem::getCurrentProrityMap()
{
    bool shouldShowLocalModel = hasLocalModel();

    int index1 = m_modelVLayout->indexOf(m_publicCloudFrame);
    int index3 = m_modelVLayout->indexOf(m_privateFrame);

    KyInfo() << "cloud index:" << index1;
    KyInfo() << "custom index:" << index3;

    // 根据当前的排序顺序设置优先级
    QMap<DeployType, int> priorityMap;

    if (shouldShowLocalModel == true) {
        int index2 = m_modelVLayout->indexOf(m_ondeviceFrame);
        KyInfo() << "ondevice index:" << index2;

        // 对云端、本地、自定义进行比较
        if (index1 < index2 && index1 < index3) {
            // 云端模型排第一
            priorityMap[DeployType::PublicCloud] = 1;
            if (index2 < index3) {
                // 本地模型排第二，自定义模型排第三
                priorityMap[DeployType::Ondevice] = 2;
                priorityMap[DeployType::Custom] = 3;
            } else {
                // 自定义模型排第二，本地模型排第三
                priorityMap[DeployType::Custom] = 2;
                priorityMap[DeployType::Ondevice] = 3;
            }
        } else if (index2 < index1 && index2 < index3) {
            // 本地模型排第一
            priorityMap[DeployType::Ondevice] = 1;
            if (index1 < index3) {
                // 云端模型排第二，自定义模型排第三
                priorityMap[DeployType::PublicCloud] = 2;
                priorityMap[DeployType::Custom] = 3;
            } else {
                // 自定义模型排第二，云端模型排第三
                priorityMap[DeployType::Custom] = 2;
                priorityMap[DeployType::PublicCloud] = 3;
            }
        } else {
            // 自定义模型排第一
            priorityMap[DeployType::Custom] = 1;
            if (index1 < index2) {
                // 云端模型排第二，本地模型排第三
                priorityMap[DeployType::PublicCloud] = 2;
                priorityMap[DeployType::Ondevice] = 3;
            } else {
                // 本地模型排第二，云端模型排第三
                priorityMap[DeployType::Ondevice] = 2;
                priorityMap[DeployType::PublicCloud] = 3;
            }
        }

    } else {
        // 只需考虑对云端和自定义进行比较
        if (index1 < index3) {
            priorityMap[DeployType::PublicCloud] = 1;
            priorityMap[DeployType::Custom] = 2;
        } else {
            priorityMap[DeployType::Custom] = 1;
            priorityMap[DeployType::PublicCloud] = 2;
        }
        // 始终设置本地优先级为-1
        priorityMap[DeployType::Ondevice] = -1;
    }

    return priorityMap;
}

void TestAiSubSystem::showErrorMessage(const QString &message, QWidget *parent)
{
    QMessageBox msgBox(parent);
    msgBox.setIcon(QMessageBox::Question);
    msgBox.setText(message);

    QPushButton *cancelButton = msgBox.addButton(tr("Cancel"), QMessageBox::RejectRole);
    QPushButton *sureButton = msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
    msgBox.setDefaultButton(sureButton);
    msgBox.exec();
}

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