/**
 * @file ai_agent_engine.c
 * @brief 引擎公开 API 实现
 */

#include "aiagent_engine.h"
#include "engine_internal.h"
#include "state_machine.h"
#include "audio/audio_manager.h"
#include "protocol/message_dispatcher.h"
#include "protocol/agent_message.h"
#include "protocol/protocol_commands.h"
#include "protocol/visual_sender.h"
#include "connection/connection_manager.h"
#include "connection/connection_url_builder.h"
#include "connection/userserver_client.h"
#include "protocol/license.h"
#include "interact/interact_manager.h"
#include "aiagent_credentials.h"
#include "hal_mutex.h"
#include "hal_log.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define TAG "ENGINE"

/* 状态机回调适配器：转发给场景层 on_state_change */
static void engine_state_change_cb(aiagent_state_t old_state,
                                    aiagent_state_t new_state,
                                    void *user_ctx)
{
    engine_internal_ctx_t *ctx = (engine_internal_ctx_t *)user_ctx;

    /* 连接就绪后补发当前交互模式的初始化命令 */
    if (ctx && old_state == AIAGENT_STATE_CONNECTING &&
        new_state == AIAGENT_STATE_READY) {
        interact_mgr_reenter(ctx);
    }

    if (ctx && ctx->callbacks.on_state_change) {
        ctx->callbacks.on_state_change(old_state, new_state, ctx->callbacks.user_ctx);
    }
}

aiagent_engine_t aiagent_engine_create(const aiagent_callbacks_t *callbacks)
{
    if (!callbacks) {
        return NULL;
    }

    engine_internal_ctx_t *ctx = (engine_internal_ctx_t *)calloc(1, sizeof(engine_internal_ctx_t));
    if (!ctx) {
        return NULL;
    }

    memcpy(&ctx->callbacks, callbacks, sizeof(aiagent_callbacks_t));
    ctx->state = AIAGENT_STATE_IDLE;
    ctx->initialized = false;
    ctx->started = false;

    ctx->state_mutex = hal_mutex_create();
    if (!ctx->state_mutex) {
        free(ctx);
        return NULL;
    }

    BD_LOGI(TAG, "engine created");
    return (aiagent_engine_t)ctx;
}

int aiagent_engine_init(aiagent_engine_t engine, const aiagent_config_t *config)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !config) {
        return -1;
    }

    if (ctx->initialized) {
        BD_LOGW(TAG, "already initialized");
        return 0;
    }

    /* 深拷贝配置 */
    memcpy(&ctx->config, config, sizeof(aiagent_config_t));
    state_machine_init(ctx, engine_state_change_cb, ctx);
    msg_dispatcher_init(ctx);

    audio_mgr_config_t audio_cfg;
    memset(&audio_cfg, 0, sizeof(audio_cfg));
    audio_cfg.sample_rate       = config->audio_sample_rate;
    audio_cfg.channels          = config->audio_channels;
    audio_cfg.frame_ms          = config->audio_frame_ms;
    audio_cfg.on_data           = NULL;  /* recorder callback wired internally */
    audio_cfg.user_ctx          = ctx;

    int audio_ret = audio_mgr_init(ctx, &audio_cfg);
    if (audio_ret < 0) {
        BD_LOGW(TAG, "audio mgr init fail (non-fatal)");
    }

    interact_mgr_init(ctx, config->default_mode);

    ctx->initialized = true;
    BD_LOGI(TAG, "engine initialized");
    return 0;
}

int aiagent_engine_start(aiagent_engine_t engine)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->initialized) {
        return -1;
    }

    if (ctx->started) {
        return 0;
    }

    /* 构建 WebSocket URL */
    const char *url = conn_url_build(ctx);
    if (!url) {
        BD_LOGE(TAG, "build url fail (appid missing?)");
        if (ctx->callbacks.on_error) {
            ctx->callbacks.on_error(AIAGENT_ERR_INVALID_PARAM, "cannot build ws url",
                                     ctx->callbacks.user_ctx);
        }
        return -1;
    }

    BD_LOGI(TAG, "connect: %.100s...", url);
    int ret = conn_mgr_connect(ctx, url);
    if (ret < 0) {
        BD_LOGE(TAG, "connect fail");
        if (ctx->callbacks.on_error) {
            ctx->callbacks.on_error(AIAGENT_ERR_NETWORK, "connect failed",
                                     ctx->callbacks.user_ctx);
        }
        return -1;
    }

    ctx->started = true;
    audio_mgr_start_record(ctx);
    audio_mgr_start_playback(ctx);

    BD_LOGI(TAG, "engine started");
    return 0;
}

void aiagent_engine_stop(aiagent_engine_t engine)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started) {
        return;
    }

    /* 停止引擎后再断开连接 */
    ctx->started = false;

    audio_mgr_stop_record(ctx);
    audio_mgr_stop_playback(ctx);
    conn_mgr_disconnect(ctx);

#if AIAGENT_CONN_MODE == AIAGENT_CONN_MODE_USERSERVER
    /* USERSERVER 模式：与 create 配对，best-effort 通知服务端释放实例 */
    if (ctx->userserver_instance_id[0] != '\0') {
        userserver_destroy_instance(ctx->config.userserver_url,
                                    ctx->config.userserver_destroy_path,
                                    ctx->config.appid,
                                    ctx->userserver_instance_id);
        ctx->userserver_instance_id[0] = '\0';
    }
#endif

    ctx->state = AIAGENT_STATE_IDLE;

    BD_LOGI(TAG, "engine stopped");
}

void aiagent_engine_destroy(aiagent_engine_t engine)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx) {
        return;
    }

    /* 确保已停止 */
    if (ctx->started) {
        aiagent_engine_stop(engine);
    }

    msg_dispatcher_deinit(ctx);
    interact_mgr_deinit(ctx);
    audio_mgr_deinit(ctx);

    if (ctx->state_mutex) {
        hal_mutex_destroy(ctx->state_mutex);
        ctx->state_mutex = NULL;
    }

    free(ctx);
    BD_LOGI(TAG, "engine destroyed");
}

int aiagent_engine_start_record(aiagent_engine_t engine)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started) {
        return -1;
    }

    /* 录音硬件已在 engine_start 中启动，这里仅切换状态使数据流通 */
    state_machine_post_event(ctx, SM_EVT_START_LISTEN);
    return 0;
}

int aiagent_engine_stop_record(aiagent_engine_t engine)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started) {
        return -1;
    }

    state_machine_post_event(ctx, SM_EVT_STOP_LISTEN);
    return 0;
}

int aiagent_engine_interrupt(aiagent_engine_t engine)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started) {
        return -1;
    }

    /* 只在 SPEAKING 状态发送打断 */
    if (ctx->state != AIAGENT_STATE_SPEAKING) {
        return 0;
    }

    char msg_buf[16];
    int n = agent_msg_create_break(msg_buf, sizeof(msg_buf));
    if (n <= 0) {
        return -1;
    }

    int ret = conn_mgr_send_text(ctx, msg_buf);
    if (ret == 0) {
        audio_mgr_stop_playback(ctx);
        state_machine_post_event(ctx, SM_EVT_INTERRUPT);
    }
    return ret;
}

int aiagent_engine_send_text(aiagent_engine_t engine, const char *text)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started || !text) {
        return -1;
    }

    char msg_buf[512];
    int n = agent_msg_create_text(text, msg_buf, sizeof(msg_buf));
    if (n <= 0) {
        return -1;
    }

    return conn_mgr_send_text(ctx, msg_buf);
}

int aiagent_engine_send_audio(aiagent_engine_t engine, const uint8_t *data, size_t len)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started || !data || len == 0) {
        return -1;
    }

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

    return conn_mgr_send_binary(ctx, data, len);
}

int aiagent_engine_set_volume(aiagent_engine_t engine, int volume)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx) {
        return -1;
    }

    if (volume < 0) volume = 0;
    if (volume > 100) volume = 100;

    if (ctx->player_handle) {
        hal_player_set_volume(ctx->player_handle, (uint8_t)volume);
    }
    if (ctx->local_player_handle) {
        hal_local_player_set_volume(ctx->local_player_handle, (uint8_t)volume);
    }
    return 0;
}

int aiagent_engine_switch_mode(aiagent_engine_t engine, aiagent_interact_mode_t mode)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx) {
        return -1;
    }

    int ret = interact_mgr_switch_mode(ctx, mode);
    if (ret == 0) {
        ctx->config.default_mode = mode;
    }
    return ret;
}

int aiagent_engine_switch_voice(aiagent_engine_t engine, const char *voice_id)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started || !voice_id) {
        return -1;
    }

    char msg_buf[128];
    int n = agent_msg_create_switch_voice(voice_id, msg_buf, sizeof(msg_buf));
    if (n <= 0) {
        return -1;
    }

    return conn_mgr_send_text(ctx, msg_buf);
}

aiagent_state_t aiagent_engine_get_state(aiagent_engine_t engine)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx) {
        return AIAGENT_STATE_IDLE;
    }
    return state_machine_get_state(ctx);
}

bool aiagent_engine_is_busy(aiagent_engine_t engine)
{
    aiagent_state_t st = aiagent_engine_get_state(engine);
    return (st != AIAGENT_STATE_IDLE);
}

int aiagent_engine_send_fc_result(aiagent_engine_t engine,
                                   const char *session_id,
                                   const char *result,
                                   const char *message)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started || !session_id || !result) {
        return -1;
    }

    return protocol_send_fc_result(ctx, session_id, result, message);
}

/* ==========================================================================
 * 按键 & 唤醒词事件转发到对话管理器
 * ========================================================================== */

int aiagent_engine_notify_key_press(aiagent_engine_t engine)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started) {
        return -1;
    }
    interact_mgr_notify_key(ctx, INTERACT_KEY_PRESS);
    return 0;
}

int aiagent_engine_notify_key_release(aiagent_engine_t engine)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started) {
        return -1;
    }
    interact_mgr_notify_key(ctx, INTERACT_KEY_RELEASE);
    return 0;
}

int aiagent_engine_notify_key_long_press(aiagent_engine_t engine)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started) {
        return -1;
    }
    interact_mgr_notify_key(ctx, INTERACT_KEY_LONG_PRESS);
    return 0;
}

int aiagent_engine_notify_wakeword(aiagent_engine_t engine)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started) {
        return -1;
    }
    interact_mgr_notify_wakeword(ctx);
    return 0;
}

/* ==========================================================================
 * SET 命令 API
 * ========================================================================== */

int aiagent_engine_update_system_prompt(aiagent_engine_t engine, const char *json_payload)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started || !json_payload) {
        return -1;
    }
    return protocol_send_update_system_prompt(ctx, json_payload);
}

int aiagent_engine_set_enhance_query(aiagent_engine_t engine, const char *json_payload)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started || !json_payload) {
        return -1;
    }
    return protocol_send_enhance_query(ctx, json_payload);
}

int aiagent_engine_set_auto_interrupt(aiagent_engine_t engine, bool enable)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started) {
        return -1;
    }
    return enable ? protocol_send_auto_int_enable(ctx)
                  : protocol_send_auto_int_disable(ctx);
}

int aiagent_engine_switch_scene_role(aiagent_engine_t engine, const char *json)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started || !json) {
        return -1;
    }
    return protocol_send_switch_scene_role(ctx, json);
}

/* ==========================================================================
 * 视觉 & 事件扩展 API
 * ========================================================================== */

int aiagent_engine_send_event(aiagent_engine_t engine, const char *event_str)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started || !event_str) {
        return -1;
    }

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

    return conn_mgr_send_text(ctx, event_str);
}

int aiagent_engine_update_visual_mode(aiagent_engine_t engine, int vision_mode, int expire_sec)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started) {
        return -1;
    }

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

    /* 构造: [SET]:[UPDATE_VISION_MODE]:{"mode":"N","expire":"M"} */
    char cmd_buf[128];
    snprintf(cmd_buf, sizeof(cmd_buf),
             "[SET]:[UPDATE_VISION_MODE]:{\"mode\":\"%d\",\"expire\":\"%d\"}",
             vision_mode, expire_sec);

    BD_LOGI(TAG, "update visual mode: %d, expire: %d", vision_mode, expire_sec);
    return conn_mgr_send_text(ctx, cmd_buf);
}

int aiagent_engine_send_video(aiagent_engine_t engine,
                              const uint8_t *data, size_t len)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started || !data || len == 0) {
        return -1;
    }
    return visual_send_image(ctx, data, len);
}

int aiagent_engine_send_tts_direct(aiagent_engine_t engine, const char *text)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started || !text) {
        return -1;
    }
    return protocol_send_tts_direct(ctx, text);
}

int aiagent_engine_interrupt_delay(aiagent_engine_t engine, unsigned int delay_ms)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started) {
        return -1;
    }
    return protocol_send_break_begin(ctx, delay_ms);
}

int aiagent_engine_remote_player_stop(aiagent_engine_t engine)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started) {
        return -1;
    }
    return protocol_send_remote_player_stop(ctx);
}

int aiagent_engine_remote_player_pause(aiagent_engine_t engine)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started) {
        return -1;
    }
    return protocol_send_remote_player_pause(ctx);
}

int aiagent_engine_remote_player_resume(aiagent_engine_t engine)
{
    engine_internal_ctx_t *ctx = engine_get_ctx(engine);
    if (!ctx || !ctx->started) {
        return -1;
    }
    return protocol_send_remote_player_resume(ctx);
}
