#include "writingthread.h"
#include "../cmainwnd.h"
#include "../global/kaglobal.h"
#include <QtConcurrent>
#include <QtGui/QTextDocument>

static WritingThread *g_writingThread = nullptr;

void writingSessionCallback(ChatResult *result, void *userData) {
    KyInfo() << "writingSessionCallback";
    
    WritingThread *writing = WritingThread::getPtr();
    if (writing == NULL) {
        KyInfo() << "Writing thread not inited!";
        return;
    }

    // 检查错误码
    int errorCode = chat_result_get_error_code(result);
    if (errorCode != 0) {
        KyInfo() << "Writing error code: " << errorCode;
        
        QString errorMsg = "";
        QString translatedErrorMsg = Globals::getWritingErrorMsg(errorCode);
        if (!translatedErrorMsg.isEmpty() && translatedErrorMsg != QObject::tr("Unknown error, please restart the service or application.")) {
            errorMsg = translatedErrorMsg;
        } else {
            const char *errorMessage = chat_result_get_error_message(result);
            if (errorMessage != NULL && QString::fromUtf8(errorMessage).length() > 0 && errorCode >= 10000) {
                errorMsg = QString::fromUtf8(errorMessage);
            } else {
                errorMsg = QObject::tr("Unknown error, please restart the service or application.");
            }
        }
        
        // 构建错误消息
        QJsonObject msg;
        msg["msgType"] = "recvChatMsg";
        
        QJsonObject msgBody;
        msgBody["isEnd"] = true;
        msgBody["recvMsg"] = errorMsg;
        msgBody["errorCode"] = errorCode;
        
        // 检查是否为模型未找到错误
        if (errorCode == static_cast<int>(AI_COMMON_MODEL_NOT_FOUND)) {
            // 模型未配置
            errorMsg = QObject::tr("<span style=\"color:red\">There are currently no available large language model available.</span> \n\n 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.");
            msgBody["recvMsg"] = errorMsg;
            msgBody["noModelError"] = true;
            msgBody["colorMsg"] = "black";
        } else {
            msgBody["colorMsg"] = "red";
        }
        
        msgBody["model"] = "ai";
        msgBody["reasonMessage"] = "";
        msgBody["sentByUser"] = false;
        
        msg["msgBody"] = msgBody;
        
        Q_EMIT writing->receiveMessage(QString::fromUtf8(QJsonDocument(msg).toJson()));
        return;
    }

    const char *message = chat_result_get_assistant_message(result);
    if (message == NULL) {
        KyInfo() << "Cannot get chat message!";
        return;
    }

    KyInfo() << "Chat message: " << QString::fromUtf8(message);

    bool isEnd = chat_result_get_is_end(result);
    QString messageText = QString::fromUtf8(message);

    // 提取大纲
    if (writing->mCurrentOperation == WritingThread::OperationExtractOutline) {
        writing->mCurrentOutlineBuffer += messageText;

        if (isEnd) {
            QString rawOutline = writing->mCurrentOutlineBuffer;
            KyInfo() << "Outline extraction completed (raw): " << rawOutline;

            // 提取纯标题结构，去除正文和说明
            writing->mExtractedOutline = writing->extractMarkdownOutline(rawOutline);

            KyInfo() << "Outline extraction completed (cleaned): " << writing->mExtractedOutline;
            writing->mCurrentOutlineBuffer = "";
            writing->mWaitingForOutlineExtraction = false;
            writing->mCurrentOperation = WritingThread::OperationNone;

            if (!writing->mWaitingForToneExtraction) {
                // 所有提取完成，继续生成
                writing->continueAfterExtraction(writing->mPendingWritingRequest,
                                                 writing->mExtractedOutline,
                                                 writing->mExtractedTone);
                // 清空临时数据
                writing->mPendingWritingRequest = QJsonObject();
                writing->mExtractedOutline = "";
                writing->mExtractedTone = "";
            }
        }
        return; // 提取大纲的结果不发送给前端
    }

    // 提取语气
    if (writing->mCurrentOperation == WritingThread::OperationExtractTone) {
        writing->mCurrentToneBuffer += messageText;

        if (isEnd) {
            KyInfo() << "Tone extraction completed: " << writing->mCurrentToneBuffer;
            writing->mExtractedTone = writing->mCurrentToneBuffer.trimmed();
            writing->mCurrentToneBuffer = "";
            writing->mWaitingForToneExtraction = false;
            writing->mCurrentOperation = WritingThread::OperationNone;

            if (!writing->mWaitingForOutlineExtraction) {
                // 所有提取完成，继续生成
                writing->continueAfterExtraction(writing->mPendingWritingRequest,
                                                 writing->mExtractedOutline,
                                                 writing->mExtractedTone);
                // 清空临时数据
                writing->mPendingWritingRequest = QJsonObject();
                writing->mExtractedOutline = "";
                writing->mExtractedTone = "";
            }
        }
        return; // 提取语气的结果不发送给前端
    }

    // 生成文章/大纲/章节的回调
    QJsonObject msg;
    msg["msgType"] = "recvChatMsg";

    QJsonObject msgBody;
    msgBody["isEnd"] = isEnd;
    msgBody["recvMsg"] = messageText;
    
    // 如果是生成章节操作，在消息体中添加chapterId标识
    if (writing->mCurrentOperation == WritingThread::OperationGenerateChapter && 
        writing->mCurrentGeneratingChapterId != -1) {
        msgBody["chapterId"] = writing->mCurrentGeneratingChapterId;
        
        // 如果生成结束，重置操作类型和章节ID
        if (isEnd) {
            writing->mCurrentOperation = WritingThread::OperationNone;
            writing->mCurrentGeneratingChapterId = -1;
            KyInfo() << "Chapter generation completed, reset operation and chapterId";
        }
    }

    const char *model = chat_result_get_model_name(result);
    if (model == NULL) {
        KyInfo() << "Cannot get chat model!";
    }

    KyInfo() << "Writing model: " << QString::fromUtf8(model);

    if (QString::fromUtf8(model).length() == 0) {
        msgBody["model"] = "ai";
    } else {
        msgBody["model"] = model;
    }

    const char *reasonMessage = chat_result_get_reasoning_message(result);
    if ((reasonMessage != NULL) && (reasonMessage[0] != '\0')) {
        KyInfo() << "reasonMessage message: " << QString::fromUtf8(reasonMessage);
        msgBody["reasonMessage"] = reasonMessage;
    }

    // 处理搜索信息来源
    const ChatResultSearchInfo *searchInfo = chat_result_get_search_info(result, nullptr);
    if (searchInfo != nullptr) {
        size_t count = chat_result_search_info_get_count(searchInfo, nullptr);
        KyInfo() << "Search sources count: " << count;

        if (count > 0) {
            QJsonArray searchSourcesArray;
            for (size_t i = 0; i < count; i++) {
                const ChatResultSearchItem *item = chat_result_search_info_get_item(searchInfo, i, nullptr);
                if (item == nullptr) {
                    continue;
                }
                size_t index = chat_result_search_item_get_index(item, nullptr);
                std::string title = chat_result_search_item_get_title(item, nullptr);
                std::string url = chat_result_search_item_get_url(item, nullptr);

                KyInfo() << "Search result " << index << ": " << title.c_str() << " - " << url.c_str();

                QJsonObject sourceItem;
                sourceItem["index"] = static_cast<int>(index);
                sourceItem["title"] = QString::fromStdString(title);
                sourceItem["url"] = QString::fromStdString(url);
                searchSourcesArray.append(sourceItem);
            }

            // 如果有搜索来源，添加到消息体中
            if (searchSourcesArray.size() > 0) {
                QJsonObject sourcesData;
                sourcesData["webSearchSources"] = searchSourcesArray;
                msgBody["webSearchSources"] = QString::fromUtf8(QJsonDocument(sourcesData).toJson(QJsonDocument::Compact));
                KyInfo() << "Added webSearchSources to message body, count:" << searchSourcesArray.size();
            }
        }
    }

    msg["msgBody"] = msgBody;

    Q_EMIT writing->receiveMessage(QString::fromUtf8(QJsonDocument(msg).toJson()));

    return;
}

WritingThread::WritingThread(QObject *parent)
    : QThread (parent)
{
    mClipboard = QApplication::clipboard();
    if (mClipboard == nullptr) {
        KyInfo() << "Cannot get QApplication::clipboard!";
    }

    mDatabase = ChatDatabase::getChatDatabase();
    if (mDatabase == nullptr) {
        KyInfo() << "Cannot get ChatDatabase!";
    }

    mWritingSessionID = mDatabase->selectMaxWritingHistoryId();

    start();
}

WritingThread::~WritingThread()
{
    if ((mWritingSession == NULL) || (mWritingConfig == NULL)) {
        KyInfo() << "Writing session is not created!";
    } else {
        genai_text_stop_chat(mWritingSession);
        genai_text_destroy_session(&mWritingSession);
        chat_model_config_destroy(&mWritingConfig);
    }
}

WritingThread *WritingThread::getPtr(CMainWnd *mainWnd)
{
    if (g_writingThread == nullptr) {
        g_writingThread = new WritingThread();
    }
    // 通过实例调用非静态成员函数
    if (mainWnd) {
        g_writingThread->setMainWindow(mainWnd);
    }

    return g_writingThread;
}

void WritingThread::run()
{
    QEventLoop loop;

    initWritingThread();

    loop.exec();

    return;
}

ChatModelConfig *WritingThread::createWritingSessionConfig()
{
    ChatModelConfig *config = chat_model_config_create();
    if (config == NULL) {
        KyInfo() << "Failed to create model config!";
        return NULL;
    }

    return config;
}

void WritingThread::initWritingThread()
{
    mWritingSession = genai_text_create_session();
    if (mWritingSession == NULL) {
        KyInfo() << "*** Failed to create writing session!";
        return;
    }

    genai_text_set_model_config(mWritingSession, NULL);

    KyInfo() << "*** Start initWritingThread genai_text_init_session()";
    int ret = genai_text_init_session(mWritingSession);
    mSessionInitErrorCode = ret;
    if (ret != static_cast<int>(AI_COMMON_SUCCESS)) {
        KyInfo() << "*** Failed: genai_text_init_session failed at app init, error code:" << ret;
    }

    KyInfo() << "*** End initWritingThread genai_text_init_session()";

    genai_text_result_set_callback(mWritingSession, writingSessionCallback, NULL);

    return;
}

int WritingThread::ensureSessionInited()
{
    KyInfo() << "ensureSessionInited";
    if (mSessionInitErrorCode == static_cast<int>(AI_COMMON_SUCCESS)) {
        return 0;
    }

    if (mWritingSession == nullptr) {
        KyInfo() << "WritingSession is nullptr";
        return mSessionInitErrorCode;
    }

    KyInfo() << "genai_text_init_session need retry";
    int ret = genai_text_init_session(mWritingSession);
    if (ret == static_cast<int>(AI_COMMON_SUCCESS)) {
        mSessionInitErrorCode = 0;
        KyInfo() << "genai_text_init_session retry succeeded";
        return 0;
    }

    KyInfo() << "genai_text_init_session retry failed, error code:" << ret;
    return ret;
}

void WritingThread::emitWritingError(int errorCode)
{
    QString errorMsg = Globals::getWritingErrorMsg(errorCode);
    if (errorMsg.isEmpty() || errorMsg == QObject::tr("Unknown error, please restart the service or application.")) {
        errorMsg = QObject::tr("Unknown error, please restart the service or application.");
    }

    QJsonObject msg;
    msg["msgType"] = "recvChatMsg";

    QJsonObject msgBody;
    msgBody["isEnd"] = true;
    msgBody["recvMsg"] = errorMsg;
    msgBody["errorCode"] = errorCode;
    msgBody["colorMsg"] = "red";
    msgBody["model"] = "ai";
    msgBody["reasonMessage"] = "";
    msgBody["sentByUser"] = false;

    if (errorCode == static_cast<int>(AI_COMMON_MODEL_NOT_FOUND)) {
        errorMsg = QObject::tr("<span style=\"color:red\">There are currently no available large language model available.</span> \n\n 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.");
        msgBody["recvMsg"] = errorMsg;
        msgBody["noModelError"] = true;
        msgBody["colorMsg"] = "black";
    }

    msg["msgBody"] = msgBody;
    Q_EMIT receiveMessage(QString::fromUtf8(QJsonDocument(msg).toJson()));
}

void WritingThread::setMainWindow(CMainWnd *mainWnd)
{
    mMainWnd = mainWnd;

    return;
}

void WritingThread::setSession(int sessionId)
{
    mWritingSessionID = sessionId;
    return;
}

int WritingThread::getSession() const
{
    return mWritingSessionID;
}

void WritingThread::sendMessage(const QString message)
{
    QJsonObject data = QJsonDocument::fromJson(message.toUtf8()).object();

    if (!data.contains("msgType")) {
        KyInfo() << "Not carried msgType!";
        return;
    }

    if (!data["msgType"].isString()) {
        KyInfo() << "The type is not a string!";
        return;
    }

    QString msgType = data["msgType"].toString();

    // 发送前检查是否需要再次尝试init
    bool needSession = (msgType == "sendChatMsg" || msgType == "extractOutline" || msgType == "extractTone"
                        || msgType == "generateOutline" || msgType == "generateArticle" || msgType == "organizeOutline"
                        || msgType == "generateChapter");
    if (needSession) {
        int err = ensureSessionInited();
        if (err != 0) {
            emitWritingError(err);
            return;
        }
    }

    if (msgType == "sendChatMsg") {
        sendChatMsg(data);
        return;
    }

    // 提取大纲
    if (msgType == "extractOutline") {
        sendExtractOutlineMsg(data);
        return;
    }
    
    // 提取语气
    if (msgType == "extractTone") {
        sendExtractToneMsg(data);
        return;
    }
    
    // 生成大纲（步骤写作和逐个填空的第一步）
    if (msgType == "generateOutline") {
        sendGenerateOutlineMsg(data);
        return;
    }
    
    // 生成文章（步骤写作的第二步，或一气呵成)
    if (msgType == "generateArticle") {
        sendGenerateArticleMsg(data);
        return;
    }

    // 整理大纲（逐个填空的第二步）
    if (msgType == "organizeOutline") {
        sendOrganizeOutlineMsg(data);
        return;
    }

    // 单章节内容生成
    if (msgType == "generateChapter") {
        sendGenerateChapterMsg(data);
        return;
    }

    if (msgType == "sendStopMsg") {
        sendStopMsg(data);
        return;
    }

    if (msgType == "sendClearHistory") {
        sendClearHistory(data);
        return;
    }

    if (msgType == "sendCopyText") {
        sendCopyText(data);
        return;
    }
    //TODO:需要基于readercontrol逻辑实现朗读功能，当前逻辑建议删除
//    if (msgType == "sendReadText") {
//        sendReadText(data);
//        return;
//    }

//    if (msgType == "sendToPauseReading") {
//        sendToPauseReading(data);
//        return;
//    }

    if (msgType == "sendDownloadFile") {
        sendDownloadFile(data);
        return;
    }

    // 获取模型列表
    if (msgType == "getModelList") {
        sendGetModelList(data);
        return;
    }

    // 设置模型
    if (msgType == "setModel") {
        sendSetModel(data);
        return;
    }

    // 设置深度思考
    if (msgType == "setDeepThinking") {
        sendSetDeepThinking(data);
        return;
    }

    // 设置联网搜索
    if (msgType == "setWebSearch") {
        sendSetWebSearch(data);
        return;
    }

    return;
}

QString WritingThread::sendMessageSync(const QString message)
{
    QJsonObject data = QJsonDocument::fromJson(message.toUtf8()).object();

    if (!data.contains("msgType")) {
        KyInfo() << "Not carried msgType!";
        return REQ_PARA_ERROR;
    }

    if (!data["msgType"].isString()) {
        KyInfo() << "The type is not a string!";
        return REQ_PARA_ERROR;
    }

    QString msgType = data["msgType"].toString();

    // 提取Markdown大纲结构
    if (msgType == "extractMarkdownOutline") {
        if (!data.contains("msgBody")) {
            KyInfo() << "Not carried msgBody!";
            return REQ_PARA_ERROR;
        }

        QJsonObject msgBody = data["msgBody"].toObject();
        if (!msgBody.contains("markdownText") || !msgBody["markdownText"].isString()) {
            KyInfo() << "Not carried markdownText!";
            return REQ_PARA_ERROR;
        }

        QString markdownText = msgBody["markdownText"].toString();
        QString outline = extractMarkdownOutline(markdownText);

        QJsonObject result;
        result["msgType"] = "recvExtractMarkdownOutline";
        QJsonObject resultBody;
        resultBody["outline"] = outline;
        result["msgBody"] = resultBody;

        return QString::fromUtf8(QJsonDocument(result).toJson());
    }

    return REQ_PARA_ERROR;
}

// 获取模型列表
void WritingThread::sendGetModelList(const QJsonObject &data)
{
    KyInfo() << "sendGetModelList";

    // 异步获取模型列表
    fetchModelListAsync();
}

// 获取模型列表（同步）
QList<QJsonObject> WritingThread::getModelListSync()
{
    QList<QJsonObject> modelList;

    if (mWritingSession == nullptr) {
        KyInfo() << "Writing session not initialized!";
        return modelList;
    }

    int errorCode = 0;
    const TextModelList *textModelList = genai_text_get_model_list(mWritingSession, &errorCode);

    if (errorCode != 0 || textModelList == nullptr) {
        KyInfo() << "Failed to get model list, error code:" << errorCode;
        return modelList;
    }

    int count = genai_text_model_list_get_count(textModelList);
    KyInfo() << "Found" << count << "models";

    for (int i = 0; i < count; i++) {
        int modelError = 0;
        const TextModelInfo *modelInfo = genai_text_model_list_get_model_info(textModelList, i, &modelError);

        if (modelInfo == nullptr || modelError != 0) {
            KyInfo() << "Failed to get model info at index" << i;
            continue;
        }

        QJsonObject modelObj;

        // 获取模型名称
        const char *modelName = genai_text_model_info_get_model_name(modelInfo, &modelError);
        if (modelName != nullptr && modelError == 0) {
            modelObj["modelName"] = QString::fromUtf8(modelName);
        }

        // 获取显示名称
        const char *displayName = genai_text_model_info_get_display_name(modelInfo, &modelError);
        if (displayName != nullptr && modelError == 0) {
            modelObj["displayName"] = QString::fromUtf8(displayName);
        }

        // 获取部署类型
        ModelDeployType deployType = genai_text_model_info_get_deploy_type(modelInfo, &modelError);
        if (modelError == 0) {
            modelObj["deployType"] = static_cast<int>(deployType);

            // 添加部署类型字符串表示
            QString deployTypeStr;
            switch (deployType) {
                case ModelDeployType::PublicCloud:
                    deployTypeStr = "Cloud";
                    break;
                case ModelDeployType::PrivateCloud:
                    deployTypeStr = "Custom";
                    break;
                case ModelDeployType::OnDevice:
                    deployTypeStr = "Local";
                    break;
                default:
                    deployTypeStr = "Unknown";
                    break;
            }
            modelObj["deployTypeStr"] = deployTypeStr;
        }

        modelList.append(modelObj);
    }

    return modelList;
}

// 获取模型列表（异步）
void WritingThread::fetchModelListAsync()
{
    // 在线程中执行，避免阻塞主线程
    QtConcurrent::run([this]() {
        QJsonArray modelArray;
        QList<QJsonObject> modelList = getModelListSync();

        for (const QJsonObject &modelObj : modelList) {
            modelArray.append(modelObj);
        }

        if (!modelArray.isEmpty()) {
            KyInfo() << "Successfully fetched" << modelArray.size() << "models asynchronously" << modelArray;
            emit modelListReceived(modelArray);
        } else {
            emit modelListError("Failed to fetch model list or no models available");
        }
    });

    return;
}

// 设置模型
void WritingThread::sendSetModel(const QJsonObject &data)
{
    if (!data.contains("msgBody")) {
        KyInfo() << "Not carried msgBody!";
        return;
    }

    if (!data["msgBody"].isObject()) {
        KyInfo() << "The type is not an object!";
        return;
    }

    QJsonObject msgBody = data["msgBody"].toObject();
    if(!msgBody.contains("modelName") || !msgBody["modelName"].isString()) {
        KyInfo() << "Not carried modelName!";
        return;
    }

    QString modelName = msgBody["modelName"].toString();
    setModel(modelName);
}

// 设置模型
void WritingThread::setModel(const QString &modelName)
{
    if (mWritingSession == nullptr) {
        KyInfo() << "Writing session not initialized!";
        return;
    }

    if (mWritingConfig == nullptr) {
        mWritingConfig = createWritingSessionConfig();
    }

    if (mWritingConfig == nullptr) {
        KyInfo() << "Failed to create model config!";
        return;
    }

    // 设置模型名称
    chat_model_config_set_name(mWritingConfig, modelName.toUtf8().constData());

    // 设置深度思考和联网搜索
    chat_model_config_set_thinking_enabled(mWritingConfig, mIsCheckedThinking, nullptr);
    chat_model_config_set_web_search_enabled(mWritingConfig, mIsCheckedSearch, nullptr);

    // 应用到会话
    genai_text_set_model_config(mWritingSession, mWritingConfig);

    KyInfo() << "Model set to:" << modelName;
    return;
}

// 设置深度思考
void WritingThread::sendSetDeepThinking(const QJsonObject &data)
{
    if (!data.contains("msgBody")) {
        KyInfo() << "Not carried msgBody!";
        return;
    }

    if (!data["msgBody"].isObject()) {
        KyInfo() << "The type is not an object!";
        return;
    }

    QJsonObject msgBody = data["msgBody"].toObject();

    if(!msgBody.contains("deepThinking") || !msgBody["deepThinking"].isBool()) {
        KyInfo() << "Not carried deepThinking!";
        return;
    }

    bool isCheckedDeepThinking = msgBody["deepThinking"].toBool();
    setDeepThinking(isCheckedDeepThinking);
}

// 设置联网搜索
void WritingThread::sendSetWebSearch(const QJsonObject &data)
{
    if (!data.contains("msgBody")) {
        KyInfo() << "Not carried msgBody!";
        return;
    }

    if (!data["msgBody"].isObject()) {
        KyInfo() << "The type is not an object!";
        return;
    }

    QJsonObject msgBody = data["msgBody"].toObject();

    if(!msgBody.contains("webSearch") || !msgBody["webSearch"].isBool()) {
        KyInfo() << "Not carried webSearch!";
        return;
    }

    bool isCheckedWebSearch = msgBody["webSearch"].toBool();
    setWebSearch(isCheckedWebSearch);
}

// 设置深度思考
void WritingThread::setDeepThinking(bool checked)
{
    mIsCheckedThinking = checked;
    KyInfo() << "Writing DeepThinking set:" << mIsCheckedThinking;

    return;
}

// 设置联网搜索
void WritingThread::setWebSearch(bool checked)
{
    mIsCheckedSearch = checked;
    KyInfo() << "Writing WebSearch set:" << mIsCheckedSearch;

    return;
}

// 发送消息统一处理
void WritingThread::sendChatMsg(const QJsonObject &data)
{
    if (!data.contains("msgBody")) {
        KyInfo() << "Not carried msgBody!";
        return;
    }

    if (!data["msgBody"].isObject()) {
        KyInfo() << "The type is not an object!";
        return;
    }

    QJsonObject msgBody = data["msgBody"].toObject();
    if(!msgBody.contains("inputMsg") || !msgBody["inputMsg"].isString()) {
        KyInfo() << "Not carried inputMsg!";
        return;
    }

    QString inputMsg = msgBody["inputMsg"].toString();
    if (mWritingSession == NULL) {
        KyInfo() << "Writing session  not initialized!";
        return;
    }

    KyInfo() << "Writing inputMsg : " << inputMsg;

    bool needExtractOutline = false;
    bool needExtractTone = false;

    // 检查是否需要提取大纲
    if (msgBody.contains("outlinePath") && msgBody["outlinePath"].isString() && !msgBody["outlinePath"].toString().isEmpty()) {
        needExtractOutline = true;
    } else if (msgBody.contains("referencePath")) {
        bool hasReference = false;
        if (msgBody["referencePath"].isArray()) {
            QJsonArray refArray = msgBody["referencePath"].toArray();
            hasReference = !refArray.isEmpty();
        }

        if (hasReference) {
            // 没有结构大纲，有内容参考
            needExtractOutline = true;
        }
    }

    // 检查是否需要提取语气
    // 如果是本地文件（toneStylePath不为空），需要提取
    // 如果是已有语气（toneStylePath为空但toneStyleContent不为空），不需要提取，直接使用
    if (msgBody.contains("toneStylePath") && msgBody["toneStylePath"].isString() && !msgBody["toneStylePath"].toString().isEmpty()) {
        needExtractTone = true;
    } else if (msgBody.contains("toneStyleContent") && msgBody["toneStyleContent"].isString() && !msgBody["toneStyleContent"].toString().isEmpty()) {
        // 已有语气，不需要提取，直接使用content
        needExtractTone = false;
    }

    // 如果需要提取，使用分步提取流程
    if (needExtractOutline || needExtractTone) {
        processWritingRequestWithExtraction(data);
        return;
    }

    // 如果不需要提取，直接生成
    QString templateProperty = "";
    if (msgBody.contains("templateProperty") && msgBody["templateProperty"].isString()) {
        templateProperty = msgBody["templateProperty"].toString();
    }

    // 根据模板属性选择流程
    if (templateProperty == "一气呵成" || templateProperty.isEmpty()) {
        // 一气呵成：直接生成文章
        sendGenerateArticleMsg(data);
    } else if (templateProperty == "步骤写作" || templateProperty == "逐个填空") {
        // 步骤写作和逐个填空：先生成大纲
        sendGenerateOutlineMsg(data);
    } else {
        sendGenerateArticleMsg(data);
    }

    return;
}

// 停止回答
void WritingThread::sendStopMsg(const QJsonObject &data)
{
    KyInfo() << "sendStopMsg : ";

    if (mWritingSession == NULL) {
        KyInfo() << "Writing session not initialized!";
        return;
    }

    genai_text_stop_chat(mWritingSession);
    
    return;
}

// 清除历史
void WritingThread::sendClearHistory(const QJsonObject &data)
{
    KyInfo() << "sendClearHistory";
    if (mWritingSession == NULL) {
        KyInfo() << "Writing session not initialized!";
        return;
    }

    genai_text_clear_chat_history_messages(mWritingSession);

    return;
}

// 分步提取
void WritingThread::processWritingRequestWithExtraction(const QJsonObject &data)
{
    if (!data.contains("msgBody")) {
        KyInfo() << "Not carried msgBody!";
        return;
    }
    
    QJsonObject msgBody = data["msgBody"].toObject();
    if (!msgBody.contains("inputMsg") || !msgBody["inputMsg"].isString()) {
        KyInfo() << "Not carried inputMsg!";
        return;
    }
    
    QString inputMsg = msgBody["inputMsg"].toString();
    bool needExtractOutline = false;
    bool needExtractTone = false;
    QString outlineFileContent = "";
    QString toneFileContent = "";
    
    // 检查是否需要提取大纲
    if (msgBody.contains("outlinePath") && msgBody["outlinePath"].isString() && !msgBody["outlinePath"].toString().isEmpty()) {
        needExtractOutline = true;
        if (msgBody.contains("outlineContent") && !msgBody["outlineContent"].toString().isEmpty()) {
            outlineFileContent = msgBody["outlineContent"].toString();
        }
    } else if (msgBody.contains("referencePath")) {
        bool hasReference = false;
        if (msgBody["referencePath"].isArray()) {
            QJsonArray refArray = msgBody["referencePath"].toArray();
            hasReference = !refArray.isEmpty();
        }

        if (hasReference) {
            // 没有结构大纲，但有内容参考
            needExtractOutline = true;
            // 合并多个参考文件内容
            QJsonValue refPaths = msgBody["referencePath"];
            QJsonValue refContents = msgBody.contains("referenceContent") ? msgBody["referenceContent"] : QJsonValue();
            outlineFileContent = mergeReferenceContents(refPaths, refContents);
        }
    }
    
    // 检查是否需要提取语气
    // 如果是本地文件（toneStylePath不为空），需要提取
    // 如果是已有语气（toneStylePath为空但toneStyleContent不为空），不需要提取，直接使用
    if (msgBody.contains("toneStylePath") && msgBody["toneStylePath"].isString() && !msgBody["toneStylePath"].toString().isEmpty()) {
        needExtractTone = true;
        if (msgBody.contains("toneStyleContent") && !msgBody["toneStyleContent"].toString().isEmpty()) {
            toneFileContent = msgBody["toneStyleContent"].toString();
        }
    } else if (msgBody.contains("toneStyleContent") && msgBody["toneStyleContent"].isString() && !msgBody["toneStyleContent"].toString().isEmpty()) {
        // 已有语气，不需要提取，直接使用content
        needExtractTone = false;
        // 将已有语气的content直接设置为extractedTone，后续直接使用
        mExtractedTone = msgBody["toneStyleContent"].toString();
    }
    
    // 保存待处理的请求
    mPendingWritingRequest = data;
    mExtractedOutline = "";
    mExtractedTone = "";
    mWaitingForOutlineExtraction = false;
    mWaitingForToneExtraction = false;
    
    QString extractedOutline = "";
    QString extractedTone = "";
    
    // 提取大纲
    if (needExtractOutline && !outlineFileContent.isEmpty()) {
        // 提取标题结构
        extractedOutline = extractMarkdownOutline(outlineFileContent);
        
        KyInfo() << "******************extractMarkdownOutline****************************\n" << extractedOutline;
        // 文件较大（超过5000字符）或本地提取结果为空，使用模型提取
        if (outlineFileContent.length() > 5000 || extractedOutline.isEmpty()) {

            KyInfo() << "******************使用模型异步提取大纲****************************\n";
            // 使用模型异步提取大纲
            QJsonObject extractData;
            QJsonObject extractBody;
            extractBody["fileContent"] = outlineFileContent;
            extractBody["inputMsg"] = inputMsg;
            extractData["msgBody"] = extractBody;
            mWaitingForOutlineExtraction = true;
            sendExtractOutlineMsg(extractData);
            // 不在这里继续，等待回调
        } else {
            // 使用本地提取的结果
             KyInfo() << "******************使用本地提取的结果****************************\n";
            mExtractedOutline = extractedOutline;
        }
    }
    
    // 提取语气：如果文件不大，直接读取；如果文件较大，使用模型提取
    if (needExtractTone && !toneFileContent.isEmpty()) {
        if (toneFileContent.length() > 2000) {
            // 文件较大，使用模型异步提取语气
            QJsonObject extractData;
            QJsonObject extractBody;
            extractBody["fileContent"] = toneFileContent;
            extractData["msgBody"] = extractBody;
            mWaitingForToneExtraction = true;
            sendExtractToneMsg(extractData);
            // 不在这里继续，等待回调
        } else {
            // 文件较小，直接使用文件内容作为语气描述
            mExtractedTone = toneFileContent;
        }
    }
    
    // 如果都不需要异步提取，直接继续生成
    // 如果已有语气的content已经设置到mExtractedTone，使用它；否则使用空字符串
    if (!mWaitingForOutlineExtraction && !mWaitingForToneExtraction) {
        QString finalTone = mExtractedTone;
        // 如果mExtractedTone为空，但msgBody中有toneStyleContent（已有语气），使用它
        if (finalTone.isEmpty() && msgBody.contains("toneStyleContent") && !msgBody["toneStyleContent"].toString().isEmpty() && 
            (!msgBody.contains("toneStylePath") || msgBody["toneStylePath"].toString().isEmpty())) {
            finalTone = msgBody["toneStyleContent"].toString();
        }
        continueAfterExtraction(data, mExtractedOutline, finalTone);
        // 清空临时数据
        mPendingWritingRequest = QJsonObject();
        mExtractedOutline = "";
        mExtractedTone = "";
    }
}

// 提取大纲结构
QString WritingThread::extractMarkdownOutline(const QString &markdownText)
{
    if (markdownText.isEmpty()) {
        return QString("");
    }

    QStringList lines = markdownText.split("\n");
    QStringList result;

    // 用于处理 Setext 风格的标题（=== 和 ---）
    bool isPreviousLineText = false;
    QString previousLine = "";

    for (int i = 0; i < lines.size(); ++i) {
        const QString &line = lines[i];
        QString trimmedLine = line.trimmed();

        if (trimmedLine.isEmpty()) {
            isPreviousLineText = false;
            previousLine = "";
            continue;
        }

        // 匹配Markdown ATX风格的标题格式：支持 # 到 ######
        // 格式：1-6个#号，后跟一个或多个空格，然后是标题文本
        QRegExp atxHeadingRegex("^(#{1,6})\\s+(.+)$");

        if (atxHeadingRegex.exactMatch(trimmedLine)) {
            // 提取完整的标题行（包括#号和标题文本）
            result.append(trimmedLine);
            isPreviousLineText = false;
            previousLine = "";
        } else {
            // 检查是否是 Setext 风格的标题（一级标题用 ===，二级标题用 ---）
            // 这种格式：标题文本在上一行，当前行是分隔符
            if (i > 0 && !previousLine.isEmpty()) {
                QString currentLineTrimmed = trimmedLine;
                // 检查是否是分隔符行（全部是 = 或 -）
                QRegExp setextUnderlineRegex("^(=+|-+)$");
                if (setextUnderlineRegex.exactMatch(currentLineTrimmed)) {
                    // 判断是一级标题（===）还是二级标题（---）
                    if (currentLineTrimmed.startsWith("=")) {
                        result.append("# " + previousLine.trimmed());
                    } else if (currentLineTrimmed.startsWith("-")) {
                        result.append("## " + previousLine.trimmed());
                    }
                    isPreviousLineText = false;
                    previousLine = "";
                    continue;
                }
            }

            // 保存当前行，用于下一轮检查 Setext 风格标题
            isPreviousLineText = true;
            previousLine = trimmedLine;
        }
    }

    return result.join("\n");
}

// 提取大纲消息处理
void WritingThread::sendExtractOutlineMsg(const QJsonObject &data)
{
    if (!data.contains("msgBody")) {
        KyInfo() << "Not carried msgBody!";
        return;
    }

    QJsonObject msgBody = data["msgBody"].toObject();
    QString content = "";

    // 使用请求数据中的文件内容
    if (msgBody.contains("fileContent") && !msgBody["fileContent"].toString().isEmpty()) {
        content = msgBody["fileContent"].toString();
    }

    if (content.isEmpty()) {
        // 返回空大纲
        QJsonObject result;
        result["msgType"] = "recvExtractOutline";
        QJsonObject resultBody;
        resultBody["outline"] = "";
        result["msgBody"] = resultBody;
        Q_EMIT receiveMessage(QString::fromUtf8(QJsonDocument(result).toJson()));
        return;
    }

    // 设置当前操作类型为提取大纲
    mCurrentOperation = OperationExtractOutline;

    // 使用模型提取大纲
    QString inputMsg = msgBody.contains("inputMsg") ? msgBody["inputMsg"].toString() : "";
    QString prompt = QString("请从以下文档中提取文章的结构大纲，结合用户主题\"%1\"，只输出标题层级结构（使用Markdown格式，如 # 标题、## 章节等），不要包含正文内容。如果文档中没有明显的结构信息，请根据文档主题和用户主题生成一个合理的大纲结构：\n\n%2")
                     .arg(inputMsg)
                     .arg(content);

    KyInfo() << "****prompt*****" << prompt;

    if (mWritingSession == nullptr) {
        KyInfo() << "Writing session not initialized!";
        mCurrentOperation = OperationNone;
        return;
    }

    genai_text_chat_async(mWritingSession, prompt.toUtf8().constData());
}

// 提取语气消息处理
void WritingThread::sendExtractToneMsg(const QJsonObject &data)
{
    if (!data.contains("msgBody")) {
        KyInfo() << "Not carried msgBody!";
        return;
    }

    QJsonObject msgBody = data["msgBody"].toObject();
    QString content = "";

    // 使用请求数据中的文件内容
    if (msgBody.contains("fileContent") && !msgBody["fileContent"].toString().isEmpty()) {
        content = msgBody["fileContent"].toString();
    }

    if (content.isEmpty()) {
        // 返回默认语气
        QJsonObject result;
        result["msgType"] = "recvExtractTone";
        QJsonObject resultBody;
        resultBody["tone"] = "默认";
        result["msgBody"] = resultBody;
        Q_EMIT receiveMessage(QString::fromUtf8(QJsonDocument(result).toJson()));
        return;
    }

    // 设置当前操作类型为提取语气
    mCurrentOperation = OperationExtractTone;
    mCurrentToneBuffer = "";  // 清空缓冲区

    // 使用模型提取语气
    QString prompt = QString("请分析以下文本的语气风格特点，用简洁的词语描述（如：正式、轻松、专业、亲切、严谨等），只返回语气描述词，不要其他内容：\n\n%1").arg(content);

    if (mWritingSession == nullptr) {
        KyInfo() << "Writing session not initialized!";
        mCurrentOperation = OperationNone;
        return;
    }

    genai_text_chat_async(mWritingSession, prompt.toUtf8().constData());
}

// 提取完成后继续生成
void WritingThread::continueAfterExtraction(const QJsonObject &originalData, const QString &extractedOutline, const QString &extractedTone)
{
    QJsonObject msgBody = originalData["msgBody"].toObject();
    QString templateProperty = "";
    if (msgBody.contains("templateProperty") && msgBody["templateProperty"].isString()) {
        templateProperty = msgBody["templateProperty"].toString();
    }
    
    // 使用提取出的大纲和语气
    if (!extractedOutline.isEmpty()) {
        // 将提取的大纲存储到临时字段
        msgBody["extractedOutline"] = extractedOutline;
    }
    if (!extractedTone.isEmpty()) {
        msgBody["extractedTone"] = extractedTone;
    }
    
    QJsonObject updatedData = originalData;
    updatedData["msgBody"] = msgBody;
    
    // 判断是生成大纲还是生成文章
    if (templateProperty == "步骤写作" || templateProperty == "逐个填空") {
        sendGenerateOutlineMsg(updatedData);
    } else {
        sendGenerateArticleMsg(updatedData);
    }
}

void WritingThread::stopReply()
{
    QJsonObject jsonObj;
    sendStopMsg(jsonObj);
}

// 生成大纲（步骤写作和逐个填空的第一步）
void WritingThread::sendGenerateOutlineMsg(const QJsonObject &data)
{
    // 设置当前操作类型为生成大纲
    mCurrentOperation = OperationGenerateOutline;
    
    if (!data.contains("msgBody")) {
        KyInfo() << "Not carried msgBody!";
        mCurrentOperation = OperationNone;
        return;
    }
    
    QJsonObject msgBody = data["msgBody"].toObject();
    if (!msgBody.contains("inputMsg") || !msgBody["inputMsg"].isString()) {
        KyInfo() << "Not carried inputMsg!";
        return;
    }
    
    QString inputMsg = msgBody["inputMsg"].toString();
    QString reference = "";
    QString outline = "";
    QString writingStyle = "";
    QString wordLimit = "";
    
    // 获取内容参考（支持多个文件）
    QJsonValue refPaths = msgBody.contains("referencePath") ? msgBody["referencePath"] : QJsonValue();
    QJsonValue refContents = msgBody.contains("referenceContent") ? msgBody["referenceContent"] : QJsonValue();
    QString referenceContent = mergeReferenceContents(refPaths, refContents);
    if (!referenceContent.isEmpty()) {
        reference = QString("参考内容为: \"%1\"。").arg(referenceContent);
    }
    
    KyInfo() << "----------------extractedOutline-------------" << msgBody["extractedOutline"].toString();
    // 获取结构大纲（优先使用提取出的大纲，其次从结构大纲文件，最后使用模板预置大纲）
    bool hasOutlineFile = false;
    QString outlineFileContent = "";
    
    if (msgBody.contains("extractedOutline") && !msgBody["extractedOutline"].toString().isEmpty()) {
        // 使用已提取的大纲
        outlineFileContent = msgBody["extractedOutline"].toString();
        hasOutlineFile = true;
    } else if (msgBody.contains("outlineContent") && !msgBody["outlineContent"].toString().isEmpty()) {
        // 使用请求数据中的文件内容
        outlineFileContent = msgBody["outlineContent"].toString();
        if (!outlineFileContent.isEmpty()) {
            hasOutlineFile = true;
        }
    } else if (msgBody.contains("templateOutline") && msgBody["templateOutline"].isString() && !msgBody["templateOutline"].toString().isEmpty()) {
        // 使用模板预置大纲
        QString templateOutline = msgBody["templateOutline"].toString();
        if (mDocumentReader != nullptr) {
            outlineFileContent = mDocumentReader->getAllText(templateOutline);
            if (!outlineFileContent.isEmpty()) {
                hasOutlineFile = true;
            }
        }
    }
    
    // 获取语气风格
    // 优先使用提取的语气，其次使用已有语气的content，最后使用本地文件的content
    if (msgBody.contains("extractedTone") && !msgBody["extractedTone"].toString().isEmpty()) {
        writingStyle = QString("语气风格为: \"%1\"。").arg(msgBody["extractedTone"].toString());
    } else if (msgBody.contains("toneStyleContent") && !msgBody["toneStyleContent"].toString().isEmpty()) {
        // 已有语气或本地文件的content（已有语气时toneStylePath为空，本地文件时toneStylePath不为空）
        writingStyle = QString("语气风格为: \"%1\"。").arg(msgBody["toneStyleContent"].toString());
    }
    
    // 获取字数限制
    if (msgBody.contains("wordCount") && msgBody["wordCount"].isString() && !msgBody["wordCount"].toString().isEmpty()) {
        wordLimit = getWordCount(msgBody);
    }
    
    // 构建生成大纲的提示词
    QString prompt;
    
    KyInfo() << "----------------hasOutlineFile-------------" << hasOutlineFile;
    if (hasOutlineFile) {
        // 如果有结构大纲文件，优先提取其结构，并基于用户主题进行调整
        prompt = inputMsg;
        if (!reference.isEmpty()) {
            prompt += "。" + reference;
        }
        if (!writingStyle.isEmpty()) {
            prompt += "。" + writingStyle;
        }
        if (!wordLimit.isEmpty()) {
            prompt += "。" + wordLimit;
        }
        // 明确要求：严格按照参考文档的大纲结构，只调整标题内容以匹配用户主题
        prompt = QString("任务：根据以下主题和参考文档的结构大纲，生成符合主题的文章大纲。\n\n"
                        "主题：%1\n\n").arg(inputMsg);
        
        if (!reference.isEmpty()) {
            prompt += QString("内容参考：%1\n\n").arg(reference);
        }
        
        if (!writingStyle.isEmpty()) {
            prompt += QString("%1\n\n").arg(writingStyle);
        }
        
        if (!wordLimit.isEmpty()) {
            prompt += QString("%1\n\n").arg(wordLimit);
        }
        
        // 严格按照参考文档的大纲结构
        prompt += QString("参考文档的结构大纲：\n%1\n\n"
                         "要求：\n"
                         "1. 必须严格按照参考文档的标题层级结构（H1、H2、H3的层级关系和数量完全一致）\n"
                         "2. 只调整标题文本内容，使其符合当前主题\n"
                         "3. 标题层级最多到H3（###），绝对不要生成H4（####）或更深层级\n"
                         "4. 只输出标题结构，不要包含任何正文内容、说明文字或注释\n"
                         "5. 使用Markdown格式输出，格式为：# 标题、## 章节、### 小节\n"
                         "6. 每个标题单独占一行，即每个 #、##、### 标题后必须换行，不要把所有标题连在同一行\n"
                         "7. 如果参考文档中有说明文字（如\"与主题无关\"、\"以下为\"等），请忽略这些说明，只参考标题结构\n\n"
                         "请严格按照以上要求生成大纲，只输出标题结构，不要有任何其他内容。重要：直接输出Markdown标题，不要使用代码块（不要用```markdown或```包裹内容）。").arg(outlineFileContent);
    } else {
        // 如果没有结构大纲文件，根据用户输入和参考内容生成新大纲
        prompt = inputMsg;
        if (!reference.isEmpty()) {
            prompt += "。" + reference;
        }
        if (!writingStyle.isEmpty()) {
            prompt += "。" + writingStyle;
        }
        if (!wordLimit.isEmpty()) {
            prompt += "。" + wordLimit;
        }
        prompt += "。请生成文章的结构大纲，使用Markdown格式，包含文章标题（H1）和多层级的章节标题（H2、H3），标题层级最多到H3（###），绝对不要生成H4（####）或更深层级，只输出标题结构，不要包含正文内容、说明文字或注释。每个标题单独占一行，即每个 #、##、### 标题后必须换行，不要把所有标题连在同一行。重要：直接输出Markdown标题，不要使用代码块（不要用```markdown或```包裹内容）。";
    }
    
    if (mWritingSession == nullptr) {
        KyInfo() << "Writing session not initialized!";
        return;
    }
    
    KyInfo() << "Generate outline prompt: " << prompt;
    genai_text_chat_async(mWritingSession, prompt.toUtf8().constData());
}

// 生成文章（一气呵成，或步骤写作的第二步）
void WritingThread::sendGenerateArticleMsg(const QJsonObject &data)
{
    // 设置当前操作类型为生成文章
    mCurrentOperation = OperationGenerateArticle;
    
    if (!data.contains("msgBody")) {
        KyInfo() << "Not carried msgBody!";
        mCurrentOperation = OperationNone;
        return;
    }
    
    QJsonObject msgBody = data["msgBody"].toObject();
    if (!msgBody.contains("inputMsg") || !msgBody["inputMsg"].isString()) {
        KyInfo() << "Not carried inputMsg!";
        return;
    }
    
    QString inputMsg = msgBody["inputMsg"].toString();
    QString reference = "";
    QString outline = "";
    QString writingStyle = "";
    QString wordLimit = "";
    
    // 获取内容参考
    QJsonValue refPaths = QJsonValue();
    QJsonValue refContents = QJsonValue();
    
    if (msgBody.contains("referencePath")) {
        refPaths = msgBody["referencePath"];
    }
    if (msgBody.contains("referenceContent")) {
        refContents = msgBody["referenceContent"];
    }
    
    QString referenceContent = mergeReferenceContents(refPaths, refContents);
    if (!referenceContent.isEmpty()) {
        reference = QString("参考内容为: \"%1\"。").arg(referenceContent);
    }
    
    // 获取结构大纲
    if (msgBody.contains("outlineContent") && !msgBody["outlineContent"].toString().isEmpty()) {
        outline = QString("请严格按照下面的结构大纲中的章节生成文章，禁止添加大纲中不存在的任何章节。结构大纲为: \"%1\"。").arg(msgBody["outlineContent"].toString());
    }

    // 获取语气风格
    // 优先使用提取的语气，其次使用已有语气的content，最后使用本地文件的content
    if (msgBody.contains("extractedTone") && !msgBody["extractedTone"].toString().isEmpty()) {
        writingStyle = QString("语气风格为: \"%1\"。").arg(msgBody["extractedTone"].toString());
    } else if (msgBody.contains("toneStyleContent") && !msgBody["toneStyleContent"].toString().isEmpty()) {
        // 已有语气或本地文件的content（已有语气时toneStylePath为空，本地文件时toneStylePath不为空）
        writingStyle = QString("语气风格为: \"%1\"。").arg(msgBody["toneStyleContent"].toString());
    }
    
    // 获取字数限制
    if (msgBody.contains("wordCount") && msgBody["wordCount"].isString() && !msgBody["wordCount"].toString().isEmpty()) {
        wordLimit = getWordCount(msgBody);
    }
    
    // 构建生成文章的提示词
    QString prompt = inputMsg;
    if (!reference.isEmpty()) {
        prompt += "。" + reference;
    }
    if (!outline.isEmpty()) {
        prompt += "。" + outline;
    }
    if (!writingStyle.isEmpty()) {
        prompt += "。" + writingStyle;
    }
    if (!wordLimit.isEmpty()) {
        prompt += "。" + wordLimit;
    }

    if (!outline.isEmpty()) {
        prompt += "。请根据以上大纲的内容结构和意图生成完整的文章，使用Markdown格式，确保文章有标题（H1格式），标题在第一行，并包含完整的正文内容。如果大纲格式不规范或标题层级混乱，可以适当规范化标题层级和格式，但必须包含大纲中的所有内容点，不遗漏任何信息。重要约束：只能使用大纲中已列出的章节，严禁添加大纲中没有的任何章节或内容点。生成的文章必须严格限制在大纲规定的章节范围内，章节数量和标题必须与大纲完全一致，保持章节顺序与大纲的逻辑顺序一致。重要：直接输出Markdown正文，不要使用代码块（不要用```markdown或```包裹整段内容）。";
    } else {
        prompt += "。请按照以上要求生成完整的文章，使用Markdown格式，确保文章有标题（H1格式），标题在第一行，并包含完整的正文内容。重要：直接输出Markdown正文，不要使用代码块（不要用```markdown或```包裹整段内容）。";
    }
    
    if (mWritingSession == nullptr) {
        KyInfo() << "Writing session not initialized!";
        return;
    }
    
    KyInfo() << "Generate article prompt: " << prompt;
    genai_text_chat_async(mWritingSession, prompt.toUtf8().constData());
}

// 整理大纲（逐个填空的第二步）
void WritingThread::sendOrganizeOutlineMsg(const QJsonObject &data)
{
    // 设置当前操作类型为整理大纲
    mCurrentOperation = OperationGenerateOutline;  // 复用生成大纲的操作类型
    
    if (!data.contains("msgBody")) {
        KyInfo() << "Not carried msgBody!";
        mCurrentOperation = OperationNone;
        return;
    }
    
    QJsonObject msgBody = data["msgBody"].toObject();
    if (!msgBody.contains("outlineContent") || !msgBody["outlineContent"].isString()) {
        KyInfo() << "Not carried outlineContent!";
        return;
    }
    
    QString outlineContent = msgBody["outlineContent"].toString();
    QString inputMsg = msgBody.contains("inputMsg") ? msgBody["inputMsg"].toString() : "";
    
    // 构建整理大纲的提示词
    QString prompt = QString("任务：整理和规范化以下文章大纲，使其符合标准的Markdown标题格式。\n\n"
                            "用户编辑后的大纲内容：\n%1\n\n"
                            "要求：\n"
                            "1. 保留所有有效的标题内容，删除所有正文内容（非标题的段落文字）\n"
                            "2. 确保文章主标题存在（H1格式：## 或 #），如果缺失则根据内容补充\n"
                            "3. 确保至少有一个一级章节标题（H2格式：##），如果全部缺失则根据内容补充\n"
                            "4. 规范化标题层级：文章标题为H1（#），大章节为H2（##），小节为H3（###）\n"
                            "5. 移除所有文字样式标记（如加粗、斜体、下划线、删除线等），只保留纯文本标题\n"
                            "6. 移除所有颜色设置，只保留纯文本标题\n"
                            "7. 移除所有列表标记（有序列表、无序列表），将列表项转换为普通标题或删除\n"
                            "8. 确保标题格式正确：每个标题行以#号开头，后跟空格，然后是标题文本\n"
                            "9. 标题层级最多到H3（###），不要生成H4（####）或更深层级\n"
                            "10. 只输出整理后的标题结构，不要包含任何说明文字、注释或正文内容\n\n"
                            "请严格按照以上要求整理大纲，只输出标准的Markdown标题结构：").arg(outlineContent);
    
    if (!inputMsg.isEmpty()) {
        prompt = QString("任务：根据以下主题整理和规范化文章大纲，使其符合标准的Markdown标题格式。\n\n"
                        "主题：%1\n\n"
                        "用户编辑后的大纲内容：\n%2\n\n"
                        "要求：\n"
                        "1. 保留所有有效的标题内容，删除所有正文内容（非标题的段落文字）\n"
                        "2. 确保文章主标题存在（H1格式：#），如果缺失则根据主题补充\n"
                        "3. 确保至少有一个一级章节标题（H2格式：##），如果全部缺失则根据内容补充\n"
                        "4. 规范化标题层级：文章标题为H1（#），大章节为H2（##），小节为H3（###）\n"
                        "5. 移除所有文字样式标记（如加粗、斜体、下划线、删除线等），只保留纯文本标题\n"
                        "6. 移除所有颜色设置，只保留纯文本标题\n"
                        "7. 移除所有列表标记（有序列表、无序列表），将列表项转换为普通标题或删除\n"
                        "8. 确保标题格式正确：每个标题行以#号开头，后跟空格，然后是标题文本\n"
                        "9. 标题层级最多到H3（###），不要生成H4（####）或更深层级\n"
                        "10. 只输出整理后的标题结构，不要包含任何说明文字、注释或正文内容\n\n"
                        "请严格按照以上要求整理大纲，只输出标准的Markdown标题结构：").arg(inputMsg, outlineContent);
    }
    
    if (mWritingSession == nullptr) {
        KyInfo() << "Writing session not initialized!";
        return;
    }
    
    KyInfo() << "Organize outline prompt: " << prompt;
    genai_text_chat_async(mWritingSession, prompt.toUtf8().constData());
}

// 重新写作（重新生成大纲，或重新生成文档）
void WritingThread::resendMessageFromRequestData(const QString &requestDataJson)
{
    QJsonDocument doc = QJsonDocument::fromJson(requestDataJson.toUtf8());
    if (!doc.isObject()) {
        KyInfo() << "Invalid requestData JSON";
        return;
    }

    QJsonObject requestData = doc.object();

    // 构建发送消息
    QJsonObject writingMsg;
    writingMsg["msgType"] = "sendChatMsg";
    QJsonObject msgBody;

    // 从请求数据中提取字段
    if (requestData.contains("inputMsg")) {
        msgBody["inputMsg"] = requestData["inputMsg"];
    }

    if (requestData.contains("referencePath")) {
        msgBody["referencePath"] = requestData["referencePath"];
        // 如果有文件内容，也传递过去
        if (requestData.contains("referenceContent")) {
            msgBody["referenceContent"] = requestData["referenceContent"];
        }
    }

    if (requestData.contains("outlinePath")) {
        msgBody["outlinePath"] = requestData["outlinePath"];
        // 如果有文件内容，也传递过去
        if (requestData.contains("outlineContent")) {
            msgBody["outlineContent"] = requestData["outlineContent"];
        }
    }

    if (requestData.contains("toneStylePath")) {
        msgBody["toneStylePath"] = requestData["toneStylePath"];
        // 如果有文件内容，也传递过去
        if (requestData.contains("toneStyleContent")) {
            msgBody["toneStyleContent"] = requestData["toneStyleContent"];
        }
    }

    if (requestData.contains("wordCount")) {
        msgBody["wordCount"] = requestData["wordCount"];
    }

    if (requestData.contains("templateProperty")) {
        msgBody["templateProperty"] = requestData["templateProperty"];
    }

    if (requestData.contains("templateOutline")) {
        msgBody["templateOutline"] = requestData["templateOutline"];
    }

    if (requestData.contains("templateId")) {
        msgBody["templateId"] = requestData["templateId"];
    }

    if (requestData.contains("templateName")) {
        msgBody["templateName"] = requestData["templateName"];
    }

    writingMsg["msgBody"] = msgBody;

    // 发送消息
    sendChatMsg(writingMsg);
}

// 单章节生成
void WritingThread::sendGenerateChapterMsg(const QJsonObject &data)
{
    // 设置当前操作类型为生成章节
    mCurrentOperation = OperationGenerateChapter;

    if (!data.contains("msgBody")) {
        KyInfo() << "Not carried msgBody!";
        mCurrentOperation = OperationNone;
        return;
    }

    if (!data["msgBody"].isObject()) {
        KyInfo() << "The type is not an object!";
        return;
    }

    QJsonObject msgBody = data["msgBody"].toObject();
    if (!msgBody.contains("chapterId") || !msgBody["chapterId"].isDouble()
        || !msgBody.contains("title") || !msgBody["title"].isString()
        || !msgBody.contains("outline") || !msgBody["outline"].isString()) {
        KyInfo() << "Missing required params for generateChapter!";
        return;
    }

    int chapterId = msgBody["chapterId"].toInt();
    QString chapterTitle = msgBody["title"].toString();
    QString fullOutline = msgBody["outline"].toString(); // 完整大纲（上下文）
    bool isTitle = msgBody.contains("isTitle") && msgBody["isTitle"].toBool(); // 是否为标题卡片
    
    // 保存当前生成的章节ID，用于回调时标识
    mCurrentGeneratingChapterId = chapterId;

    // 根据是否为标题卡片，生成不同的提示词
    QString prompt;
    if (isTitle) {
        // 标题卡片的提示词：只生成H1格式的标题
        prompt = QString(R"(
任务：根据以下信息重新生成文章标题，确保标题准确、简洁、有吸引力。

1. 用户输入的主题或要求：
%1

2. 完整大纲结构：
%2

3. 当前需要生成的标题（仅供参考，需要重新生成）：
%3

4. 生成要求：
- **仅生成文章主标题**，不要生成任何其他内容（如副标题、章节内容等）；
- 标题应该准确反映文章主题和内容；
- 标题应该简洁明了，长度适中（建议10-20字）；
- 标题应该具有吸引力和概括性；
- **必须使用H1格式输出**：以"# "开头（一个#号加一个空格），后跟标题文本（例如："# 文章标题"）；
- **重要**：只输出一个#号，不要输出多个#号（如"##"或"# #"）；
- **注意**：上面第3点中的标题格式仅供参考，你需要重新生成新的标题，不要直接复制或修改原有格式；
- 不要生成大纲中的章节标题或其他内容；
- **重要**：直接输出标题文本，不要使用代码块（不要用```markdown或```包裹内容）。

请严格按照以上要求，只生成H1格式的文章主标题（格式：一个#号+空格+标题文本）：
)").arg(msgBody.contains("inputMsg") ? msgBody["inputMsg"].toString() : "")
          .arg(fullOutline)
          .arg(chapterTitle);
    } else {
        // 章节卡片的提示词：生成章节内容（必须包含标题和markdown格式）
        QString wordCountStr = "";
        if (msgBody.contains("wordCount") && !msgBody["wordCount"].toString().isEmpty()) {
            QString wordCount = msgBody["wordCount"].toString();
            // 计算当前章节应该生成的字数
            // 解析大纲，统计章节数量
            int chapterCount = 0;
            QStringList lines = fullOutline.split("\n");
            for (const QString &line : lines) {
                QString trimmed = line.trimmed();
                if (trimmed.startsWith("## ") && !trimmed.startsWith("###")) {
                    chapterCount++;  // 统计二级标题数量
                }
            }
            if (chapterCount > 0) {
                // 根据总字数和章节数量，计算每个章节的平均字数
                // 这里假设每个章节字数相近，实际可以根据章节层级调整
                int totalWords = wordCount.toInt();
                int avgWordsPerChapter = totalWords / chapterCount;
                // 当前章节的字数可以设置为平均字数，或者根据章节层级调整
                wordCountStr = QString("\n\n5. 字数要求：\n- 文章总字数要求：%1字\n- 当前章节建议字数：约%2字（根据总字数和章节数量分配）").arg(wordCount).arg(avgWordsPerChapter);
            } else {
                wordCountStr = QString("\n\n5. 字数要求：\n- 文章总字数要求：%1字\n- 请根据总字数合理分配当前章节的字数").arg(wordCount);
            }
        }
        
        prompt = QString(R"(
任务：为以下章节生成详细内容，需贴合全文主题和大纲逻辑。

1. 用户输入的主题或要求：
%1

2. 完整大纲结构：
%2

3. 当前需要生成的章节：
%3

4. 生成要求：
- **必须严格按照章节标题的层级和格式输出**：
  * 首先输出完整的章节标题（包括该章节下的所有子标题），保持原有的Markdown格式和层级（##、###等）；
  * 然后在每个标题下方生成对应的正文内容；
- 内容紧扣章节标题，不偏离大纲框架；
- 根据章节标题的层级和内容，生成相应的详细内容：
  * 如果是二级标题（##），生成该大章节的概述性内容，并在其下的三级标题（###）后生成对应的具体内容；
  * 如果是三级标题（###），生成该小节的具体内容；
- 内容应该逻辑清晰、论据充分、语言流畅；
- 避免重复其他章节可能涉及的内容；
- **格式要求**：
  * 必须包含完整的章节标题结构（包括所有子标题），使用Markdown格式（##、###等）；
  * 每个标题下方生成对应的正文内容；
  * 正文内容使用Markdown格式（段落、列表、加粗等）；
- 不要生成其他章节的内容，只专注于当前章节；
- **重要**：直接输出Markdown正文，不要使用代码块（不要用```markdown或```包裹整段内容）。%4

请严格按照以上要求，生成包含完整标题结构和内容的章节内容：
)").arg(msgBody.contains("inputMsg") ? msgBody["inputMsg"].toString() : "")
          .arg(fullOutline)
          .arg(chapterTitle)
          .arg(wordCountStr);
    }

    KyInfo() << "GenerateChapter Prompt: " << prompt;

    if (mWritingSession == NULL) {
        KyInfo() << "Writing session not initialized!";
        return;
    }

    genai_text_chat_async(mWritingSession, prompt.toUtf8().constData());
}

// 保存消息到数据库
void WritingThread::saveMessageToDatabase(int msgIndex, const QString &message)
{
    if (mDatabase == nullptr) {
        KyInfo() << "Database not initialized!";
        return;
    }

    int curId = this->getSession();
    QString writingAddressString = QString("w_") + QString::number(curId);
    mDatabase->insertOne(writingAddressString, msgIndex, message, 3); // chatType=3 表示写作对话
    mDatabase->updateOperateTime(writingAddressString, msgIndex); // 更新第一条数据的operatime

    int writing_id_database = mDatabase->selectMaxWritingHistoryId();
    int writing_id_settings = ConfigManager::getInstance()->getConfigValue("writing-id").toInt();
    int maxWritingId = (writing_id_database >= writing_id_settings ? writing_id_database : writing_id_settings);
    KyInfo() << "Writing saveMessageToDatabase: curId=" << curId << ", writing_id_database=" << writing_id_database
             << ", writing_id_settings=" << writing_id_settings << ", maxWritingId=" << maxWritingId;
    if (curId == maxWritingId) {
        // 如果是新对话的第一条消息，更新最大history_id为下一个值
        int newMaxWritingId = maxWritingId + 1;
        KyInfo() << "Writing: Updating maxWritingHistoryId from" << maxWritingId << "to" << newMaxWritingId;
        mDatabase->updateMaxWritingHistoryId(newMaxWritingId);
    }

    return;
}

// 保存消息和请求数据到数据库
void WritingThread::saveMessageToDatabaseWithRequestData(int msgIndex, const QString &message, const QString &requestData)
{
    if (mDatabase == nullptr) {
        KyInfo() << "Database not initialized!";
        return;
    }

    int curId = this->getSession();
    QString writingAddressString = QString("w_") + QString::number(curId);
    mDatabase->insertOneWithRequestData(writingAddressString, msgIndex, message, 3, requestData); // chatType=3 表示写作对话
    mDatabase->updateOperateTime(writingAddressString, msgIndex); // 更新第一条数据的operatime

    int writing_id_database = mDatabase->selectMaxWritingHistoryId();
    int writing_id_settings = ConfigManager::getInstance()->getConfigValue("writing-id").toInt();
    int maxWritingId = (writing_id_database >= writing_id_settings ? writing_id_database : writing_id_settings);
    KyInfo() << "Writing saveMessageToDatabase: curId=" << curId << ", writing_id_database=" << writing_id_database
             << ", writing_id_settings=" << writing_id_settings << ", maxWritingId=" << maxWritingId;
    if (curId == maxWritingId) {
        // 如果是新对话的第一条消息，更新最大history_id为下一个值
        int newMaxWritingId = maxWritingId + 1;
        KyInfo() << "Writing: Updating maxWritingHistoryId from" << maxWritingId << "to" << newMaxWritingId;
        mDatabase->updateMaxWritingHistoryId(newMaxWritingId);
    }

    return;
}

// 获取之前对话的请求数据
QString WritingThread::getRequestDataFromDatabase(const QString &sessionId, int msgIndex)
{
    if (mDatabase == nullptr) {
        KyInfo() << "Database not initialized!";
        return QString();
    }
    
    return mDatabase->selectRequestDataBySessionIDAndIndex(sessionId, msgIndex);
}

// 从数据库删除指定索引的消息
void WritingThread::deleteMessageFromDatabase(int msgIndex)
{
    if (mDatabase == nullptr) {
        KyInfo() << "Database not initialized!";
        return;
    }

    int curId = this->getSession();
    QString addressAsString = QString::number(curId);
    addressAsString.prepend("w_");
    mDatabase->deleteBySessionIDAndIndex(addressAsString, msgIndex);
    Q_EMIT sigWritingDeleteMessageAt(msgIndex);
}

void WritingThread::updateMessageToDatabase(int msgIndex, const QString &message)
{
    if (mDatabase == nullptr) {
        KyInfo() << "Database not initialized!";
        return;
    }

    int curId = this->getSession();
    QString writingAddressString = QString("w_") + QString::number(curId);
    mDatabase->updateFeedback(writingAddressString, msgIndex, message);
    mDatabase->updateOperateTime(writingAddressString, msgIndex); // 更新操作时间

    return;
}

// 提取文件内容
QString WritingThread::parseFileContent(const QString &filePath)
{
    if (filePath.isEmpty()) {
        return QString();
    }

    if (mDocumentReader == nullptr) {
        KyInfo() << "DocumentReader not initialized!";
        return QString();
    }

    QString content = mDocumentReader->getAllText(filePath);
    return content;
}

// 合并内容参考
QString WritingThread::mergeReferenceContents(const QJsonValue &referencePaths, const QJsonValue &referenceContents)
{
    QStringList mergedContents;

    if (referenceContents.isArray()) {
        QJsonArray contentArray = referenceContents.toArray();
        for (int i = 0; i < contentArray.size(); i++) {
            QString content = contentArray[i].toString();
            if (!content.isEmpty()) {
                mergedContents.append(content);
            }
        }
    } else if (referenceContents.isString()) {
        QString content = referenceContents.toString();
        if (!content.isEmpty()) {
            mergedContents.append(content);
        }
    }

    // 如果 referenceContents 为空或不完整，从 referencePaths 读取
    if (mergedContents.isEmpty() || (referencePaths.isArray() && referencePaths.toArray().size() > mergedContents.size())) {
        QJsonArray pathArray;
        if (referencePaths.isArray()) {
            pathArray = referencePaths.toArray();
        }

        for (int i = 0; i < pathArray.size(); i++) {
            QString filePath = pathArray[i].toString();
            if (!filePath.isEmpty() && mDocumentReader != nullptr) {
                QString content = mDocumentReader->getAllText(filePath);
                if (!content.isEmpty()) {
                    if (i >= mergedContents.size()) {
                        mergedContents.append(content);
                    }
                }
            }
        }
    }

    // 合并所有内容，用换行分隔
    return mergedContents.join("\n\n");
}

// 解析字数
QString WritingThread::getWordCount(const QJsonObject &msgBody)
{
    if (msgBody["wordCount"].toString().isEmpty()) {
        // 如果没有传入字数限制，输入给模型的时候也不做字数限制。
        return QString("");
    }

    QString pageStr = msgBody["wordCount"].toString();

    // 清理输入字符串，移除空格和"页"字
    QString cleanStr = pageStr.trimmed();
    cleanStr = cleanStr.remove(" 页");

    QString startWords = "";
    QString endWords = "";
    if (cleanStr.contains("-")) {
        QStringList parts = cleanStr.split("-");

        if (parts.size() == 2) {
            QString startPage = parts.at(0);
            QString endPage = parts.at(1);

            // 检查是否为纯数字
            int startNum = startPage.toInt();
            int endNum = endPage.toInt();

            startWords = QString::number(startNum * 1000);
            endWords = QString::number(endNum * 1000);
            return QString("字数为: %1字到 %2字。").arg(startWords).arg(endWords);
        }
    } else {
        // 单个页码
        int pageNum = cleanStr.toInt();
        startWords = QString::number(pageNum * 1000);
        return QString("字数为: %1字。").arg(startWords);
    }

}

// 写作复制
void WritingThread::sendCopyText(const QJsonObject &data)
{
    KyInfo() << "sendCopyText : ";

    if (!data.contains("msgBody")) {
        KyInfo() << "Not carried msgBody!";
        return;
    }

    if (!data["msgBody"].isObject()) {
        KyInfo() << "The type is not an object!";
        return;
    }

    QJsonObject msgBody = data["msgBody"].toObject();
    if(!msgBody.contains("copyText") || !msgBody["copyText"].isString()) {
        KyInfo() << "Not carried copyText!";
        return;
    }

    QString copyText = msgBody["copyText"].toString();

    KyInfo() << "sendCopyText : " << copyText;

    if (mClipboard == nullptr) {
        KyInfo() << "Clipboard not initialized!";
        return;
    }

    mClipboard->setText(copyText);

    return;
}

// HTML转纯文本
QString WritingThread::htmlToPlainText(const QString &html)
{
    if (html.isEmpty()) {
        return QString();
    }
    
    QTextDocument document;
    document.setHtml(html);
    return document.toPlainText();
}

// Markdown转纯文本
QString WritingThread::markdownToPlainText(const QString &markdown)
{
    if (markdown.isEmpty()) {
        return QString();
    }

    QTextDocument document;
    document.setMarkdown(markdown);
    return document.toPlainText().trimmed();
}

// HTML转Markdown
QString WritingThread::htmlToMarkdown(const QString &html)
{
    if (html.isEmpty()) {
        return QString();
    }
    
    QTextDocument document;
    document.setHtml(html);
    return document.toMarkdown();
}

// 导出文档
void WritingThread::sendDownloadFile(const QJsonObject &data)
{
    if (!data.contains("msgBody")) {
        KyInfo() << "Not carried msgBody!";
        return;
    }

    if (!data["msgBody"].isObject()) {
        KyInfo() << "The type is not an object!";
        return;
    }

    QJsonObject msgBody = data["msgBody"].toObject();

    if(!msgBody.contains("docName") || !msgBody["docName"].isString()) {
        KyInfo() << "Not carried docName!";
        return;
    }

    QString docName = msgBody["docName"].toString();
    KyInfo() << "Writing docName : " << docName;

    if(!msgBody.contains("docContent") || !msgBody["docContent"].isString()) {
        KyInfo() << "Not carried docContent!";
        return;
    }

    QString docContent = msgBody["docContent"].toString();
    KyInfo() << "Writing docContent : " << docContent;


    if(!msgBody.contains("type") || !msgBody["type"].isDouble()) {
        KyInfo() << "Not carried type!";
        return;
    }

    int type = msgBody["type"].toInt();
    KyInfo() << "Writing Download type : " << type;

    mMainWnd->onWritingDownloadFile(type, docName, docContent);

    return;
}
