/**
 * @file connection_manager.c
 * @brief WebSocket 连接管理器实现（含断连自动重连）
 */

#include "connection/connection_manager.h"
#include "connection/connection_url_builder.h"
#include "engine_internal.h"
#include "state_machine.h"
#include "protocol/message_dispatcher.h"
#include "hal_websocket.h"
#include "hal_thread.h"
#include "hal_log.h"
#include <string.h>

#define TAG "CONN"

#define RECONNECT_DELAY_MS     3000
#define RECONNECT_MAX_RETRIES  5

/* 前向声明 */
static void ws_event_callback(hal_ws_event_t event, const void *data,
                              size_t len, void *user_ctx);

/**
 * 重连线程：延迟后尝试重新建立 WebSocket 连接
 */
static void reconnect_thread_entry(void *param)
{
    engine_internal_ctx_t *ctx = (engine_internal_ctx_t *)param;

    while (ctx->started && ctx->reconnect_attempts < RECONNECT_MAX_RETRIES) {
        ctx->reconnect_attempts++;
        BD_LOGI(TAG, "reconnect attempt %d/%d (delay %dms)",
                ctx->reconnect_attempts, RECONNECT_MAX_RETRIES,
                RECONNECT_DELAY_MS);

        hal_thread_sleep_ms(RECONNECT_DELAY_MS);

        if (!ctx->started) {
            break;
        }

        /* 清理旧连接 */
        if (ctx->ws_handle) {
            hal_ws_disconnect(ctx->ws_handle);
            hal_ws_destroy(ctx->ws_handle);
            ctx->ws_handle = NULL;
        }

        /* 重建 URL 并连接 */
        const char *url = conn_url_build(ctx);
        if (!url) {
            BD_LOGE(TAG, "reconnect: url build fail");
            continue;
        }

        hal_ws_config_t ws_cfg = {
            .url = url,
            .callback = ws_event_callback,
            .user_ctx = ctx,
            .recv_buf_size = 4096,
            .use_overseas_dns = AIAGENT_REGION_IS_INTL,
        };

        ctx->ws_handle = hal_ws_create(&ws_cfg);
        if (!ctx->ws_handle) {
            BD_LOGE(TAG, "reconnect: ws create fail");
            continue;
        }

        state_machine_post_event(ctx, SM_EVT_CONNECT_REQUEST);
        int ret = hal_ws_connect(ctx->ws_handle);
        if (ret == 0) {
            BD_LOGI(TAG, "reconnect success");
            ctx->reconnect_attempts = 0;
            ctx->reconnecting = false;
            return;
        }

        BD_LOGW(TAG, "reconnect: connect fail");
        hal_ws_destroy(ctx->ws_handle);
        ctx->ws_handle = NULL;
    }

    /* 重试耗尽或被停止 */
    ctx->reconnecting = false;
    if (ctx->started && ctx->reconnect_attempts >= RECONNECT_MAX_RETRIES) {
        BD_LOGE(TAG, "reconnect failed after %d attempts", RECONNECT_MAX_RETRIES);
        if (ctx->callbacks.on_error) {
            ctx->callbacks.on_error(AIAGENT_ERR_NETWORK,
                "reconnect failed", ctx->callbacks.user_ctx);
        }
    }
}

/**
 * WebSocket 事件回调 - 转发到引擎上下文
 */
static void ws_event_callback(hal_ws_event_t event, const void *data, size_t len, void *user_ctx)
{
    engine_internal_ctx_t *ctx = (engine_internal_ctx_t *)user_ctx;
    if (!ctx) {
        return;
    }

    switch (event) {
    case HAL_WS_EVENT_CONNECTED:
        BD_LOGI(TAG, "ws connected");
        state_machine_post_event(ctx, SM_EVT_CONNECTED);

        /* 根据当前配置决定是否等待 License 认证。 */
        if (!ctx->config.license_key || ctx->config.license_key[0] == '\0'
#if AIAGENT_CONN_MODE == AIAGENT_CONN_MODE_TEST
            || true
#endif
            ) {
            BD_LOGI(TAG, "skip license auth -> READY");
            state_machine_post_event(ctx, SM_EVT_AUTH_SUCCESS);
        }
        break;

    case HAL_WS_EVENT_DISCONNECTED:
        BD_LOGW(TAG, "ws disconnected");
        state_machine_post_event(ctx, SM_EVT_DISCONNECTED);
        /* 意外断连且未在重连中 → 启动重连线程 */
        if (ctx->started && !ctx->reconnecting) {
            ctx->reconnecting = true;
            hal_thread_config_t rcfg = {
                .name       = "ws_reconn",
                .entry      = reconnect_thread_entry,
                .msg_handler = NULL,
                .arg        = ctx,
                .stack_size = 2048,
                .priority   = 20,
                .queue_size = 0,
            };
            hal_thread_create(&rcfg);
        }
        break;

    case HAL_WS_EVENT_TEXT_RECEIVED:
        if (data && len > 0) {
            BD_LOGB(BD_LOGI, TAG, data, len,
                           "ws recv text(%d): %s", (int)len);
            msg_dispatcher_handle_text(ctx, (const char *)data, len);
        }
        break;

    case HAL_WS_EVENT_BINARY_RECEIVED:
        if (data && len > 0) {
            msg_dispatcher_handle_binary(ctx, data, len);
        }
        break;

    case HAL_WS_EVENT_ERROR:
        BD_LOGE(TAG, "ws error");
        state_machine_post_event(ctx, SM_EVT_ERROR);
        if (ctx->callbacks.on_error) {
            ctx->callbacks.on_error(AIAGENT_ERR_NETWORK, "WebSocket error",
                                     ctx->callbacks.user_ctx);
        }
        break;
    }
}

int conn_mgr_connect(engine_internal_ctx_t *ctx, const char *url)
{
    if (!ctx || !url) {
        return -1;
    }

    BD_LOGI(TAG, "connect: %.100s...", url);

    /* 创建 WebSocket */
    hal_ws_config_t ws_cfg = {
        .url = url,
        .callback = ws_event_callback,
        .user_ctx = ctx,
        .recv_buf_size = 4096,
        .use_overseas_dns = AIAGENT_REGION_IS_INTL,
    };

    ctx->ws_handle = hal_ws_create(&ws_cfg);
    if (!ctx->ws_handle) {
        BD_LOGE(TAG, "ws create fail");
        return -1;
    }

    /* 触发连接状态 */
    state_machine_post_event(ctx, SM_EVT_CONNECT_REQUEST);

    /* 发起连接 */
    int ret = hal_ws_connect(ctx->ws_handle);
    if (ret < 0) {
        BD_LOGE(TAG, "ws connect fail");
        hal_ws_destroy(ctx->ws_handle);
        ctx->ws_handle = NULL;
        state_machine_post_event(ctx, SM_EVT_ERROR);
        return -1;
    }

    return 0;
}

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

    if (ctx->ws_handle) {
        hal_ws_disconnect(ctx->ws_handle);
        hal_ws_destroy(ctx->ws_handle);
        ctx->ws_handle = NULL;
    }

    return 0;
}

bool conn_mgr_is_connected(engine_internal_ctx_t *ctx)
{
    if (!ctx || !ctx->ws_handle) {
        return false;
    }
    return hal_ws_is_connected(ctx->ws_handle);
}

int conn_mgr_send_text(engine_internal_ctx_t *ctx, const char *text)
{
    if (!ctx || !text || !ctx->ws_handle) {
        return -1;
    }
    return hal_ws_send_text(ctx->ws_handle, text);
}

int conn_mgr_send_binary(engine_internal_ctx_t *ctx, const void *data, size_t len)
{
    if (!ctx || !data || len == 0 || !ctx->ws_handle) {
        return -1;
    }
    return hal_ws_send_binary(ctx->ws_handle, data, len);
}

void conn_mgr_deinit(engine_internal_ctx_t *ctx)
{
    if (!ctx) {
        return;
    }
    conn_mgr_disconnect(ctx);
}
