/**
 * @file function_call_handler.c
 * @brief FC 分发处理实现
 */

#include "function_call/function_call_handler.h"
#include "engine_internal.h"
#include "interact/interact_manager.h"
#include "audio/audio_manager.h"
#include "protocol/agent_message.h"
#include "protocol/protocol_commands.h"
#include "connection/connection_manager.h"
#include "json_utils.h"
#include "hal_json.h"
#include "hal_log.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define TAG "FC"

/* ========================================================================== */
/* 发送 FC 结果                                                                */
/* ========================================================================== */

static int send_fc_result(engine_internal_ctx_t *ctx,
                          const char *session_id,
                          const char *result,
                          const char *message)
{
    if (!session_id) {
        BD_LOGW(TAG, "send_fc_result: session_id 为空, 跳过");
        return -1;
    }

    if (!conn_mgr_is_connected(ctx)) {
        BD_LOGW(TAG, "send_fc_result: WS 未连接, session=%s", session_id);
        return -1;
    }

    char result_json[256];
    snprintf(result_json, sizeof(result_json),
             "{\"result\":\"%s\",\"message\":\"%s\"}",
             result ? result : "ok",
             message ? message : "");

    char msg_buf[512];
    int n = agent_msg_create_fc_result(session_id, result_json, msg_buf, sizeof(msg_buf));
    if (n <= 0) {
        BD_LOGE(TAG, "构建FC结果失败");
        return -1;
    }

    int rc = conn_mgr_send_text(ctx, msg_buf);
    if (rc < 0) {
        BD_LOGE(TAG, "FC结果发送失败 rc=%d session=%s", rc, session_id);
    } else {
        BD_LOGI(TAG, "FC结果已发送 session=%s result=%s msg=%s",
                session_id, result ? result : "ok", message ? message : "");
    }
    return rc;
}

/* ========================================================================== */
/* 内置FC: switch_dialog_mode (对话模式切换)                                    */
/* ========================================================================== */

static int handle_fc_switch_dialog_mode(engine_internal_ctx_t *ctx,
                                         const char *session_id,
                                         const char *params)
{
    if (!params) {
        send_fc_result(ctx, session_id, "error", "missing params");
        return -1;
    }

    hal_json_t pjson = hal_json_parse(params);
    if (!pjson) {
        send_fc_result(ctx, session_id, "error", "invalid params json");
        return -1;
    }

    const char *mode_str = hal_json_get_string(pjson, "mode");
    if (!mode_str) {
        hal_json_destroy(pjson);
        send_fc_result(ctx, session_id, "error", "missing mode field");
        return -1;
    }

    aiagent_interact_mode_t mode;
    if (strcmp(mode_str, "ptt") == 0 || strcmp(mode_str, "PTT") == 0 || strcmp(mode_str, "0") == 0) {
        mode = AIAGENT_INTERACT_PRESS;
    } else if (strcmp(mode_str, "wakeword") == 0 || strcmp(mode_str, "WAKEWORD") == 0 || strcmp(mode_str, "1") == 0) {
        mode = AIAGENT_INTERACT_WAKEUP;
    } else if (strcmp(mode_str, "voice_int") == 0 || strcmp(mode_str, "VOICE_INT") == 0 || strcmp(mode_str, "2") == 0) {
        mode = AIAGENT_INTERACT_CONTINUOUS;
    } else {
        BD_LOGW(TAG, "switch_dialog_mode: 未知模式 '%s'", mode_str);
        hal_json_destroy(pjson);
        send_fc_result(ctx, session_id, "error", "unknown mode");
        return -1;
    }

    hal_json_destroy(pjson);

    BD_LOGI(TAG, "FC切换对话模式: %d", mode);
    int ret = interact_mgr_switch_mode(ctx, mode);
    if (ret == 0) {
        ctx->config.default_mode = mode;
        send_fc_result(ctx, session_id, "ok", "mode switched");
    } else {
        send_fc_result(ctx, session_id, "error", "switch failed");
    }

    return 0;
}

/* ========================================================================== */
/* 内置FC: adjust_volume (音量调节)                                             */
/* ========================================================================== */

static int handle_fc_adjust_volume(engine_internal_ctx_t *ctx,
                                    const char *session_id,
                                    const char *params)
{
    if (!params) {
        send_fc_result(ctx, session_id, "error", "missing params");
        return -1;
    }

    hal_json_t pjson = hal_json_parse(params);
    if (!pjson) {
        send_fc_result(ctx, session_id, "error", "invalid params json");
        return -1;
    }

    const char *mode_str = hal_json_get_string(pjson, "mode");
    if (!mode_str) {
        hal_json_destroy(pjson);
        send_fc_result(ctx, session_id, "error", "missing mode field");
        return -1;
    }

    int current_vol = ctx->config.volume;
    if (current_vol <= 0) current_vol = 30;

    int new_vol = current_vol;

    if (strcmp(mode_str, "up") == 0) {
        new_vol = current_vol + 10;
        if (new_vol > 100) new_vol = 100;
    } else if (strcmp(mode_str, "down") == 0) {
        new_vol = current_vol - 10;
        if (new_vol < 0) new_vol = 0;
    } else if (strcmp(mode_str, "set") == 0) {
        const char *val_str = hal_json_get_string(pjson, "value");
        if (val_str) {
            new_vol = atoi(val_str);
            if (new_vol < 0) new_vol = 0;
            if (new_vol > 100) new_vol = 100;
        }
    } else {
        BD_LOGW(TAG, "adjust_volume: 未知模式 '%s'", mode_str);
        hal_json_destroy(pjson);
        send_fc_result(ctx, session_id, "error", "unknown mode");
        return -1;
    }

    hal_json_destroy(pjson);

    BD_LOGI(TAG, "FC调节音量: %d -> %d", current_vol, new_vol);
    audio_mgr_set_volume(ctx, new_vol);
    ctx->config.volume = new_vol;

    char msg[64];
    snprintf(msg, sizeof(msg), "volume set to %d", new_vol);
    send_fc_result(ctx, session_id, "ok", msg);

    return 0;
}

/* ========================================================================== */
/* 内置 FC 注册表                                                              */
/* ========================================================================== */

typedef int (*builtin_fc_handler_fn)(engine_internal_ctx_t *ctx,
                                      const char *session_id,
                                      const char *params);

typedef struct {
    const char            *name;
    builtin_fc_handler_fn  handler;
} builtin_fc_entry_t;

static const builtin_fc_entry_t s_builtin_fcs[] = {
    { "switch_dialog_mode", handle_fc_switch_dialog_mode },
    { "adjust_volume",      handle_fc_adjust_volume      },
    /* 新增内置 FC 在此追加一行即可 */
};

#define BUILTIN_FC_COUNT (sizeof(s_builtin_fcs) / sizeof(s_builtin_fcs[0]))

static int dispatch_builtin_fc(engine_internal_ctx_t *ctx,
                                const char *session_id,
                                const char *name,
                                const char *params)
{
    if (!name) {
        return 0;
    }
    for (size_t i = 0; i < BUILTIN_FC_COUNT; ++i) {
        if (strcmp(name, s_builtin_fcs[i].name) == 0) {
            s_builtin_fcs[i].handler(ctx, session_id, params);
            return 1;
        }
    }
    return 0;
}

/* ========================================================================== */
/* FC 分发入口                                                                 */
/* ========================================================================== */

/**
 * @brief FC 分发入口
 *
 * 派发顺序：场景层 on_function_call 优先，未处理则走内置 FC 注册表。
 *
 * 服务端 FC 格式:
 *   {"session_id":"xxx","content":"{\"function_name\":\"...\",\"parameter_list\":[{...}]}","query":"..."}
 */
int fc_handler_dispatch(engine_internal_ctx_t *ctx, const char *payload, size_t len)
{
    if (!ctx || !payload || len == 0) {
        return -1;
    }

    /* ---- 步骤1: 提取 session_id ---- */
    char session_buf[64] = {0};
    {
        const char *val = NULL;
        int val_len = 0;
        if (json_find_string_value(payload, (int)len, "session_id", &val, &val_len) == 0) {
            /* val 包含首尾引号，剥离后拷贝 */
            int copy_len = val_len - 2;
            if (copy_len > (int)sizeof(session_buf) - 1) {
                copy_len = (int)sizeof(session_buf) - 1;
            }
            if (copy_len > 0) {
                memcpy(session_buf, val + 1, copy_len);
            }
            session_buf[copy_len > 0 ? copy_len : 0] = '\0';
        }
    }

    /* ---- 步骤2: 提取并反转义 content ---- */
    char content_buf[512] = {0};
    int content_len = 0;
    {
        const char *val = NULL;
        int val_len = 0;
        if (json_find_string_value(payload, (int)len, "content", &val, &val_len) == 0) {
            /* val 含首尾引号，json_unescape 会自动剥离 */
            content_len = json_unescape(val, val_len, content_buf, sizeof(content_buf));
        }
    }

    BD_LOGD(TAG, "content反转义(%d): %.100s", content_len, content_buf);

    /* ---- 步骤3: 解析 content JSON 提取 function_name / parameter_list ---- */
    const char *name = NULL;
    const char *params = NULL;
    char name_buf[64] = {0};
    char params_buf[256] = {0};

    if (content_len > 0) {
        hal_json_t cjson = hal_json_parse(content_buf);
        if (cjson) {
            /* 提取 function_name */
            const char *fn = hal_json_get_string(cjson, "function_name");
            if (fn) {
                snprintf(name_buf, sizeof(name_buf), "%s", fn);
                name = name_buf;
            }

            /* 将 parameter_list 数组中所有项合并为一个 flat JSON 对象
             * 每个 item 形如 {"key":"value"}，合并结果：{"key1":"v1","key2":"v2"} */
            hal_json_t arr = hal_json_get_array(cjson, "parameter_list");
            if (arr) {
                int count = hal_json_get_array_size(arr);
                int plen = 0;
                params_buf[plen++] = '{';

                for (int i = 0; i < count && plen < (int)sizeof(params_buf) - 4; i++) {
                    hal_json_t item = hal_json_get_array_item(arr, i);
                    if (!item) continue;

                    const char *s = hal_json_to_string(item);
                    if (s) {
                        /* item 格式：{"key":"value"}，提取键值内容 */
                        int slen = (int)strlen(s);
                        if (slen >= 2) {
                            if (plen > 1) {  /* 非第一项，补逗号 */
                                params_buf[plen++] = ',';
                            }
                            int inner = slen - 2;
                            if (plen + inner < (int)sizeof(params_buf) - 2) {
                                memcpy(params_buf + plen, s + 1, inner);
                                plen += inner;
                            }
                        }
                    }
                    hal_json_destroy(item);
                }

                params_buf[plen]     = '}';
                params_buf[plen + 1] = '\0';
                plen++;
                params = params_buf;
                hal_json_destroy(arr);
            }

            hal_json_destroy(cjson);
        } else {
            BD_LOGW(TAG, "content JSON解析失败");
        }
    }

    const char *session_id = session_buf[0] ? session_buf : NULL;

    BD_LOGI(TAG, "FC分发: name=%s, session=%s",
            name ? name : "null", session_id ? session_id : "null");

    /* ---- 步骤4: 派发（场景层优先，未处理则 fallback 到内置） ---- */
    int handled = 0;

    /* 4.1 场景层先看：返回 1 即已消化 */
    if (ctx->callbacks.on_function_call) {
        int ret = ctx->callbacks.on_function_call(session_id, name, params,
                                                   ctx->callbacks.user_ctx);
        if (ret == 1) {
            handled = 1;
        }
    }

    /* 4.2 fallback 到内置 FC 注册表 */
    if (!handled) {
        handled = dispatch_builtin_fc(ctx, session_id, name, params);
    }

    if (!handled) {
        BD_LOGW(TAG, "未识别的FC: %s", name ? name : "null");
        /* 未识别的调用也返回结果，保持会话完整 */
        if (session_id) {
            send_fc_result(ctx, session_id, "ok", "not_supported");
        }
    }

    return 0;
}

/* ========================================================================== */
/* FC 结果发送 (供外部调用)                                                     */
/* ========================================================================== */

int fc_handler_send_result(engine_internal_ctx_t *ctx,
                            const char *session_id, const char *result)
{
    if (!ctx || !session_id || !result) {
        return -1;
    }

    if (!conn_mgr_is_connected(ctx)) {
        return -1;
    }

    char msg_buf[512];
    int n = agent_msg_create_fc_result(session_id, result, msg_buf, sizeof(msg_buf));
    if (n <= 0) {
        BD_LOGE(TAG, "构建FC结果失败");
        return -1;
    }

    int ret = conn_mgr_send_text(ctx, msg_buf);
    if (ret < 0) {
        BD_LOGE(TAG, "发送FC结果失败");
    }
    return ret;
}
