#include "ctai_curl.h"

ctai_curl::ctai_curl() : m_curl(nullptr),
                         m_headers(nullptr),
                         m_initialized(false) // 初始化标志
{
}
ctai_curl::~ctai_curl()
{
    if (m_curl != nullptr)
    {
        curl_easy_cleanup(m_curl);
        m_curl = nullptr; // 可选，避免野指针
    }
}
// 流式输出回调
size_t stream_callback(void *buffer, size_t sz, size_t nmemb, void *userdata)
{
    auto ctx = static_cast<call_back_context *>(userdata);
    std::lock_guard<std::mutex> lock(ctx->instance->m_mutex);
    size_t size = sz * nmemb;
    std::string chunk(static_cast<char *>(buffer), size);
    if (ctx->m_data.postback_stream_mode)
    {
        ctx->instance->send_stream(ctx->m_data, chunk);
    }
    //qDebug() << "steam data chunk:" << chunk;
    return sz * nmemb;
}
// 非流式输出回调
size_t not_stream_callback(void *buffer, size_t sz, size_t nmemb, void *userdata)
{
    std::string *psResponse = static_cast<std::string *>(userdata);
    size_t size = sz * nmemb;
    psResponse->append(static_cast<char *>(buffer), size);
    //qDebug() << "not steam data chunk:" << *psResponse;
    return sz * nmemb;
}
void ctai_curl::set_send_post_headers(std::string head_str)
{
    m_headers = curl_slist_append(m_headers, head_str.c_str());
    qDebug() << "header:" << head_str;
    curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, m_headers);
}

void ctai_curl::set_curl_ssl(bool ssl_state)
{
    std::string ca_bundle = QDir::currentPath().toStdString() + "/cert/cacert.pem";
    if (ssl_state)
    {
        curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 2L);
        curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYHOST, 1L);
        curl_easy_setopt(m_curl, CURLOPT_CAINFO, ca_bundle.c_str());
    }
    else
    {
        curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L);
        curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYHOST, 0L);
        ssl_state = false;
    }
    qDebug() << "curl opts ssl:" << ssl_state << "ssl_pem:" << ca_bundle;
}
void ctai_curl::set_curl_timeout(int time)
{
    curl_easy_setopt(m_curl, CURLOPT_TIMEOUT, time);
    qDebug() << "curl opts timeout:" << time;
}
void ctai_curl::set_curl_followlocation(bool followlocation_state)
{
    if (followlocation_state)
    {
        curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1L);
    }
    else
    {
        curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 0L);
    }
    qDebug() << "curl opts followlocation_state:" << followlocation_state;
}
void ctai_curl::set_curl_debug_verbose(bool verbose_state)
{
    if (verbose_state)
    {
        curl_easy_setopt(m_curl, CURLOPT_VERBOSE, 1L);
    }
    else
    {
        curl_easy_setopt(m_curl, CURLOPT_VERBOSE, 0L);
    }
    qDebug() << "curl opts verbose_state:" << verbose_state;
}
void ctai_curl::set_curl_tcp_keepalive(bool keepalive_state)
{
    if (keepalive_state)
    {
        curl_easy_setopt(m_curl, CURLOPT_TCP_KEEPALIVE, 1L);
        // 空闲 60 秒后探测
        curl_easy_setopt(m_curl, CURLOPT_TCP_KEEPIDLE, 60L);
        // 每 10 秒探测一次
        curl_easy_setopt(m_curl, CURLOPT_TCP_KEEPINTVL, 10L);
        // 最多探测 3 次
        curl_easy_setopt(m_curl, CURLOPT_TCP_KEEPCNT, 3L);
    }
    else
    {
        curl_easy_setopt(m_curl, CURLOPT_TCP_KEEPALIVE, 0L);
    }
    qDebug() << "curl opts keepalive_state:" << keepalive_state;
}

std::vector<std::string> ctai_curl::steam_extract(const std::string &input)
{
    std::vector<std::string> result;
    // 定义正则表达式模式，用于匹配 data: 和 \n\n 之间的内容
    std::regex pattern(R"(data:(.*?)\n\n)");
    auto words_begin = std::sregex_iterator(input.begin(), input.end(), pattern);
    auto words_end = std::sregex_iterator();

    // 遍历所有匹配结果
    for (std::sregex_iterator i = words_begin; i != words_end; ++i)
    {
        std::smatch match = *i;
        // 提取捕获组中的内容
        result.push_back(match.str(1));
    }
    return result;
}
std::string ctai_curl::send_timestamp_to_time(time_t timestamp)
{
    // 将时间戳转换为 QDateTime 对象
    QDateTime dateTime = QDateTime::fromSecsSinceEpoch(timestamp);
    return dateTime.toString("yyyy-MM-dd hh:mm:ss").toStdString();
}
void ctai_curl::send_stream(model_data &data, std::string response_data)
{
    std::vector<std::string> _info_data = steam_extract(response_data);
    if (!_info_data.empty())
    {
        for (auto str : _info_data)
        {
            if (str == "[DONE]")
            {
                data.postback_model_data = str;
                emit send_post_out_data(data);
                return;
            }
            if (str != "")
            {
                send_not_stream(data, str);
                emit send_post_out_data(data);
            }
        }
    }
}
void ctai_curl::send_not_stream(model_data &data, std::string response_data)
{
    json response = json::parse(response_data);
    if (data.postback_stream_mode)
    {
        if (response.contains("choices") && !response["choices"].empty())
        {
            data.postback_model_data = response["choices"][0]["delta"]["content"];
        }
    }
    else
    {
        if (response.contains("choices") && !response["choices"].empty())
        {
            data.postback_model_data = response["choices"][0]["message"]["content"];
        }
    }
    // 获取时间戳自动转换为时间
    if (response.contains("created") && !response["created"].empty())
    {
        data.postback_time = send_timestamp_to_time(response["created"]);
    }
    // 任务ID
    if (response.contains("id") && !response["id"].empty())
    {
        data.postback_send_id = response["id"];
    }
    // 任务指纹
    if (response.contains("system_fingerprint") && !response["system_fingerprint"].empty())
    {
        data.postback_system_fingerprint = response["system_fingerprint"];
    }
    // 生成模型
    if (response.contains("model") && !response["model"].empty())
    {
        data.postback_server_model = response["model"];
    }
    // 数据信息
    if (response.contains("usage") && !response["usage"].empty())
    {
        if (response["usage"].contains("prompt_tokens"))
        {
            data.postback_prompt_tokens = response["usage"]["prompt_tokens"];
        }
        if (response["usage"].contains("completion_tokens"))
        {
            data.postback_completion_tokens = response["usage"]["completion_tokens"];
        }
        if (response["usage"].contains("total_tokens"))
        {
            data.postback_total_tokens = response["usage"]["total_tokens"];
        }
        if (response["usage"].contains("prompt_cache_hit_tokens"))
        {
            data.postback_prompt_cache_hit_tokens = response["usage"]["prompt_cache_hit_tokens"];
        }
        if (response["usage"].contains("prompt_cache_miss_tokens"))
        {
            data.postback_prompt_cache_hit_tokens = response["usage"]["prompt_cache_miss_tokens"];
        }
    }
}
std::string ctai_curl::send_send_body(model_data m_data)
{
    json _request_body = {
        {"model", m_data.user_model},
        {"messages", {{{"role", "user"}, {"content", m_data.send_user_data}}}},
        {"temperature", 0.7},
        {"stream", m_data.postback_stream_mode}};
    qDebug() << "request_body_str:" << _request_body.dump(4);
    return _request_body.dump();
}
void ctai_curl::set_send_post_option()
{
    set_curl_ssl(c_opts.ssl_state);
    set_curl_timeout(c_opts.timeout);
    set_curl_followlocation(c_opts.followlocation);
    set_curl_debug_verbose(c_opts.verbose);
    set_curl_tcp_keepalive(c_opts.keepalive);

    set_send_post_headers(c_data.send_content_header);
    set_send_post_headers(c_data.send_accept_header);
    set_send_post_headers(c_data.api_key);
    curl_easy_setopt(m_curl, CURLOPT_ENCODING, "UTF-8");
    curl_easy_setopt(m_curl, CURLOPT_URL, c_data.api_url.c_str());
    curl_easy_setopt(m_curl, CURLOPT_POST, 1L);
    curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, c_data.request_body.c_str());
    curl_easy_setopt(m_curl, CURLOPT_POSTFIELDSIZE, c_data.request_body.length());
    curl_easy_setopt(m_curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
}
void ctai_curl::set_send_post_opts_reset()
{
    // 先清理 headers
    if (m_headers)
    {
        curl_slist_free_all(m_headers);
        m_headers = nullptr;
    }

    if (m_curl)
    {
        // 完全清理旧的 handle
        curl_easy_cleanup(m_curl);
        // 创建新的 handle
        m_curl = curl_easy_init();
        if (m_curl)
        {
            // 设置基本选项
            curl_easy_setopt(m_curl, CURLOPT_NOSIGNAL, 1L);
        }
    }
}
void ctai_curl::curl_init()
{
    if (!m_initialized)
    {
        curl_global_init(CURL_GLOBAL_ALL);
        m_initialized = true;
    }

    // 每次都创建新的 handle
    if (m_curl)
    {
        curl_easy_cleanup(m_curl);
    }
    m_curl = curl_easy_init();
    if (!m_curl)
    {
        throw std::runtime_error("Failed to initialize CURL handle");
    }
}
void ctai_curl::send_post_response(model_data m_data, curl_opts opts)
{
    if (!m_curl)
    {
        emit send_post_out_error("CURL handle is null");
        return;
    }

    c_data = m_data;
    c_opts = opts;
    c_data.request_body = send_send_body(c_data);

    try
    {
        std::string response_data;
        call_back_context ctx{this, c_data}; // 使用列表初始化

        set_send_post_option();

        if (c_data.postback_stream_mode)
        {
            curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, stream_callback);
            curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &ctx);
        }
        else
        {
            curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, not_stream_callback);
            curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &response_data);
        }

        m_error = curl_easy_perform(m_curl);

        if (m_error != CURLE_OK)
        {
            emit send_post_out_error(curl_easy_strerror(m_error));
        }
        else if (!c_data.postback_stream_mode)
        {
            send_not_stream(c_data, response_data);
            emit send_post_out_data(c_data);
        }
    }
    catch (const std::exception &e)
    {
        emit send_post_out_error(e.what());
    }

    // 请求完成后重置
    set_send_post_opts_reset();
}