/*
 * 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 "msgpane.h"
#include "cpushbuttonex.h"
#include "global/kaglobal.h"
#include "tipwidget.h"
#include "commandtemplatelist.h"

#include <QDBusConnection>
#include <QFileDialog>
#include <QFileSystemWatcher>
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QMap>
#include <QMessageBox>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QStandardPaths>
#include <QThread>
#include <QVBoxLayout>
#include <QVariant>
#include <QSessionManager>
#include <ukui-log4qt.h>
#include <ukuistylehelper/ukuistylehelper.h>

#include <kmessagebox.h>
#include <QClipboard>
#include <QDesktopServices>
#include <QDBusUnixFileDescriptor>
#include <stdio.h>
#include <QTextDocumentWriter>
#include <aiconfig/modelconfig.h>
#include <QTextDocument>
#include <QRegularExpression>

using namespace kyai::config::model;

CMsgPane::CMsgPane()
{
    createAllChildWnd();
    initChatOperator();
    initSolts();
    initCommandList();


}

void CMsgPane::createAllChildWnd()
{
    m_reader = new Reader();
    m_recorder = new Recorder();
    m_database = ChatDatabase::getChatDatabase();
}

void CMsgPane::initSolts()
{
    connect(m_reader, &Reader::sigReadEnd, this, &CMsgPane::onReadEnd);
    connect(m_reader, &Reader::reply, this, &CMsgPane::onAudioRecvMsg);
    connect(m_reader, &Reader::sigResetPreIndex, [this](){
        Q_EMIT sigResetPreIndex();
    });

    connect(m_recorder, &Recorder::sigSendTmpMsg, [this](const QString str) {
        Q_EMIT sigSendTmpMsgToQML(str);
    });
    connect(m_recorder, &Recorder::sigSendMsg, [this](const QString str) {
        Q_EMIT sigSendMsgToQML(str);
    });
    connect(m_recorder, &Recorder::reply, this, &CMsgPane::onAudioRecvMsg);
    connect(m_recorder, &Recorder::sigCancelSendVoice, this, &CMsgPane::onCancelAudio);
    connect(m_recorder, &Recorder::sigIsStartTimer, this, &CMsgPane::onStartTimer);



    //文生图
    connect(m_chat, &SystemChat::sigPictureUpdate, this, &CMsgPane::updateToShowPic);

    //图像处理
    connect(m_chat, &SystemChat::pictureOperateUpdate, this, &CMsgPane::updateToShowOperatePic);

    //系统助手-信息来源
    connect(m_chat, &SystemChat::sigInfoSourceUpdate, this, &CMsgPane::updateToShowSource);

    //数据埋点
    //connect(m_channelMsg, &ChannelMessage::sigSendDataCollect, this, &CMsgPane::onSendDataCollect);

    //配置界面
    //connect(m_channelMsg, &ChannelMessage::sigShowSettingPage, [this]() {
    //    Q_EMIT sigSetup();
    //});

    qint64 uid = static_cast<qint64>(getuid());
    QDBusInterface iface("org.freedesktop.Accounts", "/org/freedesktop/Accounts", "org.freedesktop.Accounts", QDBusConnection::systemBus());
    QDBusReply<QDBusObjectPath> objPath = iface.call("FindUserById", uid);
    QDBusConnection::systemBus().connect("org.freedesktop.Accounts", objPath.value().path(), "org.freedesktop.Accounts.User", QString("Changed"), this, SLOT(userAccountsChanged()));

    //休眠、睡眠自动断开清除所有session
    QDBusConnection::systemBus().connect(
        QString("org.freedesktop.login1"), QString("/org/freedesktop/login1"), QString("org.freedesktop.login1.Manager"), QString("PrepareForShutdown"), this, SLOT(onCloseAllSession()));
    QDBusConnection::systemBus().connect(
        QString("org.freedesktop.login1"), QString("/org/freedesktop/login1"), QString("org.freedesktop.login1.Manager"), QString("PrepareForSleep"), this, SLOT(onCloseAllSession()));

    //插拔输入设备的信号3.1的聲音
    QDBusConnection::sessionBus().connect(QString(), QString("/"), "org.ukui.media", "sourcePortChanged", this,
                                          SLOT(handleInputDeviceChanged()));

    //活跃模块信号槽
    connect(this,&CMsgPane::showPage,this,&CMsgPane::updateCurrentActiveModule);
}

void CMsgPane::initChatOperator()
{
    m_chat = SystemChat::getPtr();

    connect(m_chat, &SystemChat::reply, this, &CMsgPane::onRecvMsg);
    connect(m_chat, &SystemChat::toolReply, this, &CMsgPane::onRecvTool);
    connect(m_chat, &SystemChat::sigAddScheduleDate, this, &CMsgPane::onAddToSchedule);

    connect(m_chat, &SystemChat::sigGeneratingPic, [=](QString model, QString feedbackURL){
        QJsonObject jsonObj;
        jsonObj["drawMsg"] = true;
        jsonObj["modelMsg"] = tr("Generated by %1").arg(model);
        jsonObj["feedbackURL"] = feedbackURL;
        QJsonDocument jDoc(jsonObj);
        QString jsonStr = jDoc.toJson(QJsonDocument::Indented);
        pushMsg("updateMsg", jsonStr, tr("Answering"));
    });

}

void CMsgPane::onBackBtnClicked()
{
    Q_EMIT sigBtnClicked(m_activeModule);
}

void CMsgPane::onSwitchToPlugin(QString page)
{
    pushMsg("switchToPlugin", "", page);
}

void CMsgPane::onClearContext()
{
    m_chat->clearContext();
}

QString CMsgPane::onSendMsg(const QString &jsonMsgHead, const QString &msg)
{
    //解析jsonMsgHead
    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonMsgHead.toUtf8());
//    KyInfo() << "onSendMsg" << jsonDoc;

    if (jsonDoc.isNull() || !jsonDoc.isObject()) {
        QJsonObject innerErrorJsonObject;
        innerErrorJsonObject["isReplying"] = false;
        QJsonDocument innerErrorJsonDoc(innerErrorJsonObject);
        return innerErrorJsonDoc.toJson(QJsonDocument::Indented);
    }

    QJsonObject jsonObjToQt = jsonDoc.object();
    msgHead = jsonObjToQt["msgHead"].toString();
    promptId = jsonObjToQt["promptId"].toInt();
    bool reAnswer = jsonObjToQt["reAnswer"].toBool();

    imagePath = jsonObjToQt["imagePath"].toString();
    imageSrc = jsonObjToQt["imageSrc"].toString();

    documentPath = jsonObjToQt["documentPath"].toString();
    documentIcon = jsonObjToQt["documentIcon"].toString();
    documentName = jsonObjToQt["documentName"].toString();
    documentSize = jsonObjToQt["documentSize"].toString();
    m_chat->soundFlag = jsonObjToQt["speechFlag"].toBool();

    send_message = msg;

    m_chat->target = RECVMSG;
    m_operatorId = 0; // 发送消息将图像处理操作置为文生图

    //1、判断是否为dbus命令   转为模型功能

    //判断是否有标签模板
    if(msgHead != "" && promptId != -1) {
        m_chat->setActor(promptId);
        KyInfo() << "set actor: " << promptId;
    }

    if(!reAnswer) {
        // 重新回答不需要渲染右侧消息
        QJsonObject jsonObjForSendMsg;
        jsonObjForSendMsg["msgHead"] = msgHead;
        jsonObjForSendMsg["promptId"] = promptId;
        jsonObjForSendMsg["colorMsg"] = "";
        jsonObjForSendMsg["imagePath"] = imagePath;
        jsonObjForSendMsg["imageSrc"] = imageSrc;
        jsonObjForSendMsg["documentPath"] = documentPath;
        jsonObjForSendMsg["documentIcon"] = documentIcon;
        jsonObjForSendMsg["documentName"] = documentName;
        jsonObjForSendMsg["documentSize"] = documentSize;
        jsonObjForSendMsg["speechFlag"] = m_chat->soundFlag;
        QJsonDocument aiJsonSendWebDoc(jsonObjForSendMsg);
        QString jsonMsgHeadToWeb = aiJsonSendWebDoc.toJson(QJsonDocument::Indented);
        pushMsg("addMsg", jsonMsgHeadToWeb, msg);
    }

    QJsonObject jsonObj;
    jsonObj["isFirst"] = true;
    QJsonDocument jDoc(jsonObj);
    QString jsonStr = jDoc.toJson(QJsonDocument::Indented);
    pushMsg("addRecvMsg", jsonStr, tr("Answering"));

    // 真正的发送时机
    if(imagePath.length() == 0) {
        m_chat->sendMessage(msg, documentPath);
    } else {
        m_chat->sendMessage(msg, imagePath);
    }

    QJsonObject retJsonObject;
    retJsonObject["isReplying"] = true;
    QJsonDocument retJsonDoc(retJsonObject);
    QString retJsonString = retJsonDoc.toJson(QJsonDocument::Indented);
    return retJsonString;
}

void CMsgPane::onStopReply()
{
    m_chat->stopChat();

    return;
}

//清除所有Session，在使用时重新初始化
void CMsgPane::onCloseAllSession()
{
    KyInfo() << "closeAllSession";
//    m_chat->closeSession();
    // 需要关注一下，这里的nlp算不算不在使用中了，如果没有置为false的话，会不会影响回答;
    m_recorder->closeSession();
    m_reader->closeSession();

}


///
/// \brief CMsgPane::checkChatModel  用于检查NLP模型、VISION模型、意图模型（本地NLP模型）是否配置
/// \param errorCode   错误码
/// \return 如果对应模型配置了，返回true；反之，返回false
///
bool CMsgPane::checkChatModel(int errorCode)
{
    kyai::assistant::ErrorCode error = static_cast<kyai::assistant::ErrorCode>(errorCode);
    if (error == kyai::assistant::ErrorCode::NlpModelNotFound || error == kyai::assistant::ErrorCode::VisionModelNotFound || error == kyai::assistant::ErrorCode::IntentNlpModelNotFound) {
        QJsonObject errorObject;
        errorObject["modelMsg"] = "ai";
        errorObject["noModelError"] = "true";
        QJsonDocument errorDoc(errorObject);
        QString json = errorDoc.toJson(QJsonDocument::Indented);
        QString errorMsg = "";

        switch(error){
        case kyai::assistant::ErrorCode::NlpModelNotFound:
            errorMsg = tr("The text dialogue feature requires support from a\"**large language model**\".  Configuration steps:\n\n 1. Go to the **System Settings > AI Module Management > Model Configuration** page to add a \"cloud model\", a \"local model\" or a \"optional model\". \n 2. If the model configuration is already completed, please confirm whether the model is enabled. \n\n Note: Running a local model may consume significant device resources. Please ensure your device meets the performance requirements.");
            break;
        case  kyai::assistant::ErrorCode::VisionModelNotFound:
            errorMsg = tr("The text-to-image feature requires support from a\"**vision model**\".  Configuration steps:\n\n 1. Go to the **System Settings > AI Module Management > Model Configuration** page to add a \"cloud model\", a \"local model\" or a \"optional model\". \n 2. If the model configuration is already completed, please confirm whether the model is enabled. \n\n Note: Running a local model may consume significant device resources. Please ensure your device meets the performance requirements.");
            break;
        case  kyai::assistant::ErrorCode::IntentNlpModelNotFound:
           errorMsg = tr("The system control feature requires support from a\"**large language model**\".  Configuration steps:\n\n 1. Go to the **System Settings > AI Module Management > Model Configuration** page to add a \"local model\". \n 2. If the model configuration is already completed, please confirm whether the model is enabled. \n\n Note: Running a local model may consume significant device resources. Please ensure your device meets the performance requirements.");
           break;
        }

        pushMsg("updateMsg", json, errorMsg);

        QTimer *tempTimer = new QTimer(this);
        connect(tempTimer,&QTimer::timeout,this,[&]{
            pushMsg("replyEnd", true);
        });
        tempTimer->setSingleShot(true);
        tempTimer->start(1000);

        return false;
    }


    return true;
}

void CMsgPane::onRecvMsg(QString reasoningContentMsg, QString msg, bool is_reasoning_end, bool is_end, int index, int errorCode, QString model , QString feedbackURL)
{
//    KyInfo() << "onRecvMsg msg" << msg;
//    KyInfo() << "onRecvMsg is_end" << is_end;
//    KyInfo() << "onRecvMsg index" << index;
//    KyInfo() << "onRecvMsg errorCode" << errorCode;

    //qDebug() << "onRecvMsg=reasoningContentMsg==" << reasoningContentMsg;
    //qDebug() << "onRecvMsg=msg==" << msg;
    //NLP错误码
    if(errorCode != 0)
    {  
        //如果上一条消息正在显示，则调用停止回答接口
        if(recv_message != "")
        { 
            recv_message = "";
            recv_reasoning_message = "";

        }

        //模型未配置，报错后结束会话。
        if (!checkChatModel(errorCode)){
            return;
        }

        //对于未知错误，展示error_message字段对应的所有值
        if(static_cast<kyai::assistant::ErrorCode>(errorCode) != kyai::assistant::ErrorCode::UnknownError){
            msg = globals::getErrorMsg(errorCode);
        }

        errorMessageToJs("", "ai", "red", msg);
        clearJsonMessage();
        return;
    }

    QString tmpStr = tr("Generated by %1").arg(model);
    jsonObjToWeb["modelMsg"] = tmpStr;
    jsonObjToWeb["feedbackURL"] = feedbackURL;
    QJsonDocument aiJsonSendWebDoc(jsonObjToWeb);
    QString jsonMsgHeadToWeb = aiJsonSendWebDoc.toJson(QJsonDocument::Indented);
//    KyInfo() << "onRecvMsg jsonMsgHeadToWeb" << jsonMsgHeadToWeb;
    //如果是新消息的第一个回答，设置消息头，清空文本，准备显示正文
    if(new_reply){
        pushMsg("updateMsg", jsonMsgHeadToWeb, "");
        clearJsonMessage();
    }
    recv_message.append(msg);
    recv_reasoning_message.append(reasoningContentMsg);
    new_reply = is_end;
    m_is_reasoning_end = is_reasoning_end;

    updateBubble();


}

void CMsgPane::onAudioRecvMsg(QString msg, bool is_end, int index, int errorCode, QString model)
{
    if(errorCode != 0)
    {
        //如果上一条消息正在显示，则停止显示动画，输出全部文字
        if(recv_message != "")
        {
            onStopReply();
        }

        //模型未配置的错误需要单独处理
        if (errorCode == AISDK_MODEL_NOT_FOUND){

            //启用计时器，当前端和后端都收到停止信号后，发送错误消息
            QTimer *tempTimer = new QTimer(this);
            connect(tempTimer,&QTimer::timeout,this,[=]{
                if (getIsEnd()){

                    QJsonObject jsonObj;
                    jsonObj["isFirst"] = true;
                    jsonObj["modelMsg"] = "ai";
                    jsonObj["noModelError"] = "true";
                    QJsonDocument jDoc(jsonObj);
                    QString jsonStr = jDoc.toJson(QJsonDocument::Indented);
                    QString errorStr = tr("The voice dialogue feature requires support from a \"**voice model**\". Configuration steps:\n\n 1. Go to the **System Settings > AI Module Management > Model Configuration** page to add a \"cloud model\", a \"local model\" or a \"optional model\".\n 2. If the model configuration is already completed, please confirm whether the model is enabled. \n\n Note: Running a local model may consume significant device resources. Please ensure your device meets the performance requirements.");
                    pushMsg("addRecvMsg", jsonStr, errorStr);
                    pushMsg("replyEnd", true);

                    tempTimer->stop();
                }

            });
            tempTimer->start(100);

            Q_EMIT cancelSendAudio();

            return;
        }
        QTimer *tempTimer2 = new QTimer(this);
        connect(tempTimer2,&QTimer::timeout,this,[=]{
            if (getIsEnd()){
                QJsonObject jsonObj;
                jsonObj["isFirst"] = true;
                QJsonDocument jDoc(jsonObj);
                QString jsonStr = jDoc.toJson(QJsonDocument::Indented);
                pushMsg("addRecvMsg", jsonStr, "");
                errorMessageToJs("",tr("Generated by AI Assistant"),"red",msg);
                clearJsonMessage();

                tempTimer2->stop();
            }

        });
        tempTimer2->start(100);

        return;
    }
}

void CMsgPane::onRecvTool(QString msg, QMap<int, QString> imageToolMap, QString imagePath, int errorCode, QString model, QString feedbackURL)
{
//    if(is_thinking == true)
//    {
//        is_thinking = false;
//    }

    //NLP错误码
    if(errorCode != 0)
    {
        errorMessageToJs("", tr("Generated by AI Assistant"), "red", msg);
        //pushMsg("replyEnd", true);
        clearJsonMessage();
        return;
    }

    QJsonObject jsonObj;
    QJsonArray jsonArray;
    for(auto i = imageToolMap.constBegin(); i != imageToolMap.constEnd(); ++i)
    {
        QJsonObject toolObj;
        toolObj["tool_id"] = i.key();
        toolObj["tool_name"] = i.value();
        jsonArray.append(toolObj);
    }
    jsonObj["pictureOperates"] = jsonArray;
    QJsonDocument doc(jsonObj);
    QString jsonData = doc.toJson(QJsonDocument::Indented);

    QJsonObject todoJsonObjToWeb;
    QString tmpStr = tr("Generated by %1").arg(model);
    todoJsonObjToWeb["msgHead"] = msgHead;
    todoJsonObjToWeb["promptId"] = promptId;
    todoJsonObjToWeb["msg"] = msg;
    todoJsonObjToWeb["imagePath"] = imagePath;
    todoJsonObjToWeb["modelMsg"] = tmpStr;
    todoJsonObjToWeb["feedbackURL"] = feedbackURL;
    QJsonDocument aiJsonSendWebDoc(todoJsonObjToWeb);
    QString scheJsonMsgHeadToWeb = aiJsonSendWebDoc.toJson(QJsonDocument::Indented);

    pushMsg("updateMsg", scheJsonMsgHeadToWeb, msg);

    pushMsg("appendRecvTool", jsonData, msg);
    Q_EMIT updateOperateRefresh();//图像处理的重新回答不可用
    pushMsg("replyEnd", true);
}


void CMsgPane::onShowText(const QString text)
{
    pushMsg("showText", "", text);
}

void CMsgPane::onShowSpeech(const QString text)
{
    //    QString msg = this->m_finishedSpeech + text;
    //    msg.replace('\n', "");
    //    QString js_str = QString("updateMsg('%1')").arg(msg);
    //    KyInfo() << js_str;
    //    m_pViewChat->page()->runJavaScript(js_str);
}

void CMsgPane::onAppendSpeech(const int speakerID, const QString text)
{
    ModelConfig mc;
    std::string modelStr = mc.getCurrentModelName(AiCapability::Speech, DeployType::PublicCloud);
    QString tmpStr = QString::fromStdString(modelStr);
    jsonObjToWeb["modelMsg"] = tmpStr;
    jsonObjToWeb["speakerId"] = speakerID;
    QJsonDocument modelJsonSendWebDoc(jsonObjToWeb);
    QString jsonMsgHeadToWeb = modelJsonSendWebDoc.toJson(QJsonDocument::Indented);
    clearJsonMessage();
}

void CMsgPane::updateToShowPic(QString imageData, QString errorMessage)
{
        //如果文生图生成失败，向前端插入生成失败的图片
    if (errorMessage == "failed"){
        m_operatorId = 4;
        Q_EMIT insertImage("", m_operatorId, imagePath);
        return;
    }

    if(imageData != ""){
        QString str = QString("data:" + imageData);
        Q_EMIT insertImage(str, m_operatorId, imagePath);
    }else{
        //如果无图片数据，说明文生图已暂停
        Q_EMIT sigCancelGenerateImage();
    }

    pushMsg("replyEnd", true);
}

void CMsgPane::updateToShowOperatePic(QString imageData, QString errorMessage)
{
    if(imageData != "")
    {
        QString str = QString("data:" + imageData);
        Q_EMIT insertOperateImage(str, m_operatorId, imagePath);
        Q_EMIT updateOperateRefresh();//图像处理的重新回答不可用
    }
    pushMsg("replyEnd", true);
    clearJsonMessage();
}

void CMsgPane::sigPictureAutoSpeak()
{
    if(m_chat->soundFlag)
    {
      m_chat->soundFlag = false; //设置语音回答标志位
      pushMsg("triggerAutoRead", "");
    }
}

/**
 * @brief CMsgPane::updateToShowAIPic  AI文生图返回图片函数
 * @param imageData 图像数据
 * @param errorMessage 错误信息
 */
//void CMsgPane::updateToShowAIPic(VisionImageData *imageData, QString errorMessage)
//{
//    KyInfo() << "updateToShowAIPic" << imageData;
//    if(imageData != nullptr)
//    {
//        KyInfo() << "图片base64 data数据：" << imageData->data << "图片字节数：" << imageData->data_size << "图像宽高：" << imageData->width << imageData->height;

//        //上传图像到html，并更新当前的对话框
//        QPixmap map;
//        map.loadFromData(imageData->data, imageData->data_size);

//        QImage image = map.toImage();
//        // 将QImage转换为QByteArray
//        QByteArray byteArray;
//        QBuffer buffer(&byteArray);
//        buffer.open(QIODevice::WriteOnly);
//        image.save(&buffer, "PNG");
//        buffer.close();
//        QString str = QString("data:image/png;base64," + byteArray.toBase64());
//        Q_EMIT insertImage(str);
//    }
//    if(!errorMessage.isEmpty())
//    {
//        KyInfo() << "图片生成失败，imageData为空，错误信息(存在多种错误反馈)： " << errorMessage;
//        jsonObjToWeb["modelMsg"] = "ai";
//        jsonObjToWeb["colorMsg"] = "red";
//        QJsonDocument aiJsonSendWebDoc(jsonObjToWeb);
//        QString jsonMsgHeadToWeb = aiJsonSendWebDoc.toJson(QJsonDocument::Indented);
//        pushMsg("updateMsg", jsonMsgHeadToWeb, errorMessage + "，请重新尝试。");
//    }
//    pushMsg("replyEnd", true);
//    clearJsonMessage();
//}

/**
 * @brief CMsgPane::updateBubble
 * 原功能：按字去更新内容
 * 现功能：接收SDK返回的文本显示到前端
 */
void CMsgPane::updateBubble()
{
    //显示推理过程
    if(recv_reasoning_message != ""){
        KyInfo() << "思考过程message=" << recv_reasoning_message;
        // 思考过程消息加载
        if(new_reply)
        {
            recv_message = "";
            recv_reasoning_message = "";
            pushMsg("replyEnd", true);
            return;
        }
        if(m_is_reasoning_end)
        {
            KyInfo() << "思考过程回答结束";
            recv_reasoning_message = "";
            return;
        }
        QString show_reason_msg = recv_reasoning_message;
        pushMsg("updateReasoningMsg", "", show_reason_msg);
    }else{
        // 总结消息加载
        if(new_reply)
        {
            //对于is_end信号和msg一起返回的消息，需要再向前端更新一次文本
            if(recv_message != ""){
                pushMsg("updateMsg", "", recv_message);
            }
            KyInfo() << "recv_message" << recv_message;
            recv_message = "";
            recv_reasoning_message = "";
            //如果上一条消息是整理周报，那么在回答结束时生成周报
            int mID = m_commandListModel->getPromptId("整理周报");
            if(promptId == mID)
            {
                Q_EMIT saveToPDF();
                return;
            }
            pushMsg("replyEnd", true);

            //语音模式下记录当前回答的所有内容并在回答结束后进行朗读  --该功能已删除
            return;
        }
        QString show_msg = recv_message;
        pushMsg("updateMsg", "", show_msg);
    }

    return;
}

//无参，多用于控制前端状态变化
void CMsgPane::pushMsg(QString func)
{
    if(func == "saveLastMsgToDatabase"){
        Q_EMIT saveLastMsgToDatabase();
    }
}

//单参，多用于修改某属性的值
void CMsgPane::pushMsg(QString func, QVariant arg1)
{
    if (func == "replyEnd"){
        bool flag = arg1.toBool();
        Q_EMIT replyEnd(flag);
    }
    else if(func == "addReportPath"){
        QString path = arg1.toString();
        Q_EMIT addReportPath(path);
    }
    else if(func == "triggerAutoRead"){
        QString msg = arg1.toString();
        Q_EMIT triggerAutoRead(msg);
    }
}

//消息类发送接口，所有对话类消息通过此处发送至前端
void CMsgPane::pushMsg(QString func, QString jsonMsgHeadToWeb, QString msg)
{
    if (func == "addMsg") {
        Q_EMIT addMsg(jsonMsgHeadToWeb, msg);
    }
    // 定义一个正则表达式匹配 HTML 标签
    QRegularExpression htmlTagPattern("<[^>]+>");
    // 使用正则表达式进行匹配
    QRegularExpressionMatch match = htmlTagPattern.match(msg);
    // 如果返回的结果里面带html标签，则不转换，直接发前端显示
    if(msg != "" && !match.hasMatch()){
        if(msg != ""){
            msg = msg.replace("#", "##"); // 设计要求，将markdown格式的#大标题替换成##小标题
        }
        msg = convertMarkDownToHtml(msg);
    }

    if (func == "addRecvMsg") {
        Q_EMIT addRecvMsg(jsonMsgHeadToWeb, msg);
    }

    if (func == "updateMsg") {
        Q_EMIT updateMsg(jsonMsgHeadToWeb, msg);
    }
    if(func == "addRecvSources"){
        Q_EMIT addRecvSources(jsonMsgHeadToWeb);
    }
    if(func == "appendRecvTool"){
        Q_EMIT appendRecvTool(jsonMsgHeadToWeb);
    }
    if (func == "updateReasoningMsg") {
        Q_EMIT updateReasoningMsg(jsonMsgHeadToWeb, msg);
    }
}

bool CMsgPane::getIsEnd()
{
    bool currentIsEnd  = new_reply && !m_isReplying;
    return  currentIsEnd;
}

bool CMsgPane::isCommunity()
{
    static int sIsCommunity = -1;
    if(sIsCommunity == -1)
    {
        QString filename = "/etc/os-release";
        QSettings osSettings(filename, QSettings::IniFormat);

        QString versionID = osSettings.value("VERSION_ID").toString();

        if(versionID.compare("22.04", Qt::CaseSensitive))
        {
            sIsCommunity = 0;
        }
        else
        {
            sIsCommunity = 1;
        }
    }
    return (bool)(sIsCommunity);
}

QString CMsgPane::getDefaultFace()
{
    if(isCommunity())
    {
        return ":/images/01-default-community.png";
    }

    //优先读取控制面板的默认头像文件，保持登录锁屏默认头像和控制面板一致
    QFile faceFile("/usr/share/ukui/faces/default.png");
    if(faceFile.exists())
    {
        return "/usr/share/ukui/faces/default.png";
    }

    return ":/images/01-default-commercial.png";
}

void CMsgPane::initDefaultUserIcon()
{
    m_defaultUserIcon = getDefaultFace();

    return;
}

QString CMsgPane::markdownToHtml(const std::string &markdown)
{
    // Convert the markdown text to HTML
    const char* markdownText = markdown.c_str();
    char* html = cmark_markdown_to_html(markdownText, strlen(markdownText), CMARK_OPT_DEFAULT);

    // Handle the conversion result
    std::string htmlStr(html);
    //cmark_mem_free(html);
    QString qStr = QString::fromStdString(htmlStr);
    return qStr;
}


void CMsgPane::xdgOpen(QString path)
{
    QProcess process;
    QString command = "xdg-open";
    QStringList arguments;
    arguments << path;
    process.startDetached(command, arguments);
    process.waitForFinished(-1);
    // 检查进程是否正常退出
    if (process.exitStatus() == QProcess::NormalExit) {
        KyInfo() << "xdgOpen successfully!";
    } else {
        KyInfo() << "Failed  to open the dir with xdgOpen";
    }
}

void CMsgPane::xdgOpenForImageOperate(QString base64Image, int operatorId, QString imagePath)
{
    if(base64Image == ""){
        return;
    }
    QString imageFileName = ""; // 文件名
    QString savePath = QDir::homePath().append("/.config/kylin-aiassistant/operate-temp/"); // 实际保存文件路径

    // 若图片路径不为空，并且消息提为空则展示图片路径
    if(imagePath != ""){
        QFileInfo fileInfo(imagePath);
        QString fileName = fileInfo.baseName();
        if(fileName != ""){
            imageFileName = fileName;
        }else{
            imageFileName = imagePath;
        }
    }
    if(operatorId == 1){
        imageFileName = imageFileName.append(tr("-ScannedBlackWhiteDocument.png"));
    }else if(operatorId == 2){
        imageFileName = imageFileName.append(tr("-SmartCutouts.png"));
    }else{
//        imageFileName = "operate-temp.png";
        QDateTime currentTime = QDateTime::currentDateTime();
        QString timestamp = currentTime.toString("yyyyMMdd_hhmmss"); // 格式: 年月日_时分秒
        imageFileName = QString("aiassistant_%1_temp.png").arg(timestamp);
    }
    savePath = savePath.append(imageFileName);
    base64Image = base64Image.replace("data:image/png;base64,", ""); // 前端传来的需要去除前缀

    QString operate_path = QDir::homePath().append("/.config/kylin-aiassistant/operate-temp");
    if (!QDir().exists(operate_path))
        QDir().mkdir(operate_path);

    // 解码 Base64 字符串
    QByteArray decodedData = QByteArray::fromBase64(base64Image.toUtf8());

    // 将字节数据转换为 QImage
    QImage image;
    if (!image.loadFromData(decodedData)) {
        KyInfo() << "Failed to load image from decoded data.";
        return; // 如果加载失败，返回
    }

    // 使用 QImageWriter 保存图像
    QImageWriter writer(savePath);
    if (!writer.write(image)) {
        KyInfo() << "Failed to write image to file.";
        return; // 如果写入失败，返回
    }
    xdgOpen(savePath);
}

void CMsgPane::initCurrentUserName()
{
    QString objpath = QString("/org/freedesktop/Accounts/User%1").arg(getuid());

    QString userName;
    QDBusInterface *iproperty = new QDBusInterface("org.freedesktop.Accounts", objpath, "org.freedesktop.DBus.Properties", QDBusConnection::systemBus());
    QDBusReply<QMap<QString, QVariant>> ipropertyReply = iproperty->call("GetAll", "org.freedesktop.Accounts.User");
    if(ipropertyReply.isValid())
    {
        QMap<QString, QVariant> propertyMap = ipropertyReply.value();

        userName = propertyMap.find("RealName").value().toString();
    }

    changeCurrentUserName(userName);

    return;
}

void CMsgPane::initCurrentUserIcon()
{

    QString objpath = QString("/org/freedesktop/Accounts/User%1").arg(getuid());

    QString iconfile;
    QDBusInterface *iproperty = new QDBusInterface("org.freedesktop.Accounts", objpath, "org.freedesktop.DBus.Properties", QDBusConnection::systemBus());
    QDBusReply<QMap<QString, QVariant>> ipropertyReply = iproperty->call("GetAll", "org.freedesktop.Accounts.User");
    if(ipropertyReply.isValid())
    {
        QMap<QString, QVariant> propertyMap = ipropertyReply.value();

        iconfile = propertyMap.find("IconFile").value().toString();
    }

    if(!QFile(iconfile).exists())
    {
        iconfile = m_defaultUserIcon;
        return;
    }

    QImage image(iconfile);

    QByteArray ba;
    QBuffer buf(&ba);
    image.save(&buf, "png");
    buf.close();
    QString base64Str = QString::fromLocal8Bit(ba.toBase64());
    QString base64StrIcon = "data:image/png;base64," + base64Str;

    changeCurrentUserIcon(base64StrIcon);

    return;
}

void CMsgPane::userAccountsChanged()
{
    initCurrentUserName();
    initCurrentUserIcon();

    return;
}

void CMsgPane::saveDialogToFile(const QString &dialogJsonString)
{
    // 获取当前时间
    QDateTime currentTime = QDateTime::currentDateTime();

    // 格式化当前时间为字符串，包含年、月、日、小时、分钟和秒
    QString formattedTime = currentTime.toString("yyyyMMdd_hhmmss");

    // 使用格式化后的时间作为文件名
    QString fileName = globals::defaultPath + "/.dialog/dialog_" + formattedTime + ".json";

    QFile file(fileName);
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        return;
    }

    file.write(dialogJsonString.toUtf8());

    file.close();

    // 由于CMsgPane::saveDialogToFile是被异步调用的，所以这里通过信号通知历史会话界面当前已经保存了会话到文件，以此更新历史会话界面。
    Q_EMIT sigSaveDialog(fileName);

    return;
}

void CMsgPane::saveMessageToFile(const QString &msgJsonString)
{
    QString fileName = globals::defaultPath + "/.dialog/message.json";

    QFile file(fileName);
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        return;
    }

    file.write(msgJsonString.toUtf8());

    file.close();

    return;
}


void CMsgPane::saveDialog()
{
    // 先保存当前会话
//    m_pViewChat->page()->runJavaScript("getActiveDialog()", [this](const QVariant &v) {
//        this->saveDialogToFile(v.toString());
//    });

    return;
}

void CMsgPane::clearDialog()
{
    // 然后清除当前会话
//    m_pViewChat->page()->runJavaScript("clearActiveDialog()");

    return;
}

void CMsgPane::loadPlugin(QString pluginHtmlFile)
{
//    m_pViewChat->load(QUrl(pluginHtmlFile));
}


///
/// \brief CMsgPane::onAddToSchedule
/// 向前端发送消息，根据isAddSchedule 和 isGenerateToDo 控制前端显示UI
/// \param operatorId  日历相关操作码， 21 新建日程 22 生成待办
/// \param schedule_date  打开日历的日期
///
void CMsgPane::onAddToSchedule(int operatorId, QString schedule_date, QString msg, QString model, QString feedbackURL)
{
    QString tmpStr = tr("Generated by %1").arg(model);
    QJsonObject todoJsonObjToWeb;
    if (operatorId == 21) {
        todoJsonObjToWeb["isAddSchedule"] = true;
    }
    else {
        todoJsonObjToWeb["isGenerateToDo"] = true;
    }
    todoJsonObjToWeb["scheduleDate"] = schedule_date;
    todoJsonObjToWeb["msgHead"] = msgHead;
    todoJsonObjToWeb["promptId"] = promptId;
    todoJsonObjToWeb["modelMsg"] = tmpStr;
    todoJsonObjToWeb["feedbackURL"] = feedbackURL;
    QJsonDocument aiJsonSendWebDoc(todoJsonObjToWeb);
    QString scheJsonMsgHeadToWeb = aiJsonSendWebDoc.toJson(QJsonDocument::Indented);
    pushMsg("updateMsg", scheJsonMsgHeadToWeb, msg);
    recv_message = "";
    recv_reasoning_message = "";
    new_reply = true;
    clearJsonMessage();
    pushMsg("replyEnd", true);

    return;
}

///
/// \brief CMsgPane::openSchedule
/// 通过AI SDK打开日历
/// \param schedule_date 年月日信息，格式 2025-03-25
///
void CMsgPane::openSchedule(QString schedule_date)
{
    m_chat->sendToolMessage(21, SCHEDULE, schedule_date);
}

void CMsgPane::onSendAudio()
{
    //检查模型是否配置由SDK完成，根据错误码报错
    m_recorder->startRecord();

    return;
}

void CMsgPane::onStopAudio()
{
    m_recorder->stopRecord();
    //录音结束，调用recorder的发送接口，异步返回结果
}

void CMsgPane::onCancelAudio()
{

    m_recorder->stopRecord();
    Q_EMIT cancelSendAudio();
}

void CMsgPane::onStartTimer()
{
    Q_EMIT updateCurrentStartTimer();
}

//当切换历史会话时，需要通过speechMode判断是否需要取消录音
void CMsgPane::onSpeechModeChanged(int status)
{

    // 语音四种状态，对应qml speechMode: 0 未进行录音 2 正在录音
    qDebug() << "onSpeechModeChanged" << status;

    speechMode = status;
}

void CMsgPane::onStartRead(const QString &msg, int index)
{
    KyInfo() << "startRead" << msg << index;
    bool ret = m_reader->sendText(msg, index);

}

void CMsgPane::onPauseRead()
{
    KyInfo() << "pauseRead";
    m_reader->pauseReading();
}

void CMsgPane::onContinueRead(int index)
{
    KyInfo() << "continueRead" << index;
    m_reader->continueReading(index);
}

void CMsgPane::onReadEnd(int index)
{
    KyInfo() << "ReadEnd " << index;
    Q_EMIT setReadEnd(index);
}

void CMsgPane::onClearDictation()
{
//    TipWidget::showTip(tr("Cleared"), 1000, QSize(106, 48), parentWidget(), TipWidget::OK);
}

void CMsgPane::onCopySuccess()
{
    Q_EMIT copySuccess();
}

void CMsgPane::onCopyText(const QString &text)
{
    Q_EMIT copyToClipboard(text);
}

void CMsgPane::onCopyImage(const QString &base64Image)
{
    // 复制图片到剪切板
    QString base64Image1;
    int commaIndex = base64Image.indexOf(',');
    if (commaIndex != -1) {
        // 去掉前缀data:image/png;base64,
         base64Image1 = base64Image.mid(commaIndex + 1);
    } else {
        KyInfo() << "无法找到Base64数据的前缀结束符";
    }
    if (base64Image1.length() > 0) {
        QByteArray decodedData = QByteArray::fromBase64(base64Image1.toUtf8());
        QImage image;
        if (!image.loadFromData(decodedData)) {
            KyInfo() << "image loadFromData failed";
            return;
        }
        QPixmap pixmap = QPixmap::fromImage(image);
        if (pixmap.isNull()) {
            KyInfo() << "pixmap is null";
            return;
        } else {
            // 复制到剪切板
            QClipboard *clipBoard= QApplication::clipboard();
            clipBoard->setPixmap(pixmap);
            KyInfo() << "复制图片到剪贴板";
            Q_EMIT copyImageToClipboard();
        }
    }
}

void CMsgPane::onLikeAction()
{
    Q_EMIT sigLikeAction();
}

void CMsgPane::onContinueDialog()
{
    QMetaObject::invokeMethod( this, "onTipsContinueDialog",Qt::QueuedConnection);

}

void CMsgPane::onTipsContinueDialog()
{
     Q_EMIT tipsContinueDialog();
}

void CMsgPane::onsigReloadIsRunning()
{
    QMetaObject::invokeMethod(this,"onTipsReloadIsRunning",Qt::QueuedConnection);

}

void CMsgPane::onReloadIsRunning()
{
    Q_EMIT sigReloadIsRunning();
}


void CMsgPane::onLoadMessageList()
{
    QString directoryPath = globals::defaultPath + "/.dialog";
    QDir dir(directoryPath);
    if(!dir.exists())
    {
        KyInfo() << "目录不存在：" << directoryPath;
        return;
    }
    QString fileName = "message.json";
    QFile file(directoryPath + "/" + fileName);
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        KyInfo() << "无法打开文件：" << fileName;
        return;
    }

    QByteArray jsonData = file.readAll();
    file.close();

    QJsonParseError parseError;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError);
    if(parseError.error != QJsonParseError::NoError)
    {
        KyInfo() << "JSON 解析错误：" << parseError.errorString();
        return;
    }

    QJsonArray jsonArray = jsonDoc.array();
    QString str = QJsonDocument(jsonArray).toJson(QJsonDocument::Indented);
    str.replace("\\", "\\\\");
    str.replace("\n", "\\n");
    str.replace("\"", "\\\"");
    QString js_str = QString("loadMessageList('%1')").arg(str);
    //    m_pViewChat->page()->runJavaScript(js_str);
}

void CMsgPane::onChangedIsReplyingStatus(bool isReplying)
{
    m_isReplying = isReplying;
    KyInfo() << "update m_isReplying " << m_isReplying;
}

void CMsgPane::onDownloadImage(const QString &base64Image)
{
    Q_EMIT sigSaveAs(base64Image);
}

void CMsgPane::onSaveHTML2PDF(const QString &data)
{
    QString htmlContent = data;
    QTextDocument document;
    document.setHtml(htmlContent);

    QString dirPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
    //m_dirPath = picPath + "/" + tr("Docs Processing");
    QString m_dirPath = dirPath + "/kylin-aiassistant/周报";
    QDir dir;
    if(!dir.exists(m_dirPath))
    {
        if(!dir.mkpath(m_dirPath))
        {
            KyInfo() << "创建文档处理目录失败";
        }
        else
        {
            KyInfo() << "创建文档处理目录成功 dirpath = " << m_dirPath;
        }
    }

    //生成pdf文件名
    QDateTime currentTime = QDateTime::currentDateTime();
    QString formattedTime = currentTime.toString("yyyyMMdd_hhmmss");
    // 使用格式化后的时间作为文件名
    QString fileName = "周报_" + formattedTime + ".docx";
    QString path = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).at(0);
    if(path.endsWith("/"))
    {
        path += "kylin-aiassistant/周报/" + fileName;
    }
    else
    {
        path += "/kylin-aiassistant/周报/" + fileName;
    }
    // 使用 QTextDocumentWriter 保存为 HTML 格式
    QString tmpPath = path;
    tmpPath.replace(".docx", ".html");
    QTextDocumentWriter writer(tmpPath);
    writer.setFormat("html"); // 保存为 HTML 格式
    if (!writer.write(&document)) {
        KyInfo() << "Failed to save document.";
    } else {
        KyInfo() << "Document saved as HTML:" << tmpPath;
    }

    // 使用外部工具将 html 转换为 DOCX
    QProcess process;
    QStringList arguments;
    arguments << tmpPath << "-o" << path << "--reference-doc=/usr/share/kylin-aiassistant/custom-reference.docx";
    process.start("pandoc", arguments);
    process.waitForFinished();

    // 删除临时 HTML 文件
    QFile::remove(tmpPath);

    pushMsg("addReportPath", path);
    return;
}

void CMsgPane::onSendDataCollect(const QString &eventCode, const QString &pageName)
{
    //埋点数据发送与处理
    // 初始化埋点数据，传入应用类型，桌面应用，时间类型，点击事件
    KTrackData *node = kdk_dia_data_init(KEVENTSOURCE_DESKTOP, KEVENT_CLICK);
    // 传入事件描述“对话框——发送消息”，所在界面“主界面”，上传事件
    //KyInfo() << eventCode.toLocal8Bit().data() << pageName.toLocal8Bit().data();
    kdk_dia_upload_default(node, eventCode.toLocal8Bit().data(), pageName.toLocal8Bit().data());
    // 释放内存
    kdk_dia_data_free(node);
}

void CMsgPane::onSelectFile(int typeNum)
{
    Q_EMIT sigOpenFile(typeNum);
}

void CMsgPane::onShowImage(const QString &imagePath, int counts)
{
    if(counts >1){
        QJsonObject jsonObj;
        jsonObj["msgHead"] = msgHead;
        jsonObj["promptId"] = -1;
        jsonObj["modelMsg"] = "ai";
        jsonObj["colorMsg"] = "red";
        jsonObj["imageSrc"] = "";
        QJsonDocument ModelJsonSendWebDoc(jsonObj);
        QString errorJsonMsgHeadToWeb = ModelJsonSendWebDoc.toJson(QJsonDocument::Indented);
        pushMsg("addRecvMsg", errorJsonMsgHeadToWeb, tr("The number of files uploaded cannot exceed 1."));
        pushMsg("replyEnd", true);
        clearJsonMessage();
        return;
    }
    QFile file(imagePath);
    if(!file.open(QIODevice::ReadOnly))
    {
        // 错误处理：文件无法打开
        return;
    }
    //判断图片的大小是否超过50MB
    if(file.size() > 50 * 1024 * 1024){
        file.close();
        QJsonObject jsonObj;
        jsonObj["msgHead"] = msgHead;
        jsonObj["promptId"] = -1;
        jsonObj["modelMsg"] = "ai";
        jsonObj["colorMsg"] = "red";
        jsonObj["imageSrc"] = "";
        QJsonDocument ModelJsonSendWebDoc(jsonObj);
        QString errorJsonMsgHeadToWeb = ModelJsonSendWebDoc.toJson(QJsonDocument::Indented);
        pushMsg("addRecvMsg", errorJsonMsgHeadToWeb, tr("The size of the uploaded image cannot exceed 50MB."));
        pushMsg("replyEnd", true);
        clearJsonMessage();
        return;
    }
    QString base64Image = getBase64FromImagePath(imagePath);
    QString str = QString("data:image/png;base64," + base64Image);
    Q_EMIT addImagePreview(imagePath , str);
}

QString CMsgPane::onPictureOperateClick(int toolId, const QString &imagePathTem)
{
    m_operatorId = toolId;
    if(imagePathTem.length() == 0)
    {
        KyInfo() << "error imagePath 为空";
        clearJsonMessage();
        jsonObjToWeb["modelMsg"] = tr("Generated by AI Assistant");
        jsonObjToWeb["colorMsg"] = "red";
        QJsonDocument aiJsonSendWebDoc(jsonObjToWeb);
        QString jsonMsgHeadToWeb = aiJsonSendWebDoc.toJson(QJsonDocument::Indented);
        pushMsg("addRecvMsg", jsonMsgHeadToWeb, tr("Image processing failed"));
        pushMsg("replyEnd", true);
        clearJsonMessage();
        QJsonObject retJsonObject;
        retJsonObject["isReplying"] = false;
        QJsonDocument retJsonDoc(retJsonObject);
        QString retJsonString = retJsonDoc.toJson(QJsonDocument::Indented);
        return retJsonString;
    }
    else
    {
        QJsonObject jsonObj;
        jsonObj["drawMsg"] = true;
        QJsonDocument jDoc(jsonObj);
        QString jsonStr = jDoc.toJson(QJsonDocument::Indented);
        pushMsg("addRecvMsg", jsonStr, tr("Answering"));
        clearJsonMessage();
        imagePath = imagePathTem;
        m_chat->sendToolMessage(toolId, IMAGE, imagePathTem);
        QJsonObject retJsonObject;
        retJsonObject["isReplying"] = true;
        QJsonDocument retJsonDoc(retJsonObject);
        QString retJsonString = retJsonDoc.toJson(QJsonDocument::Indented);
        return retJsonString;
    }
}

void CMsgPane::onImageDragIn(bool dragin)
{
    QString js_str = QString("imageDragIn('%1')").arg(dragin);
//    m_pViewChat->page()->runJavaScript(js_str);
}

void CMsgPane::onShowErrorMoreImage()
{
    QJsonObject jsonObj;
    jsonObj["msgHead"] = msgHead;
    jsonObj["promptId"] = -1;
    jsonObj["modelMsg"] = "ai";
    jsonObj["colorMsg"] = "red";
    jsonObj["imageSrc"] = "";
    QJsonDocument ModelJsonSendWebDoc(jsonObj);
    QString errorJsonMsgHeadToWeb = ModelJsonSendWebDoc.toJson(QJsonDocument::Indented);
    pushMsg("addRecvMsg", errorJsonMsgHeadToWeb, tr("The number of files uploaded cannot exceed 1."));
    pushMsg("replyEnd", true);
    clearJsonMessage();
}

void CMsgPane::onShowErrorSizeImage()
{
    QJsonObject jsonObj;
    jsonObj["msgHead"] = msgHead;
    jsonObj["promptId"] = -1;
    jsonObj["modelMsg"] = "ai";
    jsonObj["colorMsg"] = "red";
    jsonObj["imageSrc"] = "";
    QJsonDocument ModelJsonSendWebDoc(jsonObj);
    QString errorJsonMsgHeadToWeb = ModelJsonSendWebDoc.toJson(QJsonDocument::Indented);
    pushMsg("addRecvMsg", errorJsonMsgHeadToWeb, tr("The size of the uploaded file cannot exceed 50MB."));
    pushMsg("replyEnd", true);
    clearJsonMessage();
}

void CMsgPane::onShowErrorFormatImage()
{
    QJsonObject jsonObj;
    jsonObj["msgHead"] = msgHead;
    jsonObj["promptId"] = -1;
    jsonObj["modelMsg"] = "ai";
    jsonObj["colorMsg"] = "red";
    jsonObj["imageSrc"] = "";
    QJsonDocument ModelJsonSendWebDoc(jsonObj);
    QString errorJsonMsgHeadToWeb = ModelJsonSendWebDoc.toJson(QJsonDocument::Indented);
    pushMsg("addRecvMsg", errorJsonMsgHeadToWeb, tr("The file format is not supported. Please use the following supported formats: "
                                                    "PNG, BMP, JPE, JPG, GIF, WEBP, JPEG, ICO"));
    pushMsg("replyEnd", true);
    clearJsonMessage();
}

QString iconToBase64(const QIcon &icon)
{
    // 将QIcon转换为QPixmap（使用默认大小或指定大小）
    QPixmap pixmap = icon.pixmap(32, 32); // 例如，32x32像素大小
    QByteArray ba;
    QBuffer buffer(&ba);
    buffer.open(QIODevice::WriteOnly);

    // 将QPixmap保存为字节数组
    pixmap.save(&buffer, "PNG"); // 使用PNG格式保存
    buffer.close();

    // 对字节数组进行Base64编码
    QString base64 = ba.toBase64();

    return base64;
}
void CMsgPane::onShowDocument(const QString &filePath)
{
    //传入文件路径，文件图标，文件名，文件大小
    QFileInfo fileInfo(filePath);
    if(!fileInfo.exists())
    {
        KyInfo() << "文件不存在:" << filePath;
        return;
    }

    QString fileName = fileInfo.fileName();

    // 获取图标
    QIcon fileIcon = QIcon();
    fileIcon = QIcon::fromTheme(globals::getFileIconName("file://" + filePath), QIcon::fromTheme("text-x-generic"));
    QString base64Icon = iconToBase64(fileIcon);

    QString str = QString("data:image/png;base64," + base64Icon);

    qint64 size = fileInfo.size();
    double fileSizeKB = static_cast<double>(size) / 1024;
    // 上传文件大小不能超过50MB
    if(fileSizeKB > 50 * 1024){
        QJsonObject jsonObj;
        jsonObj["msgHead"] = msgHead;
        jsonObj["promptId"] = -1;
        jsonObj["modelMsg"] = "ai";
        jsonObj["colorMsg"] = "red";
        jsonObj["imageSrc"] = "";
        QJsonDocument ModelJsonSendWebDoc(jsonObj);
        QString errorJsonMsgHeadToWeb = ModelJsonSendWebDoc.toJson(QJsonDocument::Indented);
        pushMsg("addRecvMsg", errorJsonMsgHeadToWeb, tr("The size of the uploaded file cannot exceed 50MB."));
        pushMsg("replyEnd", true);
        clearJsonMessage();
        return;
    }
    QString fileSize;
    if(fileSizeKB > 1024)
    {
        double fileSizeMB = static_cast<double>(fileSizeKB) / 1024;
        fileSize = QString::number(fileSizeMB, 'f', 2) + "MB";
    }
    else
    {
        fileSize = QString::number(fileSizeKB, 'f', 2) + "KB";
    }
    activateMainWindow();
    Q_EMIT addDocumentPreview(filePath, str, fileName, fileSize);
//    QTimer *tempTimer = new QTimer(this);
//    connect(tempTimer,&QTimer::timeout,this,[&]{
//        KyInfo() << "!!!!!!!!!!!!!!11";
//    });
//    tempTimer->setSingleShot(true);
//    tempTimer->start(1000);
}

void CMsgPane::onShowErrorFormatFile()
{
    QJsonObject jsonObj;
    jsonObj["msgHead"] = msgHead;
    jsonObj["promptId"] = -1;
    jsonObj["modelMsg"] = "ai";
    jsonObj["colorMsg"] = "red";
    jsonObj["imageSrc"] = "";
    QJsonDocument ModelJsonSendWebDoc(jsonObj);
    QString errorJsonMsgHeadToWeb = ModelJsonSendWebDoc.toJson(QJsonDocument::Indented);
    pushMsg("addRecvMsg", errorJsonMsgHeadToWeb, tr("The file format is not supported. Please use the following supported formats: "
                                                 "txt、pdf、docx、pptx"));
    pushMsg("replyEnd", true);
    clearJsonMessage();
}

void CMsgPane::onShowErrorFormat()
{
    QJsonObject jsonObj;
    jsonObj["msgHead"] = msgHead;
    jsonObj["promptId"] = -1;
    jsonObj["modelMsg"] = "ai";
    jsonObj["colorMsg"] = "red";
    jsonObj["imageSrc"] = "";
    QJsonDocument ModelJsonSendWebDoc(jsonObj);
    QString errorJsonMsgHeadToWeb = ModelJsonSendWebDoc.toJson(QJsonDocument::Indented);
    pushMsg("addRecvMsg", errorJsonMsgHeadToWeb, tr("The file format is not supported. Please use the following supported formats:\n"
                                                 "Images: png、bmp、jpe、jpg、gif、webp、jpeg、ico\n"
                                                 "Documents: txt、pdf、docx、pptx"));
    pushMsg("replyEnd", true);
    clearJsonMessage();
}

QString CMsgPane::getBase64FromImagePath(const QString &imagePath)
{
    QFile file(imagePath);
    if(!file.open(QIODevice::ReadOnly))
    {
        // 错误处理：文件无法打开
        return QString();
    }

    QByteArray fileData = file.readAll();
    file.close();

    return fileData.toBase64();
}

void CMsgPane::errorMessageToJs(QString msgHead, QString modelMsg, QString colorMsg, QString errorMsg)
{
    QJsonObject jsonObj;
    jsonObj["msgHead"] = msgHead;
    jsonObj["promptId"] = -1;
    jsonObj["modelMsg"] = modelMsg;
    jsonObj["colorMsg"] = colorMsg;
    jsonObj["imageSrc"] = "";
    jsonObj["drawMsg"] = false;
    QJsonDocument ModelJsonSendWebDoc(jsonObj);
    QString errorJsonMsgHeadToWeb = ModelJsonSendWebDoc.toJson(QJsonDocument::Indented);
    pushMsg("updateMsg", errorJsonMsgHeadToWeb, errorMsg);
    pushMsg("replyEnd", true);
}

void CMsgPane::clearJsonMessage()
{
    jsonObjToWeb["msgHead"] = "";
    jsonObjToWeb["promptId"] = -1;
    jsonObjToWeb["modelMsg"] = "";
    jsonObjToWeb["colorMsg"] = "";
    jsonObjToWeb["drawMsg"] = false;
    jsonObjToWeb["imageSrc"] = "";
    jsonObjToWeb["speakerId"] = "";
    jsonObjToWeb["imagePath"] = "";
    jsonObjToWeb["imageSrc"] = "";
    jsonObjToWeb["year"] = -1;
    jsonObjToWeb["month"] = -1;
    jsonObjToWeb["day"] = -1;
    jsonObjToWeb["isAddSchedule"] = false;
    jsonObjToWeb["isGenerateToDo"] = false;
}

void CMsgPane::updateToShowSource(QMap<int, QString> infoSourceMap)
{
    QJsonObject jsonObj;
    QJsonArray jsonArray;
    for(auto i = infoSourceMap.constBegin(); i != infoSourceMap.constEnd(); ++i)
    {
        QJsonObject toolObj;
        toolObj["tool_id"] = i.key();
        toolObj["text"] = i.value();
        jsonArray.append(toolObj);
    }
    jsonObj["infoSources"] = jsonArray;

    QJsonDocument doc(jsonObj);
    QString jsonData = doc.toJson(QJsonDocument::Indented);

    pushMsg("addRecvSources", jsonData, "");
}

void CMsgPane::onSelectInfoSource(int toolId)
{
    KyInfo() << "__________________"
             << "toolId" << toolId;
    m_chat->sendToolMessage(toolId, SOURCE, "");
//    QString js_str2 = QString("setReplyStale()"); //设置上一条回答不可重新生成
//    m_pViewChat->page()->runJavaScript(js_str2);
}

void CMsgPane::initCommandList()
{
    // 获取所有的 prompts
    std::vector<Prompt> promptList = m_chat->getPrompts();
    m_commandListModel = new CommandTemplateList;
    CommandTemplateList::originalCommandListModel = m_commandListModel;
    m_commandListModel->initData(promptList);

}
void CMsgPane::openDocument(const QString &documentPath)
{
    //KyInfo() << "documentPath" << documentPath;
    // 检查文件和文件夹是否存在
    if(!QFileInfo::exists(documentPath))
    {
        QMessageBox::critical(nullptr, "", tr("No such file or directory!"));
        return;
    }

    QString path = QString("file://") + documentPath;
    //KyInfo() << "path" << path;
    bool is_open = QDesktopServices::openUrl(QUrl(path, QUrl::TolerantMode));

    if(!is_open)
    {
        //KyInfo() << "open by xdg";
        QString cmd = QString("xdg-open ") + path;
        QProcess::startDetached(cmd);
    }
}

bool CMsgPane::isSupportDocumentQA()
{
    return m_chat->getFeatureStatus(Features::Feature::DocumentQA);
}

bool CMsgPane::isSupportHtml2Docx()
{
    QProcess process;
    process.start("dpkg-query", QStringList() << "-W" << "-f" << "${Version}" << "pandoc");
    process.waitForFinished();
    QString output = process.readAllStandardOutput().trimmed();

    KyInfo() << "pandoc version :" << output;

    if(output == "") {
        return false;
    }

    return true;
}

bool CMsgPane::isSupportImageProcessing()
{
    return m_chat->getFeatureStatus(Features::Feature::ImageProcessing);
}

int CMsgPane::getCurrentSessionId()
{
    return m_chat->getSession();
}


void CMsgPane::activateMainWindow()
{
    // 发射信号
    Q_EMIT activateMainWindowSignal();
}

int CMsgPane::getShowPage()
{
    return g_currentPage;
}

void CMsgPane::updateDialogueListSessionId()
{
    Q_EMIT updateDialogueList();
}

void CMsgPane::onStopSpeak()
{
    Q_EMIT cancelVoiceStopReplying();
}

void CMsgPane::openUkuiControlCenter()
{
    QProcess process;
    QString command = "ukui-control-center";
    QStringList arguments;
    arguments << "-m" << "aisubsystem";
    process.startDetached(command, arguments);
    process.waitForFinished(-1);
    // 检查进程是否正常退出
    if (process.exitStatus() == QProcess::NormalExit) {
        KyInfo() << "ukui-control-center successfully!";
    } else {
        KyInfo() << "Failed  to open ukui-control-center";
    }
}

///
/// \brief CMsgPane::handleInputDeviceChanged
/// 处理声音I/O设备拔插信号
void CMsgPane::handleInputDeviceChanged()
{
    if (speechMode == 2)
        m_recorder->stopRecord();
    Q_EMIT cancelSendAudio();
}

void CMsgPane::onStartReplyingToChat()
{
    Q_EMIT startReplyingToChat(true);
}

void CMsgPane::saveToDatabase(int msgInex, QString message)
{
    int curID = m_chat->getSession();
    QString addressAsString = QString::number(curID);
    m_database->insertOne(addressAsString, msgInex, message);
    m_database->updateOperateTime(addressAsString, msgInex);//更新第一条数据的operatime
    int history_id_database = m_database->selectMaxHistoryId();
    int history_id_settings  = g_configManager->getConfigValue("history-id").toInt();
    if(curID == (history_id_database >= history_id_settings ? history_id_database : history_id_settings))
    {
        //g_configManager->updateConfig("history-id", (curID + 1)%INT_MAX);
        m_database->updateMaxHistoryId(((history_id_database >= history_id_settings ? history_id_database : history_id_settings) + 1));
    }
    int curWinMode = getCurWinMode();
    //窗口模式
    if(curWinMode == 3){
         getDialogueList();
    }

}

void CMsgPane::updateFeedbackDatabase(int msgInex, QString message)
{
    int curID = m_chat->getSession();
    QString addressAsString = QString::number(curID);
    m_database->updateFeedback(addressAsString, msgInex, message);
}

void CMsgPane::loadHistory()
{
    QStringList list =  m_database->selectAll();
    Q_EMIT loadConversation(list);
}

//去除字符串里面的标签
QString removeHtmlTags(const QString &input) {
    QTextDocument doc;
    doc.setHtml(input);
    return doc.toPlainText();  // 返回纯文本
}

void CMsgPane::loadHistoryBySessionId(QString sessionId)
{
    //KyInfo() << "Q_EMIT loadHistoryBySessionId sessionId=" << sessionId;
    QStringList list =  m_database->selectBySessionID(sessionId);
    if(m_chat->getSession() != sessionId.toInt()){
        onPauseRead();//切换对话时，若对话不是当前对话停止朗读
    }
    m_chat->setSession(sessionId.toInt());
    Q_EMIT changeSessionId(m_chat->getSession());
    Q_EMIT loadConversation(list);
    Q_EMIT modifyDialogueListFlag("");//恢复删除后列表的删除选中状态
    std::vector<Message> history;
    // 遍历 QStringList 取出msg字段
        for (const QString &jsonStr : list) {
            QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonStr.toUtf8());
            if (!jsonDoc.isObject()) {
                qWarning() << "Invalid JSON:" << jsonStr;
                continue;
            }
            QJsonObject jsonObj = jsonDoc.object();
            QString author = jsonObj.value("author").toString();
            std::string msg = removeHtmlTags(jsonObj.value("message").toString()).toStdString();
            Message m;
            if (author == "User") {
                m.user = msg;
            } else {
                m.assistant = msg;
            }
            history.push_back(m);
        }
    m_chat->initWithHistory(history);
}


void CMsgPane::getPluginList()
{
    Q_EMIT loadPluginList(m_pluginList);
}

void CMsgPane::getDialogueList()
{
    QStringList list =  m_database->selectAllDialogue();
    //KyInfo() << list;
    Q_EMIT loadDialogueList(list);
}

void CMsgPane::modifyDialogueList(const QVariantList &strings)
{
    for (const QVariant &sessionIDs : strings) {
        QString sessionID = sessionIDs.toString();
        Q_EMIT modifyDialogueListFlag(sessionID);
    }
}

void CMsgPane::initDeleteLayout(const QVariantList &strings)
{
    // 初始化删除确认弹窗
    Q_EMIT sigLoadMyMessageBox(strings);
}

void CMsgPane::deleteSessionList(const QVariantList &strings)
{
    // 删除选中历史记录
    // 用户点击了取消按钮或关闭了消息框，执行取消操作
    //KyInfo() << "deleteSessionList";
    QStringList deleteList;
    for (const QVariant &sessionIDs : strings) {
        QString sessionID = sessionIDs.toString();
        if(sessionID == QString::number(m_chat->getSession())){
            // stopreply之后不会触发自动朗读
            m_chat->soundFlag = false;
            onStopReply();
            onPauseRead();//若删除的对话为当前对话，则停止朗读
            if (speechMode == 2) {
                // 正在说话
                onCancelAudio();
            }

            Q_EMIT clearListModel();
            //若当前删除的对话为当前session则初始化session
            m_chat->initSystemChat();

        }
        KyInfo() << "删除的sessionID为:" << sessionID;
        m_database->deleteBySessionID(sessionID);
        deleteList.append(sessionID);
    }
    //调用前端页面删除
    Q_EMIT deleteDialogueList(deleteList);
}

QString CMsgPane::convertMarkDownToHtml(const QString &markDown)
{
    // 将markDown格式转换为html格式
    if(markDown.length() < 1){
        return "";
    }else{
        return markdownToHtml(markDown.toStdString());
    }
}

void CMsgPane::updateCurrentActiveModule(const int pageNumber)
{
    //根据显示界面的索引不同更新当前活跃模块内容
    switch (pageNumber) {
    case 0:
        m_activeModule = ActiveModule::MODULE_CHAT;
        break;
    case 1:
        m_activeModule = ActiveModule::MODULE_CHAT;
        break;
    case 2:
        m_activeModule = ActiveModule::MODULE_PLUGIN;
        break;
    case 4:
        m_activeModule = ActiveModule::MODULE_CHAT;
        break;
    default:
        m_activeModule = ActiveModule::MODULE_CHAT;
        break;
    }
}

void CMsgPane::initCurrentUser()
{
    // 初始化用户头像图标
    initCurrentUserIcon();
    initCurrentUserName();
}

void CMsgPane::closeSession()
{
    int history_id_database = m_database->selectMaxHistoryId();
    int history_id_settings = g_configManager->getConfigValue("history-id").toInt();
    m_chat->setSession((history_id_database >= history_id_settings ? history_id_database : history_id_settings));
    m_chat->initSystemChat();
    Q_EMIT changeSessionId(m_chat->getSession());
}


