#ifndef WRITINGTHREAD_H
#define WRITINGTHREAD_H

#include <QThread>
#include <QEventLoop>
#include <QJsonObject>
#include <QJsonDocument>
#include <QString>
#include <QClipboard>

#include <genai/text/chat.h>
#include <genai/text/modelinfo.h>
#include <ukui-log4qt.h>

#include "writingstyle.h"
#include "textselect/clipboard.h"
#include "documentreader.h"
#include "chatdatabase.h"

#define REQ_PARA_ERROR R"({"msgType": "error", "msgBody":{"errorMsg" : "Request parameter error."}})"

class CMainWnd;
class WritingThread : public QThread
{
    Q_OBJECT
public:
    explicit WritingThread(QObject *parent = nullptr);
    ~WritingThread();

    static WritingThread *getPtr(CMainWnd* mainWnd = nullptr);

    // 记录当前操作类型
    enum OperationType {
        OperationNone = 0,           // 无操作
        OperationExtractOutline,     // 提取大纲
        OperationExtractTone,        // 提取语气
        OperationGenerateOutline,    // 生成大纲
        OperationGenerateArticle,    // 生成文章
        OperationGenerateChapter     // 生成章节
    };
    Q_ENUM(OperationType)

    /* 所有异步消息都通过这个接口从QML端发送消息，禁止添加额外接口，应通过在参数里新增字段。该参数为一个json对象。
     * 遵守的格式如下，其中msgType为字符串，标识当前消息的分类。msgBody为一个json对象，用于携带具体的参数。
     * {"msgType":"xxx", "msgBody":{}}
     */
    Q_INVOKABLE void sendMessage(const QString message);

    /* 所有同步消息(即调用需要返回值的场景)都通过这个接口从QML端发送消息，禁止添加额外接口，应通过在参数里新增字段。该参数为一个json对象。
     * 遵守的格式如下，其中msgType为字符串，标识当前消息的分类。msgBody为一个json对象，用于携带具体的参数。
     * {"msgType":"xxx", "msgBody":{}}
     * 返回值格式为： {"msgType":"xxx", "msgBody":{}}
     */
    Q_INVOKABLE QString sendMessageSync(const QString message);

    // 获取模型列表
    QList<QJsonObject> getModelListSync();
    void fetchModelListAsync();

    // 设置模型
    void setModel(const QString &modelName);

    // 设置是否开启深度思考或联网搜索
    void setDeepThinking(bool checked);
    void setWebSearch(bool checked);

    // 会话ID管理
    Q_INVOKABLE int getSession() const;
    Q_INVOKABLE void setSession(int sessionId);

    // 保存消息到数据库
    Q_INVOKABLE void saveMessageToDatabase(int msgIndex, const QString &message);
    Q_INVOKABLE void saveMessageToDatabaseWithRequestData(int msgIndex, const QString &message, const QString &requestData);
    // 更新消息到数据库
    Q_INVOKABLE void updateMessageToDatabase(int msgIndex, const QString &message);
    // 从数据库获取请求数据并重新发送
    Q_INVOKABLE QString getRequestDataFromDatabase(const QString &sessionId, int msgIndex);
    // 从数据库删除指定索引的消息
    Q_INVOKABLE void deleteMessageFromDatabase(int msgIndex);
    // 解析文件内容，文件选择时立即解析
    Q_INVOKABLE QString parseFileContent(const QString &filePath);
    // 合并多个参考文件内容
    QString mergeReferenceContents(const QJsonValue &referencePaths, const QJsonValue &referenceContents);
    // 从请求数据重新发送消息
    Q_INVOKABLE void resendMessageFromRequestData(const QString &requestDataJson);

    // 提取Markdown大纲结构
    QString extractMarkdownOutline(const QString &markdownText);
    // HTML转纯文本
    Q_INVOKABLE QString htmlToPlainText(const QString &html);
    // Markdown转纯文本
    Q_INVOKABLE QString markdownToPlainText(const QString &markdown);
    // HTML转Markdown
    Q_INVOKABLE QString htmlToMarkdown(const QString &html);
    // 先提取大纲和语气，再生成
    void processWritingRequestWithExtraction(const QJsonObject &data);
    void continueAfterExtraction(const QJsonObject &originalData, const QString &extractedOutline, const QString &extractedTone);
    void stopReply();
    
    QJsonObject mPendingWritingRequest;   // 待处理的写作请求
    QString mExtractedOutline;            // 已提取的大纲
    QString mExtractedTone;               // 已提取的语气
    QString mCurrentOutlineBuffer;        // 当前大纲提取的流式缓冲区
    QString mCurrentToneBuffer;           // 当前语气提取的流式缓冲区
    bool mWaitingForOutlineExtraction = false;  // 是否等待大纲提取完成
    bool mWaitingForToneExtraction = false;     // 是否等待语气提取完成
    OperationType mCurrentOperation = OperationNone;  // 当前操作类型
    int mCurrentGeneratingChapterId = -1; // 当前正在生成的章节ID
signals:
    /* 所有异步消息都通过这个信号接口向QML端返回通知消息，禁止添加额外接口，应通过在参数里新增字段。该参数为一个json对象。
     * 遵守的格式如下，其中msgType为字符串，标识当前消息的分类。msgBody为一个json对象，用于携带具体的参数。
     * {"msgType":"xxx", "msgBody":{}}
     */
    void receiveMessage(const QString message);

    // 模型列表相关
    void modelListReceived(const QJsonArray &modelList);
    void modelListError(const QString &error);

    void sigWritingDeleteMessageAt(int msgIndex);  // 按照索引从知识库删除气泡

protected:
    void run();

private:
    void setMainWindow(CMainWnd* mainWnd);
    void initWritingThread();
    ChatModelConfig *createWritingSessionConfig();
    void sendChatMsg(const QJsonObject &data);
    void sendGenerateChapterMsg(const QJsonObject &data);
    void sendStopMsg(const QJsonObject &data);
    void sendClearHistory(const QJsonObject &data);
    void sendCopyText(const QJsonObject &data);
    void sendDownloadFile(const QJsonObject &data);

    // 模型列表相关方法
    void sendGetModelList(const QJsonObject &data);
    void sendSetModel(const QJsonObject &data);
    QJsonArray fetchModelList();

    // 设置是否开启深度思考或联网搜索
    void sendSetDeepThinking(const QJsonObject &data);
    void sendSetWebSearch(const QJsonObject &data);
    QString getOutline(const QJsonObject &msgBody);
    QString getWritingStyle(const QJsonObject &msgBody);
    QString getWordCount(const QJsonObject &msgBody);
    
    // 大纲和语气提取相关方法
    void sendExtractOutlineMsg(const QJsonObject &data);
    void sendExtractToneMsg(const QJsonObject &data);
    void sendGenerateOutlineMsg(const QJsonObject &data);
    void sendGenerateArticleMsg(const QJsonObject &data);
    void sendOrganizeOutlineMsg(const QJsonObject &data);
    QString filterOutlineContent(const QString &content);

    int ensureSessionInited();
    void emitWritingError(int errorCode);


private:
    ChatModelConfig *mWritingConfig = nullptr;
    GenAiTextSession *mWritingSession = nullptr;
    QClipboard *mClipboard = nullptr;
    CMainWnd* mMainWnd = nullptr;
    DocumentReader *mDocumentReader = nullptr;

    bool mIsCheckedThinking = false;
    bool mIsCheckedSearch = false;

    ChatDatabase *mDatabase = nullptr;  // 数据库
    int mWritingSessionID = 0;          // 写作会话ID
    int mSessionInitErrorCode = 0;      // genai_text_init_session 返回值，0 表示成功
};

#endif // WRITINGTHREAD_H
