/**
 * @file message_dispatcher.c
 * @brief 下行消息路由分发
 */

#include "protocol/message_dispatcher.h"
#include "protocol/agent_protocol.h"
#include "aiagent_defaults.h"
#include "engine_internal.h"
#include "state_machine.h"
#include "audio/audio_manager.h"
#include "protocol/license.h"
#include "interact/interact_manager.h"
#include "function_call/function_call_handler.h"
#include "protocol/protocol_commands.h"
#include "connection/connection_manager.h"
#include "hal_device_info.h"
#include "hal_log.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TAG "DISP"

int msg_dispatcher_init(engine_internal_ctx_t *ctx)
{
    if (!ctx) {
        return -1;
    }
    return 0;
}

/* ==========================================================================
 * License 处理
 * ========================================================================== */

/**
 * 处理 License 消息：[MUST] 触发激活，[PASS] 表示通过
 */
static void handle_license(engine_internal_ctx_t *ctx, const char *buf, size_t len)
{
    if (license_handle_response(buf, len)) {
        /* License 通过（PASS / ACTIVE_OK） */
        BD_LOGI(TAG, "license auth success");
        state_machine_post_event(ctx, SM_EVT_AUTH_SUCCESS);

        /* 发送设备信息 */
#if AIAGENT_SEND_DEVICE_INFO
        char dev_id[AIAGENT_DEVICE_ID_LEN] = {0};
        hal_device_get_device_id(dev_id, sizeof(dev_id));
        char dev_info[256];
        snprintf(dev_info, sizeof(dev_info),
                 AGENT_CMD_DEVICE_INFO_FMT,
                 dev_id, dev_id,
                 AIAGENT_ASR_TEXT_EXT ? "true" : "false");
        if (conn_mgr_is_connected(ctx)) {
            conn_mgr_send_text(ctx, dev_info);
            BD_LOGI(TAG, "sent device info");
        }
#endif

        if (ctx->callbacks.on_license_result) {
            ctx->callbacks.on_license_result(true, ctx->callbacks.user_ctx);
        }
    } else {
        /* 需要激活 license */
        license_resp_type_t resp = license_parse_response(buf, len);
        if (resp == LIC_RESP_MUST) {
            char dev_id[AIAGENT_DEVICE_ID_LEN] = {0};
            hal_device_get_device_id(dev_id, sizeof(dev_id));
            const char *lic_key = ctx->config.license_key;
            const char *uid = ctx->config.cfg.user_id;
            if (lic_key && dev_id[0]) {
                license_activate(ctx, dev_id, uid, lic_key);
            } else {
                BD_LOGE(TAG, "no license_key or device_id");
                state_machine_post_event(ctx, SM_EVT_AUTH_FAIL);
            }
        } else if (resp == LIC_RESP_FAILED) {
            BD_LOGE(TAG, "license auth failed");
            state_machine_post_event(ctx, SM_EVT_AUTH_FAIL);
            if (ctx->callbacks.on_license_result) {
                ctx->callbacks.on_license_result(false, ctx->callbacks.user_ctx);
            }
        }
    }
}

/* ==========================================================================
 * ASR 处理
 * ========================================================================== */

#if AIAGENT_ASR_TEXT_EXT
/* 在 '&' 分隔的扩展段中查找 [key]:value，命中返回 value 起始指针(未 null 终止)和长度 */
static const char *asr_ext_find(const char *buf, const char *end,
                                const char *key, size_t *vlen)
{
    size_t klen = strlen(key);
    const char *p = buf;
    while (p < end) {
        if (*p != '[') {
            while (p < end && *p != '&') { p++; }
            if (p < end) { p++; }
            continue;
        }
        const char *kbeg = p + 1;
        const char *kend = kbeg;
        while (kend < end && *kend != ']') { kend++; }
        if (kend >= end || (kend + 1) >= end || *(kend + 1) != ':') {
            while (p < end && *p != '&') { p++; }
            if (p < end) { p++; }
            continue;
        }
        const char *vbeg = kend + 2;
        const char *vend = vbeg;
        while (vend < end && *vend != '&') { vend++; }

        if ((size_t)(kend - kbeg) == klen &&
            memcmp(kbeg, key, klen) == 0) {
            *vlen = (size_t)(vend - vbeg);
            return vbeg;
        }
        p = (vend < end) ? vend + 1 : vend;
    }
    return NULL;
}

/* 拷贝字符串并补齐结尾符 */
static void asr_ext_copy(char *dst, size_t cap, const char *src, size_t len)
{
    if (!dst || cap == 0) return;
    if (!src || len == 0) { dst[0] = '\0'; return; }
    size_t n = (len < cap - 1) ? len : (cap - 1);
    memcpy(dst, src, n);
    dst[n] = '\0';
}
#endif /* AIAGENT_ASR_TEXT_EXT */

static void handle_asr(engine_internal_ctx_t *ctx, agent_msg_type_t type,
                       const char *content, size_t content_len)
{
    bool is_final = (type == AGENT_MSG_TYPE_ASR || type == AGENT_MSG_TYPE_ASR_CONT);

    if (is_final) {
        state_machine_post_event(ctx, SM_EVT_ASR_RESULT);
    }

    if (!content || content_len == 0) {
        return;
    }

    /* 切分 text|||[ext...] */
    size_t text_len = content_len;
    const char *ext_buf = NULL;
    size_t ext_len = 0;
    if (content_len >= 3) {
        for (size_t i = 0; i + 2 < content_len; i++) {
            if (content[i] == '|' && content[i + 1] == '|' && content[i + 2] == '|') {
                text_len = i;
                ext_buf = content + i + 3;
                ext_len = content_len - (i + 3);
                break;
            }
        }
    }

    char *tmp = (char *)malloc(text_len + 1);
    if (!tmp) {
        return;
    }
    memcpy(tmp, content, text_len);
    tmp[text_len] = '\0';

    /* 纯文本回调（向后兼容） */
    if (ctx->callbacks.on_asr_result) {
        ctx->callbacks.on_asr_result(tmp, is_final, ctx->callbacks.user_ctx);
    }

    /* 扩展回调：情绪/声纹/session_id */
    if (ctx->callbacks.on_asr_result_ext) {
#if AIAGENT_ASR_TEXT_EXT
        if (ext_buf && ext_len > 0) {
            char  emo_buf[64]   = {0};
            char  name_buf[32]  = {0};
            char  sid_buf[48]   = {0};
            char  fin_buf[8]    = {0};
            size_t vlen = 0;
            const char *v;
            const char *eend = ext_buf + ext_len;

            v = asr_ext_find(ext_buf, eend, "emotion", &vlen);
            asr_ext_copy(emo_buf, sizeof(emo_buf), v, vlen);
            v = asr_ext_find(ext_buf, eend, "nick_name", &vlen);
            asr_ext_copy(name_buf, sizeof(name_buf), v, vlen);
            v = asr_ext_find(ext_buf, eend, "session_id", &vlen);
            asr_ext_copy(sid_buf, sizeof(sid_buf), v, vlen);
            v = asr_ext_find(ext_buf, eend, "finish", &vlen);
            asr_ext_copy(fin_buf, sizeof(fin_buf), v, vlen);

            aiagent_asr_ext_t ext = {
                .emotion    = emo_buf[0]  ? emo_buf  : NULL,
                .name       = name_buf[0] ? name_buf : NULL,
                .session_id = sid_buf[0]  ? sid_buf  : NULL,
                .finish     = (strcmp(fin_buf, "true") == 0),
            };
            ctx->callbacks.on_asr_result_ext(tmp, is_final, &ext,
                                             ctx->callbacks.user_ctx);
        } else {
            ctx->callbacks.on_asr_result_ext(tmp, is_final, NULL,
                                             ctx->callbacks.user_ctx);
        }
#else
        (void)ext_buf; (void)ext_len;
        ctx->callbacks.on_asr_result_ext(tmp, is_final, NULL,
                                         ctx->callbacks.user_ctx);
#endif
    }

    free(tmp);
}

/* ==========================================================================
 * AI/LLM 回复处理
 * ========================================================================== */

static void handle_ai_response(engine_internal_ctx_t *ctx, agent_msg_type_t type,
                               const char *content, size_t content_len)
{
    bool is_final = (type == AGENT_MSG_TYPE_AI);

    if (ctx->callbacks.on_ai_response && content) {
        char *tmp = (char *)malloc(content_len + 1);
        if (tmp) {
            memcpy(tmp, content, content_len);
            tmp[content_len] = '\0';
            ctx->callbacks.on_ai_response(tmp, is_final, ctx->callbacks.user_ctx);
            free(tmp);
        }
    }
}

/* ==========================================================================
 * TTS 事件处理
 * ========================================================================== */

static void handle_tts_event(engine_internal_ctx_t *ctx, agent_msg_type_t type)
{
    switch (type) {
    case AGENT_MSG_TYPE_TTS_BEGIN:
        BD_LOGI(TAG, "TTS begin speaking");
        /* TTS 开始时恢复播放输出 */
        audio_mgr_set_silence(ctx, false);
        /* 注入播放预缓冲静音数据 */
        audio_mgr_prefill_silence(ctx);
        state_machine_post_event(ctx, SM_EVT_TTS_BEGIN);
        interact_mgr_notify_tts(ctx, true);
        if (ctx->callbacks.on_tts_event) {
            ctx->callbacks.on_tts_event(true, ctx->callbacks.user_ctx);
        }
        break;

    case AGENT_MSG_TYPE_TTS_END:
        BD_LOGI(TAG, "TTS end speaking");
        state_machine_post_event(ctx, SM_EVT_TTS_END);
        /* 清空 TTS 期间积压的回声数据 */
        audio_mgr_clear_send_cbuf(ctx);
        interact_mgr_notify_tts(ctx, false);
        if (ctx->callbacks.on_tts_event) {
            ctx->callbacks.on_tts_event(false, ctx->callbacks.user_ctx);
        }
        break;

    case AGENT_MSG_TYPE_TTS_BEGIN_AUDIO:
        BD_LOGD(TAG, "TTS begin audio");
        break;

    case AGENT_MSG_TYPE_TTS_END_AUDIO:
        BD_LOGD(TAG, "TTS end audio");
        break;

    default:
        break;
    }
}

/* ==========================================================================
 * 事件消息处理
 * ========================================================================== */

static void handle_event(engine_internal_ctx_t *ctx, agent_msg_type_t type,
                         const char *content, size_t content_len)
{
    aiagent_event_type_t evt_type;

    switch (type) {
    case AGENT_MSG_TYPE_VOICE_COMING:
        BD_LOGD(TAG, "voice coming");
        audio_mgr_set_silence(ctx, true);
        evt_type = AIAGENT_EVT_VOICE_COMING;
        break;

    case AGENT_MSG_TYPE_VOICE_DISAPPEAR:
        BD_LOGD(TAG, "voice disappear");
        audio_mgr_set_silence(ctx, false);
        state_machine_post_event(ctx, SM_EVT_STOP_LISTEN);
        evt_type = AIAGENT_EVT_VOICE_DISAPPEAR;
        break;

    case AGENT_MSG_TYPE_INTERRUPT:
        BD_LOGI(TAG, "server interrupt");
        audio_mgr_stop_playback(ctx);
        state_machine_post_event(ctx, SM_EVT_INTERRUPT);
        evt_type = AIAGENT_EVT_INTERRUPT;
        break;

    case AGENT_MSG_TYPE_CONID: {
        BD_LOGB(BD_LOGI, TAG, content, content_len, "session conid: %s");
        evt_type = AIAGENT_EVT_CONID;
        break;
    }

    case AGENT_MSG_TYPE_AGENTID: {
        BD_LOGB(BD_LOGI, TAG, content, content_len, "agent id: %s");
        evt_type = AIAGENT_EVT_AGENTID;
        break;
    }

    case AGENT_MSG_TYPE_LEAVING:
        BD_LOGW(TAG, "server leaving");
        state_machine_post_event(ctx, SM_EVT_DISCONNECTED);
        evt_type = AIAGENT_EVT_LEAVING;
        break;

    case AGENT_MSG_TYPE_PLAY_AUDIO: {
        BD_LOGB(BD_LOGI, TAG, content, content_len, "play audio: %s");
        evt_type = AIAGENT_EVT_PLAY_AUDIO;
        break;
    }

    case AGENT_MSG_TYPE_UPLOAD_IMAGE:
        BD_LOGI(TAG, "upload image request");
        evt_type = AIAGENT_EVT_UPLOAD_IMAGE;
        break;

    case AGENT_MSG_TYPE_TAG_MSG: {
        BD_LOGB(BD_LOGI, TAG, content, content_len, "tag msg: %s");
        evt_type = AIAGENT_EVT_TAG_MSG;
        break;
    }

    case AGENT_MSG_TYPE_MEDIA_GEN_RESULT:
        BD_LOGI(TAG, "media generate result (%d bytes)", (int)content_len);
        evt_type = AIAGENT_EVT_MEDIA_GEN_RESULT;
        break;

    case AGENT_MSG_TYPE_REMOTE_PLAYER_BEGIN:
        BD_LOGI(TAG, "remote player begin");
        evt_type = AIAGENT_EVT_REMOTE_PLAYER_BEGIN;
        break;

    case AGENT_MSG_TYPE_REMOTE_PLAYER_END:
        BD_LOGI(TAG, "remote player end");
        evt_type = AIAGENT_EVT_REMOTE_PLAYER_END;
        break;

    case AGENT_MSG_TYPE_DIRECT_PLAY: {
        BD_LOGB(BD_LOGI, TAG, content, content_len, "direct play: %s");
        evt_type = AIAGENT_EVT_DIRECT_PLAY;
        break;
    }

    case AGENT_MSG_TYPE_EVENT:
    default:
        /* 未单独分类的 [E]:... 事件，原文透传给业务侧自行解析 */
        BD_LOGB(BD_LOGI, TAG, content, content_len, "event: %s");
        evt_type = AIAGENT_EVT_GENERIC;
        break;
    }

    /* 通知上层 */
    if (ctx->callbacks.on_event) {
        ctx->callbacks.on_event(evt_type, content, content_len, ctx->callbacks.user_ctx);
    }
}

/* ==========================================================================
 * 函数调用处理
 * ========================================================================== */

static void handle_function_call(engine_internal_ctx_t *ctx, const char *payload, size_t len)
{
    BD_LOGB(BD_LOGI, TAG, payload, len, "function call: %s");
    fc_handler_dispatch(ctx, payload, len);
}

/* ==========================================================================
 * 文本消息主分发
 * ========================================================================== */

/**
 * @brief 处理单条协议消息
 */
static int dispatch_single_message(engine_internal_ctx_t *ctx, const char *buf, size_t len)
{
    if (!buf || len == 0) {
        return -1;
    }

    /* 解析协议消息 */
    agent_protocol_result_t result;
    memset(&result, 0, sizeof(result));

    int ret = agent_protocol_parse_text(buf, len, &result);
    if (ret < 0 && ret != -2) {
        BD_LOGW(TAG, "parse fail: %d", ret);
        return -1;
    }

    /* 按消息类型分发 */
    switch (result.type) {

    /* --- 语音识别 --- */
    case AGENT_MSG_TYPE_ASR:
    case AGENT_MSG_TYPE_ASR_MID:
    case AGENT_MSG_TYPE_ASR_CONT:
    case AGENT_MSG_TYPE_ASR_MID_CONT:
        handle_asr(ctx, result.type, result.content, result.content_len);
        break;

    /* --- 大模型回复 --- */
    case AGENT_MSG_TYPE_AI:
    case AGENT_MSG_TYPE_AI_MID:
    case AGENT_MSG_TYPE_AI_HINT:
        handle_ai_response(ctx, result.type, result.content, result.content_len);
        break;

    /* --- TTS --- */
    case AGENT_MSG_TYPE_TTS_BEGIN:
    case AGENT_MSG_TYPE_TTS_END:
    case AGENT_MSG_TYPE_TTS_BEGIN_AUDIO:
    case AGENT_MSG_TYPE_TTS_END_AUDIO:
        handle_tts_event(ctx, result.type);
        break;

    /* --- License --- */
    case AGENT_MSG_TYPE_LICENSE:
        handle_license(ctx, buf, len);
        break;

    /* --- 事件 --- */
    case AGENT_MSG_TYPE_VOICE_COMING:
    case AGENT_MSG_TYPE_VOICE_DISAPPEAR:
    case AGENT_MSG_TYPE_INTERRUPT:
    case AGENT_MSG_TYPE_CONID:
    case AGENT_MSG_TYPE_AGENTID:
    case AGENT_MSG_TYPE_LEAVING:
    case AGENT_MSG_TYPE_PLAY_AUDIO:
    case AGENT_MSG_TYPE_UPLOAD_IMAGE:
    case AGENT_MSG_TYPE_TAG_MSG:
    case AGENT_MSG_TYPE_MEDIA_GEN_RESULT:
    case AGENT_MSG_TYPE_REMOTE_PLAYER_BEGIN:
    case AGENT_MSG_TYPE_REMOTE_PLAYER_END:
    case AGENT_MSG_TYPE_DIRECT_PLAY:
    case AGENT_MSG_TYPE_EVENT:
        handle_event(ctx, result.type, result.content, result.content_len);
        break;

    /* --- 函数调用 --- */
    case AGENT_MSG_TYPE_FUNCTION:
        handle_function_call(ctx, result.content, result.content_len);
        break;

    /* --- 本轮结束 --- */
    case AGENT_MSG_TYPE_DONE:
        BD_LOGD(TAG, "turn done");
        state_machine_post_event(ctx, SM_EVT_STOP_LISTEN);
        break;

    /* --- 未知 --- */
    case AGENT_MSG_TYPE_UNKNOWN:
    default: {
        BD_LOGB(BD_LOGI, TAG, buf, len, "unknown msg: %s");
        break;
    }
    }

    return 0;
}

/**
 * @brief 处理 WebSocket 文本消息（按 '\n' 分割粘包）
 */
int msg_dispatcher_handle_text(engine_internal_ctx_t *ctx, const char *buf, size_t len)
{
    if (!ctx || !buf || len == 0) {
        return -1;
    }

    const char *p = buf;
    const char *end = buf + len;

    while (p < end) {
        while (p < end && (*p == '\n' || *p == '\r')) {
            p++;
        }
        if (p >= end) {
            break;
        }

        const char *line_end = p;
        while (line_end < end && *line_end != '\n' && *line_end != '\r') {
            line_end++;
        }

        size_t line_len = (size_t)(line_end - p);
        if (line_len > 0) {
            BD_LOGB(BD_LOGI, TAG, p, line_len,
                           "dispatch(%d): %s", (int)line_len);
            dispatch_single_message(ctx, p, line_len);
        }

        p = line_end;
    }

    return 0;
}

/* ==========================================================================
 * 二进制消息处理（服务端下发的 PCM 音频）
 * ========================================================================== */

int msg_dispatcher_handle_binary(engine_internal_ctx_t *ctx, const void *buf, size_t len)
{
    if (!ctx || !buf || len == 0) {
        return -1;
    }

    /* 二进制数据 = TTS PCM，写入播放器；并通知应用层 */
    audio_mgr_write_playback_data(ctx, buf, len);

    if (ctx->callbacks.on_audio_data) {
        ctx->callbacks.on_audio_data((const uint8_t *)buf, len, ctx->callbacks.user_ctx);
    }

    return 0;
}

void msg_dispatcher_deinit(engine_internal_ctx_t *ctx)
{
    (void)ctx;
}
