/**
 * @file audio_manager.c
 * @brief 音频管道：协调 HAL 录音、播放和发送线程
 */

#include "audio/audio_manager.h"
#include "audio/audio_buffer.h"
#include "engine_internal.h"
#include "interact/interact_manager.h"
#include "hal_audio_recorder.h"
#include "hal_audio_player.h"
#include "hal_local_player.h"
#include "connection/connection_manager.h"
#include "hal_thread.h"
#include "hal_semaphore.h"
#include "hal_mutex.h"
#include "hal_log.h"
#include "hal_system.h"
#include <stdlib.h>
#include <string.h>

#define TAG "AUDIO_MGR"

/* 默认音频参数 */
#define DEFAULT_SAMPLE_RATE    16000
#define DEFAULT_CHANNELS       1
#define DEFAULT_BITS           16
#define DEFAULT_FRAME_MS       20

/* 播放预缓冲阈值，约 400ms 音频数据 */
#define PLAYBACK_PREFILL_BYTES (1280 * 10)

#define AUDIO_SEND_CBUF_SIZE   (128 * 1024)
#define AUDIO_SEND_FRAME_BYTES 640      /* 20ms @ 16kHz/mono/16bit */
#define AUDIO_SEND_DRAIN_MAX   4        /* 单次唤醒最多发送 4 帧 */

/* 下行解码分块 */
#define CODEC_DEC_CHUNK        320
static uint8_t s_dec_pcm[CODEC_DEC_CHUNK * 4];

/* 静音超时时长 */
#define SILENCE_DURATION_MS    600

/* 播放静音标志 */
static volatile bool s_should_silence = false;
static uint32_t s_silence_start_ms = 0;

/* 音频发送线程上下文 */
typedef struct {
    audio_cbuf_t            send_cbuf;
    uint8_t                *send_cbuf_mem;
    hal_thread_t            send_thread;
    hal_sem_t               send_sem;
    hal_mutex_t             send_mutex;
    engine_internal_ctx_t  *engine_ctx;
    volatile bool           send_running;
    uint8_t                 frame_buf[AUDIO_SEND_FRAME_BYTES];
} audio_send_ctx_t;

static audio_send_ctx_t s_send_ctx;

/* 音频发送线程 */
static void audio_send_thread_entry(void *arg)
{
    audio_send_ctx_t *sctx = (audio_send_ctx_t *)arg;

    while (sctx->send_running) {
        /* 50ms 超时定期检查 running 标志 */
        hal_sem_wait(sctx->send_sem, 50);

        if (!sctx->send_running) {
            break;
        }

        engine_internal_ctx_t *ctx = sctx->engine_ctx;
        if (!ctx || !ctx->ws_handle) {
            continue;
        }

        if (!conn_mgr_is_connected(ctx)) {
            /* 未连接时清空待发送数据 */
            hal_mutex_lock(sctx->send_mutex);
            audio_cbuf_clear(&sctx->send_cbuf);
            hal_mutex_unlock(sctx->send_mutex);
            continue;
        }

        /* 单次唤醒最多发送 AUDIO_SEND_DRAIN_MAX 帧 */
        int drained = 0;
        while (sctx->send_running && drained < AUDIO_SEND_DRAIN_MAX) {
            hal_mutex_lock(sctx->send_mutex);
            size_t rlen = audio_cbuf_read(&sctx->send_cbuf, sctx->frame_buf, AUDIO_SEND_FRAME_BYTES);
            hal_mutex_unlock(sctx->send_mutex);

            if (rlen == 0) {
                break;
            }

            if (!conn_mgr_is_connected(ctx)) {
                break;
            }

            conn_mgr_send_binary(ctx, sctx->frame_buf, rlen);
            drained++;
        }
    }
}

/* HAL 录音回调：写入发送缓冲并通知发送线程 */
static void recorder_data_callback(const void *pcm_data, size_t len, void *user_ctx)
{
    engine_internal_ctx_t *ctx = (engine_internal_ctx_t *)user_ctx;
    if (!ctx || !ctx->ws_handle) {
        return;
    }

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

    if (!s_send_ctx.send_running) {
        return;
    }

    /* 按键说话模式：未按下按键时不上行音频 */
    if (interact_mgr_get_mode(ctx) == AIAGENT_INTERACT_PRESS &&
        !ctx->press_capturing) {
        return;
    }

    /* g722 时先编码；raw16k 直通（out 直接指向原 PCM，零拷贝） */
    const void *out = pcm_data;
    size_t out_len = len;
    uint8_t enc_buf[AUDIO_SEND_FRAME_BYTES];
    if (ctx->audio_codec && !audio_codec_is_passthrough(ctx->audio_codec)) {
        int n = audio_codec_encode(ctx->audio_codec, pcm_data, (int)len,
                                   enc_buf, (int)sizeof(enc_buf));
        if (n <= 0) {
            return;
        }
        out = enc_buf;
        out_len = (size_t)n;
    }

    hal_mutex_lock(s_send_ctx.send_mutex);
    size_t wlen = audio_cbuf_write(&s_send_ctx.send_cbuf, out, out_len);
    hal_mutex_unlock(s_send_ctx.send_mutex);

    if (wlen == 0) {
        BD_LOGW(TAG, "send cbuf full, drop %d bytes", (int)out_len);
        return;
    }

    hal_sem_post(s_send_ctx.send_sem);
}

/* ========================================================================== */
/* 播放器事件回调                                                              */
/* ========================================================================== */

static void player_event_callback(hal_player_event_t event, void *user_ctx)
{
    engine_internal_ctx_t *ctx = (engine_internal_ctx_t *)user_ctx;
    if (!ctx) {
        return;
    }

    switch (event) {
    case HAL_PLAYER_EVENT_STARTED:
        BD_LOGD(TAG, "player started");
        break;
    case HAL_PLAYER_EVENT_STOPPED:
        BD_LOGD(TAG, "player stopped");
        break;
    case HAL_PLAYER_EVENT_UNDERRUN:
        BD_LOGD(TAG, "player underrun");
        break;
    case HAL_PLAYER_EVENT_ERROR:
        BD_LOGE(TAG, "player error");
        break;
    }
}

/* ========================================================================== */
/* 公开接口                                                                    */
/* ========================================================================== */

int audio_mgr_init(engine_internal_ctx_t *ctx, const audio_mgr_config_t *config)
{
    if (!ctx) {
        return -1;
    }

    int sample_rate = config ? config->sample_rate : DEFAULT_SAMPLE_RATE;
    int channels    = config ? config->channels    : DEFAULT_CHANNELS;
    int frame_ms    = config ? config->frame_ms    : DEFAULT_FRAME_MS;

    if (sample_rate <= 0) sample_rate = DEFAULT_SAMPLE_RATE;
    if (channels <= 0)    channels = DEFAULT_CHANNELS;
    if (frame_ms <= 0)    frame_ms = DEFAULT_FRAME_MS;

    /* 按配置的编码创建编解码器（raw16k 直通 / g722） */
    if (!ctx->audio_codec) {
        ctx->audio_codec = audio_codec_create(ctx->config.audio_codec);
    }

    memset(&s_send_ctx, 0, sizeof(s_send_ctx));
    s_send_ctx.send_cbuf_mem = (uint8_t *)malloc(AUDIO_SEND_CBUF_SIZE);
    if (!s_send_ctx.send_cbuf_mem) {
        BD_LOGE(TAG, "alloc send cbuf fail");
        return -1;
    }
    audio_cbuf_init(&s_send_ctx.send_cbuf, s_send_ctx.send_cbuf_mem, AUDIO_SEND_CBUF_SIZE);

    s_send_ctx.send_mutex = hal_mutex_create();
    if (!s_send_ctx.send_mutex) {
        BD_LOGE(TAG, "create send mutex fail");
        free(s_send_ctx.send_cbuf_mem);
        s_send_ctx.send_cbuf_mem = NULL;
        return -1;
    }

    s_send_ctx.send_sem = hal_sem_create(0);
    if (!s_send_ctx.send_sem) {
        BD_LOGE(TAG, "create send sem fail");
        hal_mutex_destroy(s_send_ctx.send_mutex);
        free(s_send_ctx.send_cbuf_mem);
        memset(&s_send_ctx, 0, sizeof(s_send_ctx));
        return -1;
    }

    s_send_ctx.engine_ctx = ctx;
    s_send_ctx.send_running = true;

    hal_thread_config_t send_thr_cfg;
    memset(&send_thr_cfg, 0, sizeof(send_thr_cfg));
    send_thr_cfg.name        = "audio_send";
    send_thr_cfg.entry       = audio_send_thread_entry;
    send_thr_cfg.arg         = &s_send_ctx;
    send_thr_cfg.stack_size  = 6144; /* WebSocket 加密发送线程栈大小 */
    send_thr_cfg.priority    = 15;
    send_thr_cfg.queue_size  = 8;

    s_send_ctx.send_thread = hal_thread_create(&send_thr_cfg);
    if (!s_send_ctx.send_thread) {
        BD_LOGE(TAG, "create send thread fail");
        hal_sem_destroy(s_send_ctx.send_sem);
        hal_mutex_destroy(s_send_ctx.send_mutex);
        free(s_send_ctx.send_cbuf_mem);
        memset(&s_send_ctx, 0, sizeof(s_send_ctx));
        return -1;
    }

    hal_recorder_config_t rec_cfg;
    memset(&rec_cfg, 0, sizeof(rec_cfg));
    rec_cfg.sample_rate     = sample_rate;
    rec_cfg.channels        = channels;
    rec_cfg.bits_per_sample = DEFAULT_BITS;
    rec_cfg.frame_ms        = frame_ms;
    rec_cfg.aec_enable      = ctx->config.aec_enable;
    rec_cfg.on_data         = recorder_data_callback;
    rec_cfg.user_ctx        = ctx;

    ctx->recorder_handle = hal_recorder_create(&rec_cfg);
    if (!ctx->recorder_handle) {
        BD_LOGE(TAG, "create recorder fail");
        return -1;
    }

    hal_player_config_t ply_cfg;
    memset(&ply_cfg, 0, sizeof(ply_cfg));
    ply_cfg.sample_rate     = sample_rate;
    ply_cfg.channels        = channels;
    ply_cfg.bits_per_sample = DEFAULT_BITS;
    ply_cfg.on_event        = player_event_callback;
    ply_cfg.user_ctx        = ctx;

    ctx->player_handle = hal_player_create(&ply_cfg);
    if (!ctx->player_handle) {
        BD_LOGE(TAG, "create player fail");
        hal_recorder_destroy(ctx->recorder_handle);
        ctx->recorder_handle = NULL;
        return -1;
    }

    int vol = ctx->config.volume;
    if (vol <= 0) vol = 30;
    hal_player_set_volume(ctx->player_handle, (uint8_t)vol);

    /* 本地播放器用于提示音 */
    ctx->local_player_handle = hal_local_player_create();
    if (!ctx->local_player_handle) {
        BD_LOGW(TAG, "create local player fail (non-fatal)");
    } else {
        hal_local_player_set_volume(ctx->local_player_handle, (uint8_t)vol);
    }

    BD_LOGI(TAG, "audio mgr init ok (sr=%d ch=%d frame=%dms)",
            sample_rate, channels, frame_ms);
    return 0;
}

int audio_mgr_start_record(engine_internal_ctx_t *ctx)
{
    if (!ctx || !ctx->recorder_handle) {
        return -1;
    }

    /* 新一轮会话复位编解码状态（含重连场景） */
    audio_codec_reset(ctx->audio_codec);

    /* 开始录音前清空发送缓冲区 */
    if (s_send_ctx.send_mutex) {
        hal_mutex_lock(s_send_ctx.send_mutex);
        audio_cbuf_clear(&s_send_ctx.send_cbuf);
        hal_mutex_unlock(s_send_ctx.send_mutex);
    }

    BD_LOGI(TAG, "start record (state=%d)", ctx->state);
    return hal_recorder_start(ctx->recorder_handle);
}

int audio_mgr_stop_record(engine_internal_ctx_t *ctx)
{
    if (!ctx || !ctx->recorder_handle) {
        return -1;
    }
    BD_LOGI(TAG, "stop record");
    return hal_recorder_stop(ctx->recorder_handle);
}

int audio_mgr_start_playback(engine_internal_ctx_t *ctx)
{
    if (!ctx || !ctx->player_handle) {
        return -1;
    }

    hal_player_stop(ctx->player_handle);

    hal_player_prepare(ctx->player_handle);

    BD_LOGI(TAG, "playback prepare (prefill %dB)", PLAYBACK_PREFILL_BYTES);
    return 0;
}

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

    /* 计算本次是否处于静音窗口（VOICE_COMING 后 SILENCE_DURATION_MS 内） */
    bool silence_now = false;
    if (s_should_silence) {
        uint32_t elapsed = hal_system_get_time_ms() - s_silence_start_ms;
        if (elapsed < SILENCE_DURATION_MS) {
            silence_now = true;
        } else {
            s_should_silence = false;
            s_silence_start_ms = 0;
            BD_LOGI(TAG, "静音超时自动恢复 (%d ms)", (int)elapsed);
        }
    }

    int total = 0;

    if (ctx->audio_codec && !audio_codec_is_passthrough(ctx->audio_codec)) {
        /* g722：分块解码为 PCM 后写入播放器 */
        const uint8_t *p = (const uint8_t *)data;
        int remain = (int)len;
        while (remain > 0) {
            int cin = (remain > CODEC_DEC_CHUNK) ? CODEC_DEC_CHUNK : remain;
            int n = audio_codec_decode(ctx->audio_codec, p, cin,
                                       s_dec_pcm, (int)sizeof(s_dec_pcm));
            if (n <= 0) {
                break;
            }
            if (silence_now) {
                memset(s_dec_pcm, 0, (size_t)n);
            }
            int w = hal_player_write(ctx->player_handle, s_dec_pcm, (size_t)n);
            if (w > 0) {
                total += w;
            }
            p += cin;
            remain -= cin;
        }
    } else {
        /* 直通：data 即 PCM */
        if (silence_now) {
            memset((void *)data, 0, len);
        }
        total = hal_player_write(ctx->player_handle, data, len);
    }

    /* 数据达到预缓冲阈值后启动 player */
    if (!hal_player_is_started(ctx->player_handle)) {
        if (hal_player_buffered_size(ctx->player_handle) >= PLAYBACK_PREFILL_BYTES) {
            BD_LOGI(TAG, "prefill done, start playback");
            hal_player_start(ctx->player_handle);
        }
    }

    return total;
}

int audio_mgr_stop_playback(engine_internal_ctx_t *ctx)
{
    if (!ctx || !ctx->player_handle) {
        return -1;
    }
    BD_LOGI(TAG, "stop playback");
    return hal_player_stop(ctx->player_handle);
}

void audio_mgr_prefill_silence(engine_internal_ctx_t *ctx)
{
    if (!ctx || !ctx->player_handle) {
        return;
    }

    int cur = hal_player_buffered_size(ctx->player_handle);
    int need = PLAYBACK_PREFILL_BYTES - cur;
    if (need <= 0) {
        return;
    }

    static const uint8_t s_silence_chunk[640] = {0};
    int written = 0;
    while (need > 0) {
        int chunk = need > (int)sizeof(s_silence_chunk)
                    ? (int)sizeof(s_silence_chunk) : need;
        int w = hal_player_write(ctx->player_handle, s_silence_chunk, chunk);
        if (w <= 0) {
            break;
        }
        need -= w;
        written += w;
    }
    BD_LOGI(TAG, "tts prefill silence +%dB (cbuf %d->%d)",
            written, cur, hal_player_buffered_size(ctx->player_handle));
}

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

    /* 停止流播放再播本地文件 */
    if (ctx->player_handle) {
        hal_player_stop(ctx->player_handle);
    }

    if (!ctx->local_player_handle) {
        BD_LOGW(TAG, "no local player");
        return -1;
    }

    BD_LOGI(TAG, "play local: %s", file_path);
    return hal_local_player_play(ctx->local_player_handle, file_path, NULL, NULL);
}

int audio_mgr_set_volume(engine_internal_ctx_t *ctx, int volume)
{
    if (!ctx) {
        return -1;
    }

    uint8_t vol = (uint8_t)(volume < 0 ? 0 : (volume > 100 ? 100 : volume));

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

int audio_mgr_set_aec(engine_internal_ctx_t *ctx, bool enable)
{
    (void)ctx;
    (void)enable;
    /* AEC 在录音器创建时配置，运行时切换需重建录音器 */
    BD_LOGI(TAG, "AEC %s (下次录音重启时生效)", enable ? "on" : "off");
    return 0;
}

void audio_mgr_set_silence(engine_internal_ctx_t *ctx, bool silence)
{
    (void)ctx;
    s_should_silence = silence;
    if (silence) {
        s_silence_start_ms = hal_system_get_time_ms();
        BD_LOGI(TAG, "播放静音开始 (voice coming)");
    } else {
        s_silence_start_ms = 0;
        BD_LOGI(TAG, "播放静音解除 (voice disappear)");
    }
}

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

    if (ctx->recorder_handle) {
        hal_recorder_destroy(ctx->recorder_handle);
        ctx->recorder_handle = NULL;
    }

    /* 销毁发送线程及缓冲区 */
    s_send_ctx.send_running = false;
    if (s_send_ctx.send_sem) {
        hal_sem_post(s_send_ctx.send_sem);  /* 唤醒线程退出 */
    }
    if (s_send_ctx.send_thread) {
        hal_thread_destroy(s_send_ctx.send_thread);
        s_send_ctx.send_thread = NULL;
    }
    if (s_send_ctx.send_sem) {
        hal_sem_destroy(s_send_ctx.send_sem);
        s_send_ctx.send_sem = NULL;
    }
    if (s_send_ctx.send_mutex) {
        hal_mutex_destroy(s_send_ctx.send_mutex);
        s_send_ctx.send_mutex = NULL;
    }
    if (s_send_ctx.send_cbuf_mem) {
        free(s_send_ctx.send_cbuf_mem);
        s_send_ctx.send_cbuf_mem = NULL;
    }
    s_send_ctx.engine_ctx = NULL;

    if (ctx->player_handle) {
        hal_player_destroy(ctx->player_handle);
        ctx->player_handle = NULL;
    }

    if (ctx->local_player_handle) {
        hal_local_player_destroy(ctx->local_player_handle);
        ctx->local_player_handle = NULL;
    }

    if (ctx->audio_codec) {
        audio_codec_destroy(ctx->audio_codec);
        ctx->audio_codec = NULL;
    }

    BD_LOGI(TAG, "audio mgr deinit");
}

void audio_mgr_clear_send_cbuf(engine_internal_ctx_t *ctx)
{
    (void)ctx;
    if (!s_send_ctx.send_mutex) {
        return;
    }
    hal_mutex_lock(s_send_ctx.send_mutex);
    audio_cbuf_clear(&s_send_ctx.send_cbuf);
    hal_mutex_unlock(s_send_ctx.send_mutex);
    BD_LOGD(TAG, "send cbuf cleared (TTS end)");
}
