#include "audiotts_play.h"
#include "audioplay.h"
#include "device_identity.h"
#include "mqtt_init.h"
#include "http_config_mqtt.h"

#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/buffer.h>

#define TTS_ADUINO_PTAH "/home/orangepi/car/master/audio.mp3"

// 全局变量：存储 HTTP 响应数据
static char *http_response = NULL;
static size_t http_response_len = 0;

static bool audio_tts_index=0;


// HTTP 响应回调函数：接收服务器返回的 JSON 数据
static size_t http_write_callback(void *ptr, size_t size, size_t nmemb, void *userdata) {
    size_t total = size * nmemb;
    // 扩容并拷贝响应数据
    char *temp = realloc(http_response, http_response_len + total + 1);
    if (!temp) {
        my_zlog_error("Realloc response buffer failed");
        return 0;
    }
    http_response = temp;
    memcpy(http_response + http_response_len, ptr, total);
    http_response_len += total;
    http_response[http_response_len] = '\0';  // 末尾加结束符
    return total;
}

// 生成 UUID（去除连字符，保证 reqid 唯一性）
void generate_uuid(char *buf, size_t len) {
    if (len < 33) return;  // UUID 去除连字符后 32 位
    uuid_t uuid;
    uuid_generate_random(uuid);
    uuid_unparse(uuid, buf);
    // 移除连字符
    char *p = strchr(buf, '-');
    while (p) {
        memmove(p, p + 1, strlen(p));
        p = strchr(buf, '-');
    }
}

// Base64 解码（将响应中的音频数据解码为二进制）
unsigned char *base64_decode(const char *input, size_t *output_len) {
    BIO *bio, *b64;
    size_t len = strlen(input);
    unsigned char *buffer = (unsigned char *)malloc(len * 3 / 4 + 1024);  // 预留足够空间

    if (!buffer) return NULL;

    // 初始化 OpenSSL Base64 解码
    OpenSSL_add_all_algorithms();  // 初始化 OpenSSL 算法（避免解码失败）
    b64 = BIO_new(BIO_f_base64());
    bio = BIO_new_mem_buf(input, len);
    bio = BIO_push(b64, bio);

    // 禁用换行符处理（关键：避免 Base64 字符串含换行导致解码失败）
    BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
    *output_len = BIO_read(bio, buffer, len * 3 / 4 + 1024);

    // 清理资源
    BIO_free_all(bio);

    // 调整缓冲区大小为实际解码长度
    buffer = realloc(buffer, *output_len);
    return buffer;
}


/**
 * 保存音频数据到文件（目录已存在）
 * @param data     音频数据指针
 * @param len      音频数据长度
 * @param filepath 完整文件路径
 * @return 0成功，1失败
 */
int save_audio_file(const void *data, size_t len, const char *filepath) {
    if (!data || len == 0 || !filepath) {
        my_zlog_error("Invalid parameters for save_audio_file\n");
        return 1;
    }
    
    FILE *fp = fopen(filepath, "wb");
    if (!fp) {
        my_zlog_error( "Open file %s failed: %s\n", filepath, strerror(errno));
        return 1;
    }
    
    size_t written = fwrite(data, 1, len, fp);
    fclose(fp);
    
    if (written != len) {
        my_zlog_error("Write file %s incomplete: %zu/%zu bytes", filepath, written, len);
        remove(filepath); // 删除不完整的文件
        return 1;
    }
    
    my_zlog_info("Success! Audio saved to: %s (%zu bytes)", filepath, written);
    return 0;
}

int audio_tts(const char *text) {
    // 1. 配置参数（替换为你的真实信息，已验证有效）
    const char *appid = "5745089507";          // 你的火山引擎 AppID
    const char *access_token = "0BeoBb_DOjrxfM4aTsJfUFVVS0k5V9mt";  // 你的访问令牌
    const char *voice_type = "zh_female_linjianvhai_moon_bigtts";  // 非流式音色
    const char *cluster = "volcano_tts";       // 固定值（必选）
    const char *uid = "user123456";            // 任意非空字符串
    const char *encoding = "mp3";              // 输出格式（mp3/wav/pcm/ogg_opus）
    const char *endpoint = "https://openspeech.bytedance.com/api/v1/tts";  // HTTP 接口地址

    // 2. 生成唯一 reqid（每次调用必须不同）
    char reqid[33] = {0};
    generate_uuid(reqid, sizeof(reqid));
    my_zlog_info("Generated ReqID: %s", reqid);

    // 3. 构建请求 JSON（严格遵循接口参数格式）
    cJSON *root = cJSON_CreateObject();
    if (!root) {
        my_zlog_error("Create JSON root failed");
        return 1;
    }

    // app 节点（必选）
    cJSON *app = cJSON_CreateObject();
    cJSON_AddStringToObject(app, "appid", appid);
    cJSON_AddStringToObject(app, "token", access_token);
    cJSON_AddStringToObject(app, "cluster", cluster);
    cJSON_AddItemToObject(root, "app", app);

    // user 节点（必选）
    cJSON *user = cJSON_CreateObject();
    cJSON_AddStringToObject(user, "uid", uid);
    cJSON_AddItemToObject(root, "user", user);

    // audio 节点（必选）
    cJSON *audio = cJSON_CreateObject();
    cJSON_AddStringToObject(audio, "voice_type", voice_type);
    cJSON_AddStringToObject(audio, "encoding", encoding);
    cJSON_AddNumberToObject(audio, "speed_ratio", 1.0);  // 语速（0.1~2.0）
    cJSON_AddNumberToObject(audio, "rate", 16000);       // 采样率（默认24000）
    cJSON_AddNumberToObject(audio, "loudness_ratio", 1.0);  // 音量（0.5~2.0）
    cJSON_AddBoolToObject(audio, "enable_emotion", true);  // 开启情感
    cJSON_AddStringToObject(audio, "emotion", "gentle");    // 情感类型（gentle=温柔）
    cJSON_AddNumberToObject(audio, "emotion_scale", 4.0);   // 情感强度（1~5，默认4）
    cJSON_AddItemToObject(root, "audio", audio);

    // request 节点（必选）
    cJSON *request = cJSON_CreateObject();
    cJSON_AddStringToObject(request, "reqid", reqid);
    cJSON_AddStringToObject(request, "text", text);
    cJSON_AddStringToObject(request, "operation", "query");  // HTTP 非流式固定为 query
    cJSON_AddStringToObject(request, "extra_param", "{\"disable_markdown_filter\":true}");  // 附加参数
    cJSON_AddItemToObject(root, "request", request);

    // 生成 JSON 字符串（无格式，减少传输体积）
    char *payload = cJSON_PrintUnformatted(root);
    cJSON_Delete(root);
    if (!payload) {
        my_zlog_error("Generate JSON payload failed");
        return 1;
    }
    my_zlog_info("Request Payload: %s", payload);

    // 4. 初始化 curl 并配置 HTTP 请求
    curl_global_init(CURL_GLOBAL_DEFAULT);
    CURL *curl = curl_easy_init();
    if (!curl) {
        my_zlog_error("Initialize curl failed");
        free(payload);
        return 1;
    }

    // 设置请求头（关键：Authorization 分号分隔，Content-Type 为 JSON）
    struct curl_slist *headers = NULL;
    char auth_header[256] = {0};
    snprintf(auth_header, sizeof(auth_header), "Authorization: Bearer;%s", access_token);
    headers = curl_slist_append(headers, auth_header);
    headers = curl_slist_append(headers, "Content-Type: application/json");
    headers = curl_slist_append(headers, "Accept: application/json");

    // curl 核心配置
    curl_easy_setopt(curl, CURLOPT_URL, endpoint);
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_POST, 1L);  // POST 方法
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload);  // 请求体
    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(payload));
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_write_callback);  // 接收响应回调
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);  // 开发环境禁用 SSL 证书校验（生产环境建议启用）
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15L);  // 超时时间 15 秒（避免网络慢导致超时）
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);  // 连接超时 10 秒

    // 5. 执行 HTTP 请求
    printf("Sending request to %s...\n", endpoint);
    CURLcode res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        fprintf(stderr, "curl_easy_perform failed: %s\n", curl_easy_strerror(res));
        free(payload);
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        curl_global_cleanup();
        return 1;
    }

    // 6. 解析 HTTP 响应（JSON 格式）
    printf("Response Length: %zu bytes\n", http_response_len);
    if (http_response_len == 0) {
        fprintf(stderr, "Empty response from server\n");
        free(payload);
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        curl_global_cleanup();
        return 1;
    }

    // 解析 JSON 响应
    cJSON *response_json = cJSON_Parse(http_response);
    if (!response_json) {
        fprintf(stderr, "Parse response JSON failed: %s\n", cJSON_GetErrorPtr());
        free(payload);
        free(http_response);
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        curl_global_cleanup();
        return 1;
    }

    // // 打印完整响应（便于调试，可根据需要注释）
    // char *response_str = cJSON_Print(response_json);
    // printf("Full Response JSON (abbreviated):\n%s\n", response_str);
    // free(response_str);

    // 提取响应状态（火山引擎该接口成功码：3000 + message=Success）
    cJSON *code = cJSON_GetObjectItem(response_json, "code");
    cJSON *message = cJSON_GetObjectItem(response_json, "message");
    if (!code || code->valueint != 3000 || !message || strcmp(message->valuestring, "Success") != 0) {
        fprintf(stderr, "Request failed! Code: %d, Message: %s\n", 
                code ? code->valueint : -1, 
                message ? message->valuestring : "No message");
        cJSON_Delete(response_json);
        free(payload);
        free(http_response);
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        curl_global_cleanup();
        return 1;
    }
    printf("Request succeeded! Code: %d, Message: %s\n", code->valueint, message->valuestring);

    // 关键：直接提取 data 字段的 Base64 音频字符串（接口实际返回格式）
    cJSON *audio_base64 = cJSON_GetObjectItem(response_json, "data");
    if (!audio_base64 || !audio_base64->valuestring || strlen(audio_base64->valuestring) == 0) {
        fprintf(stderr, "Response missing audio data (data field is empty)\n");
        cJSON_Delete(response_json);
        free(payload);
        free(http_response);
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        curl_global_cleanup();
        return 1;
    }
    my_zlog_info("Audio Base64 Length: %zu bytes\n", strlen(audio_base64->valuestring));

    // 7. Base64 解码音频数据
    size_t audio_len = 0;
    unsigned char *audio_data = base64_decode(audio_base64->valuestring, &audio_len);
    if (!audio_data || audio_len == 0) {
        my_zlog_error("Base64 decode audio failed");
        cJSON_Delete(response_json);
        free(payload);
        free(http_response);
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        curl_global_cleanup();
        return 1;
    }
    my_zlog_info("Decoded Audio Length: %zu bytes", audio_len);

    if(save_audio_file(audio_data, audio_len, TTS_ADUINO_PTAH) != 0) {//保存文件
        my_zlog_error("save_audio_file fail");
    }

    // 9. 清理资源（避免内存泄漏）
    cJSON_Delete(response_json);
    free(audio_data);
    free(payload);
    free(http_response);
    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);
    curl_global_cleanup();

    return 0;
}

void set_audio_tts_index(bool index){
    audio_tts_index=index;
}

bool get_audio_tts_index(){
    return audio_tts_index;
}
