/*
 * Copyright (C) 2020, 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 "kaglobal.h"

#include <QStyleOption>
#include <QStyle>
#include <QBitmap>
#include <QPalette>
#include <QPainter>
#include <QDebug>
#include <QMap>
#include <QJsonObject>

bool isSettingOpen = false;
bool isTextAreaFocus = false;           // 输入框是否激活
bool isSpeechSynthesizing = false;      // 是否正在合成语音
bool isWayland = false;
bool isMinimizeClicked = false;         // 记录最小化按钮是否点击

PageType g_currentPage = PageType::MAIN_PAGE_SIDEBAR_MODE; // 当前页面，默认值为侧边栏模式下主页面

int Globals::themeColor = 0; // 0:为浅色 1:为深色 2:自由模式
float Globals::fontSize = g_ukuiGettings->get("system-font-size").toFloat();
QUrl Globals::openLink = QUrl(QString("https://docs.openkylin.top/zh/07_%E5%85%B3%E4%BA%8E%E7%A4%BE%E5%8C%BA/"
                                      "%E7%A4%BE%E5%8C%BA%E5%B9%B3%E5%8F%B0%E4%BB%8B%E7%BB%8D/AI%E6%A8%A1%E5%9E%8B%E8%B4%A6%E5%8F%B7%E8%8E%B7%E5%8F%96%E5%8F%8A%E9%85%8D%E7%BD%AE%E6%8C%87%E5%8D%97"));
double Globals::scaleFactor = 1.0; // 屏幕缩放比
QString Globals::defaultPath = "";
QString Globals::sysMajorVersion = getCurrentSysVersion();
Globals * Globals::m_global = nullptr;
void Globals::borderRound(QWidget *widget,int xradius,int yradius){
    if(widget){
        QStyleOption opt;
        opt.initFrom(widget);
        QPainter p(widget);
        widget->style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, widget);//绘制样式

        QBitmap bmp(widget->size());
        bmp.fill();
        QPainter painter(&bmp);
        painter.setPen(Qt::NoPen);
        painter.setBrush(Qt::black);
        painter.setRenderHint(QPainter::Antialiasing);

        //此处可修改圆角矩形大小，也可以绘制为其他想要的形状，比如圆形
        painter.drawRoundedRect(bmp.rect(), xradius, yradius);
        //该函数便使得QBitmap上像素为1的区域才显示出来
        widget->setMask(bmp);
    }
}

Globals::Globals(QObject *parent)
{

}

Globals *Globals::getinstance()
{
    if (m_global == nullptr){
        m_global = new Globals;
    }

    return m_global;
}

void Globals::borderColor(QWidget *widget, int xradius, int yradius, QColor borderColor) {
    if (widget) {
        QStyleOption opt;
        opt.initFrom(widget);
        QPainter p(widget);
        widget->style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, widget);//绘制样式

        QBitmap bmp(widget->size());
        bmp.fill();
        QPainter painter(&bmp);
        painter.setPen(Qt::NoPen);
        painter.setBrush(Qt::black);
        painter.setRenderHint(QPainter::Antialiasing);

        //此处可修改圆角矩形大小，也可以绘制为其他想要的形状，比如圆形
        painter.drawRoundedRect(bmp.rect(), xradius, yradius);
        //该函数便使得QBitmap上像素为1的区域才显示出来
        widget->setMask(bmp);
        //绘制外边框
        QPainter borderPainter(widget);
        borderPainter.setRenderHint(QPainter::Antialiasing);
        borderPainter.setPen(QPen(borderColor, 1));
        borderPainter.drawRoundedRect(widget->rect().adjusted(1, 1, -1, -1), xradius, yradius);
    }
}

QString Globals::getErrorMsg(int errorCode)
{
    QString errorMsg;
    kyai::assistant::ErrorCode error = static_cast<kyai::assistant::ErrorCode>(errorCode);
    switch(error)
    {
    case kyai::assistant::ErrorCode::Ok:
        break;
    case kyai::assistant::ErrorCode::NetError:
        KyInfo() << "网络设置错误。";
        errorMsg = QObject::tr("Network connection is unavailable. Please check your network settings and try again. If using a custom model, ensure the request address is correct.");
        break;
    case kyai::assistant::ErrorCode::ServerError:
        KyInfo() << "AI服务错误。";
        errorMsg = QObject::tr("The current service is unavailable. Please restart the system and try again.");
        break;
    case kyai::assistant::ErrorCode::UnAuthorized:
        KyInfo() << "权限限制，鉴权失败，无权访问。";
        errorMsg = QObject::tr("Authentication error. Check whether the model account configuration information is incorrect.");
        break;
    case kyai::assistant::ErrorCode::RequestTooMany:
        KyInfo() << "请求频率过高。";
        errorMsg = QObject::tr("Network connection abnormality, possible causes as follows:")
                   + "\n\n"
                   + QObject::tr("1. Model trial account, usage is restricted.")
                   + "\n\n"
                   + QObject::tr("2. The same model account logs in to multiple devices, resulting in excessively frequent requests.");
        break;
    case kyai::assistant::ErrorCode::RequestFailed:
        KyInfo() << "请求失败。";
        errorMsg = QObject::tr("The request failed, please resend it.");
        break;
    case kyai::assistant::ErrorCode::InputTextLengthInvaild:
        KyInfo() << "输入文本长度超限。";
        errorMsg = QObject::tr("If the length of the input text is exceeded, please re-edit the text before sending.");
        break;
    case kyai::assistant::ErrorCode::TaskTimeout:
        KyInfo() << "任务超时错误。";
        errorMsg = QObject::tr("The task times out, please resend it.");
        break;
    case kyai::assistant::ErrorCode::GenerateImageFailed:
        KyInfo() << "生成图片失败";
        errorMsg = QObject::tr("Failed to generate image, please resend it.");
        break;
    case kyai::assistant::ErrorCode::GenerateImageBlocked:
        KyInfo() << "生成图片阻塞";
        errorMsg = QObject::tr("The image was not approved due to content. Please adjust the prompt and try again.");
        break;
    case kyai::assistant::ErrorCode::ParamError:
        KyInfo() << "参数错误";
        errorMsg = QObject::tr("If the parameter is incorrect, check the configuration parameters.");
        break;
    case kyai::assistant::ErrorCode::InputTextInvaild:
        KyInfo() << "输入文本无效";
        errorMsg = QObject::tr("The input text is invalid, please modify it and resend it.");
        break;
    case kyai::assistant::ErrorCode::FileNotFound:
        KyInfo() << "文件未找到";
        errorMsg = QObject::tr("The input file is invalid, please confirm the location of the file and resend it.");
        break;
    case kyai::assistant::ErrorCode::IntentServerError:
        KyInfo() << "初始化意图模型失败";
        errorMsg = QObject::tr("Initializing the intent model failed, check the model configuration.");
        break;
    case kyai::assistant::ErrorCode::NlpServerError:
        KyInfo() << "NLP服务错误";
        errorMsg = QObject::tr("Failed to initialize the large language model, check the model configuration.");
        break;
    case kyai::assistant::ErrorCode::VisionServerError:
        KyInfo() << "VISION服务错误";
        errorMsg = QObject::tr("Initializing the vision model failed, please check the model configuration.");
        break;
   case kyai::assistant::ErrorCode::InputTextBlocked:
       KyInfo() << "输入错误";
       errorMsg = QObject::tr("If the input content has not passed the review and is suspected of violating the rules, please adjust it and try again.");
       break;
   case kyai::assistant::ErrorCode::OutputTextBlocked:
       KyInfo() << "输出错误";
       errorMsg = QObject::tr("The output content has not been approved, contains sensitive information, and the results cannot be displayed.");
       break;
    case kyai::assistant::ErrorCode::UnknownError:
        KyInfo() << "未知错误";
        errorMsg = QObject::tr("Unknown error, please restart the service or application.");
        break;
    case kyai::assistant::ErrorCode::SystemOperationFailed:
        KyInfo() << "系统操作失败！";
        errorMsg = QObject::tr("The system operation failed to complete. The problem may be due to insufficient model recognition ability or incorrect configuration of the end side model environment. We have listed model performance as an urgent optimization task. Meanwhile, please assist in checking the local configuration environment. Thank you for your cooperation.");
        break;
    case kyai::assistant::ErrorCode::IntentionRecognitionFailed:
        KyInfo() << "意图识别失败";
        errorMsg = QObject::tr("Your request is not recognized, please make sure your entry is clear and accurate.");
        break;
    case kyai::assistant::ErrorCode::NlpModelNotFound:
        KyInfo() << "NLP 模型未配置";
        break;
    case kyai::assistant::ErrorCode::VisionModelNotFound:
        KyInfo() << "视图模型未配置";
        break;
    case kyai::assistant::ErrorCode::FileExceedSizeLimit:
        KyInfo() << "文档过大";
        errorMsg = QObject::tr("The current file exceeds the processing limit (around 20000 words), please reduce the content appropriately and try again.");
        break;
    case kyai::assistant::ErrorCode::FileParseFailed:
        KyInfo() << "文档内容错误，空文档、纯图片文档或加密文档";
        errorMsg = QObject::tr("Unable to process the file. The file type is not supported or the content cannot be parsed.");
        break;
    case kyai::assistant::ErrorCode::CreateScheduleFailed:
        KyInfo() << "新建日程失败";
        errorMsg = QObject::tr("Sorry, I am unable to add a schedule for you as you have not provided information such as a start time, or the information can not be recognized. To successfully add a schedule, please ensure that you provide clear and accurate dates and times.");
        break;
    case kyai::assistant::ErrorCode::CreateToDoListFailed:
        KyInfo() << "生成待办失败";
        errorMsg = QObject::tr("Sorry, I am unable to create a to-do for you as you have not provided information such as a start time, or the information can not be recognized. To successfully create a to-do, please ensure that you provide clear and accurate dates and times.");
        break;
    case kyai::assistant::ErrorCode::FreeAllocatedQuotaExceeded:
        KyInfo() << "免费额度已使用完,对话次数已达上限";
        errorMsg = QObject::tr("Your free trial quota has been exhausted.");
        break;
    case kyai::assistant::ErrorCode::LocalNlpModelNotLoaded:
        KyInfo() << "当前本地模型不可用";
        errorMsg = QObject::tr("The current local model is not available.");
        break;
    case kyai::assistant::ErrorCode::SslCertificateError:
        KyInfo() << "请求时间验证失败，请检查系统时间设置或尝试更换模型后重试。";
        errorMsg = QObject::tr("Network abnormalities may be caused by the following reasons:")
                   + "\n\n"
                   + QObject::tr("1. Request time validation failed, please check the system time settings or try changing the model and retry.")
                   + "\n\n"
                   + QObject::tr("2. The network is not authenticated, please try network authentication or contact IT.");
        break;
    default:
        errorMsg = QObject::tr("Undefined error, returned.");
        break;
    }
    return errorMsg;
}

QString Globals::getErrorMsg(SpeechErrorCode errorCode)
{
    QString errorMsg;
    switch (errorCode) {
    case AISDK_NO_ERROR://0
        errorMsg = "";
        break;
    case AISDK_NET_ERROR://1
        errorMsg = QObject::tr("The network connection is not available, please check the network settings and try again.");
        break;
    case AISDK_AUTHENTICATION_FAILURE://2
        errorMsg = QObject::tr("Authentication error. Check whether the model account configuration information is incorrect.");
        KyInfo() << errorMsg;
        break;
    case AISDK_RUNTIME_ERROR://3
        errorMsg = QObject::tr("Runtime error, please restart the service or system and try again.");
        break;
    case AISDK_TOO_MANY_REQUESTS://4
        errorMsg = QObject::tr("Network connection abnormality, possible causes as follows:")
                   + "\n\n"
                   + QObject::tr("1. Model trial account, usage is restricted.")
                   + "\n\n"
                   + QObject::tr("2. The same model account logs in to multiple devices, resulting in excessively frequent requests.");
        break;
    case AISDK_SERVICE_ERROR://5
        errorMsg = QObject::tr("Cloud service error. The current request cannot be completed, check whether the service status is normal and try again.");
        break;
    case AISDK_SERVICE_TIMEOUT://6
        errorMsg = QObject::tr("The service response timed out. The request was not completed in time, please try again.");
        break;
    case AISDK_BAD_REQUEST://7
        errorMsg = QObject::tr("The request parameter or format is incorrect. Check that the parameters are formatted correctly and resubmit the request.");
        break;
    case AISDK_MODEL_RUN_FAILED://8
        errorMsg = QObject::tr("If the local model fails to run and the request cannot be completed, check the model configuration and try again.");
        break;
    case AISDK_MODEL_RUN_TIME_OUT://9
        errorMsg = QObject::tr("The local model ran timed out, please try again later.");
        break;
    case AISDK_MODEL_NOT_FOUND://10
        KyInfo() << "语音类模型未配置";
        break;
    case AISDK_SSL_CERTIFICATE_ERROR://12
        errorMsg = QObject::tr("Network abnormalities may be caused by the following reasons:")
                   + "\n\n"
                   + QObject::tr("1. Request time validation failed, please check the system time settings or try changing the model and retry.")
                   + "\n\n"
                   + QObject::tr("2. The network is not authenticated, please try network authentication or contact IT.");
        KyInfo() << "SSL证书错误，请求时间验证失败";
        break;
    case SPEECH_RECOGNITION_AUDIO_DATA_SIZE_INVALID://100
        errorMsg = QObject::tr("If the length of the speech recognition audio is too short or too long, please extend or shorten the audio length and submit it again.");
        break;
    case SPEECH_SYNTHESIS_TEXT_LENGTH_INVALID://101
        errorMsg = QObject::tr("If the text length of the speech synthesis text is too long, please send or shorten the text in parts and try again.");
        break;
    case SPEECH_PARAM_INVALID://102
        errorMsg = QObject::tr("The voice model configuration is invalid, check whether the model configuration information is incorrect.");
        break;  
    case SPEECH_DEFAULT_MICROPHONE_INVALID://103
        errorMsg = QObject::tr("The microphone was not detected, please connect the device and try again.");
        break;
    case SPEECH_UNKNOWN_ERROR: //104
        errorMsg = QObject::tr("An unknown error has occurred, please try again later.");
        break;
    case SPEECH_UNSUPPORTED_LANGUAGE://105
        errorMsg = QObject::tr("This language is not supported at this time. Please try a different language.");
        break;
    default:
        errorMsg = QObject::tr("Undefined error, returned");
        break;
    }
    KyInfo() << errorMsg;
    return errorMsg;
}

//对比版本号，if A >= B return true else return false
static bool compareVersion(const QString &cur, const QString target){
    int length = fmin(cur.length(), target.length());
    int i = 0;
    while(i != length){
        if(cur[i] == target[i]){
            ++ i;
            continue;
        }
        int j = i;
        QString v1, v2;
        while(j < cur.length() && cur[j] != '.' && cur[j].isDigit())
            v1.append(cur[j ++]);
        j = i;
        while(j < target.length() && target[j] != '.'&& target[j].isDigit())
            v2.append(target[j ++]);
        if(v1.toInt() >= v2.toInt())
            return true;
        else
            return false;
    }
    if(cur.length() >= target.length())
        return true;
    else
        return false;
}

QString Globals::getCurrentSysVersion()
{
    const char  *sysMajorVersion =  kdk_system_get_major_version();
    return QString::fromUtf8(sysMajorVersion);
}

QString Globals::getFileIconName(QString filePath)
{
    QMimeDatabase db;
    QMimeType mimeType = db.mimeTypeForFile(filePath);

    return mimeType.iconName();
}
