/**
 * @file hal_audio_recorder.c
 * @brief HAL 音频录制实现（JieLi 平台）
 */

#include "hal_audio_recorder.h"
#include "hal_log.h"
#include "app_config.h"
#include "system/includes.h"
#include "server/audio_server.h"
#include "os/os_api.h"
#include <stdlib.h>
#include <string.h>

#define TAG  "HAL_REC"

typedef struct {
    hal_recorder_config_t   config;
    void                   *enc_server;
    OS_SEM                  data_sem;
    cbuffer_t               cbuf;
    u8                     *cbuf_data;
    int                     frame_samples; /* 每帧采样数 */
    int                     frame_bytes;   /* 每帧 PCM 字节数 */
    volatile bool           running;
    volatile bool           started;
} hal_recorder_impl_t;

/* VFS 写入回调，将录音 PCM 数据写入循环缓冲区 */
static int recorder_vfs_fwrite(void *file, void *data, u32 len)
{
    hal_recorder_impl_t *impl = (hal_recorder_impl_t *)file;
    if (!impl || !impl->running) {
        return len;
    }

    int wlen = cbuf_write(&impl->cbuf, data, len);
    if (wlen > 0) {
        os_sem_post(&impl->data_sem);
    }
    return len;
}

static int recorder_vfs_fclose(void *file)
{
    return 0;
}

static int recorder_vfs_flen(void *file)
{
    return 0;
}

static const struct audio_vfs_ops recorder_vfs_ops = {
    .fwrite = recorder_vfs_fwrite,
    .fclose = recorder_vfs_fclose,
    .flen   = recorder_vfs_flen,
};

/* 录音数据读取线程 */
static void recorder_feed_thread(void *priv)
{
    hal_recorder_impl_t *impl = (hal_recorder_impl_t *)priv;
    u8 *frame_buf = (u8 *)malloc(impl->frame_bytes);
    if (!frame_buf) {
        BD_LOGE(TAG, "alloc frame_buf fail");
        os_task_del_res(OS_TASK_SELF);
        return;
    }

    while (impl->running) {
        if (os_sem_pend(&impl->data_sem, 50) != OS_NO_ERR) {
            continue;
        }
        while (impl->running && cbuf_get_data_size(&impl->cbuf) >= impl->frame_bytes) {
            int rlen = cbuf_read(&impl->cbuf, frame_buf, impl->frame_bytes);
            if (rlen > 0 && impl->config.on_data) {
                impl->config.on_data(frame_buf, rlen, impl->config.user_ctx);
            }
        }
    }

    free(frame_buf);
    /* 线程退出前释放任务资源。 */
    os_task_del_res(OS_TASK_SELF);
}

hal_recorder_handle_t hal_recorder_create(const hal_recorder_config_t *config)
{
    if (!config || !config->on_data) {
        return NULL;
    }

    hal_recorder_impl_t *impl = (hal_recorder_impl_t *)zalloc(sizeof(hal_recorder_impl_t));
    if (!impl) {
        return NULL;
    }

    memcpy(&impl->config, config, sizeof(hal_recorder_config_t));

    /* 按采样率和帧长计算每帧采样数 */
    impl->frame_samples = config->sample_rate * config->frame_ms / 1000;
    if (impl->frame_samples <= 0) {
        impl->frame_samples = 320; /* 默认 16kHz、20ms */
    }

    /* 每帧字节数 = 采样数 × 声道 × 每样本字节数 */
    impl->frame_bytes = impl->frame_samples * config->channels
                        * (config->bits_per_sample / 8);
    if (impl->frame_bytes <= 0) {
        impl->frame_bytes = 1280; /* 默认帧字节数 */
    }

    /* 分配循环缓冲区 (存10帧数据) */
    int cbuf_size = impl->frame_bytes * 10;
    impl->cbuf_data = (u8 *)malloc(cbuf_size);
    if (!impl->cbuf_data) {
        free(impl);
        return NULL;
    }
    cbuf_init(&impl->cbuf, impl->cbuf_data, cbuf_size);

    os_sem_create(&impl->data_sem, 0);
    impl->running = false;
    impl->started = false;

    /* 打开 enc server */
    impl->enc_server = server_open("audio_server", "enc");
    if (!impl->enc_server) {
        BD_LOGE(TAG, "open enc server fail");
        os_sem_del(&impl->data_sem, 0);
        free(impl->cbuf_data);
        free(impl);
        return NULL;
    }

    return (hal_recorder_handle_t)impl;
}

int hal_recorder_start(hal_recorder_handle_t handle)
{
    if (!handle) {
        return -1;
    }
    hal_recorder_impl_t *impl = (hal_recorder_impl_t *)handle;

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

    cbuf_clear(&impl->cbuf);
    impl->running = true;

    /* 启动录音数据读取线程 */
    os_task_create(recorder_feed_thread, impl, 22, 4096, 0, "rec_feed");

    /* 配置并启动 enc server */
    union audio_req req = {0};
    req.enc.cmd = AUDIO_ENC_OPEN;
    req.enc.channel = impl->config.channels;
    req.enc.volume = 100;                               /* 录音增益 100% */
    req.enc.sample_rate = impl->config.sample_rate;
    req.enc.frame_size = impl->frame_samples;           /* 每帧采样数 */
    req.enc.output_buf_len = impl->frame_samples * 4;   /* 输出缓冲长度 */
    req.enc.format = "pcm";
    req.enc.sample_source = "mic";
    req.enc.vfs_ops = &recorder_vfs_ops;
    req.enc.file = (FILE *)impl;
    req.enc.use_vad = 0;                                /* 不使用VAD, 持续录音 */
    req.enc.msec = 0;                                   /* 0 = 永不停止 */

    /* AEC 回声消除配置 */
#ifdef CONFIG_AEC_ENC_ENABLE
    if (impl->config.aec_enable) {
#define AEC_EN  BIT(0)
#define NLP_EN  BIT(1)
#define ANS_EN  BIT(2)
        static struct aec_s_attr aec_param;
        memset(&aec_param, 0, sizeof(aec_param));
        aec_param.EnableBit = AEC_EN | NLP_EN | ANS_EN;
        aec_param.output_way = 0;           /* 软件参考信号 */
        aec_param.wideband = 1;             /* 宽带模式 */
        aec_param.hw_delay_offset = 30;     /* 硬件延迟偏移 */
        aec_param.dac_ref_sr = impl->config.sample_rate;
        req.enc.aec_enable = 1;
        req.enc.aec_attr = &aec_param;
        BD_LOGI(TAG, "AEC enabled");
    }
#endif

    /* 声道映射 */
    if (impl->config.channels == 4) {
        req.enc.channel_bit_map = 0x0f;
    } else if (impl->config.channels == 2) {
        req.enc.channel_bit_map = BIT(CONFIG_AUDIO_ADC_CHANNEL_L) | BIT(CONFIG_AUDIO_ADC_CHANNEL_R);
    } else {
        req.enc.channel_bit_map = BIT(CONFIG_AUDIO_ADC_CHANNEL_L);
    }

    int ret = server_request(impl->enc_server, AUDIO_REQ_ENC, &req);
    if (ret) {
        BD_LOGE(TAG, "enc open fail: %d", ret);
        impl->running = false;
        return -1;
    }

    impl->started = true;
    BD_LOGI(TAG, "recorder started, frame_samples=%d, frame_bytes=%d",
            impl->frame_samples, impl->frame_bytes);
    return 0;
}

int hal_recorder_stop(hal_recorder_handle_t handle)
{
    if (!handle) {
        return -1;
    }
    hal_recorder_impl_t *impl = (hal_recorder_impl_t *)handle;

    if (!impl->started) {
        return 0;
    }

    /* 关闭编码 */
    union audio_req req = {0};
    req.enc.cmd = AUDIO_ENC_CLOSE;
    server_request(impl->enc_server, AUDIO_REQ_ENC, &req);

    /* 通知录音读取线程退出并释放任务资源。 */
    impl->running = false;
    os_sem_post(&impl->data_sem);
    /* 等待录音读取线程完成退出 */
    os_time_dly(20);

    impl->started = false;
    BD_LOGI(TAG, "recorder stopped");
    return 0;
}

void hal_recorder_destroy(hal_recorder_handle_t handle)
{
    if (!handle) {
        return;
    }
    hal_recorder_impl_t *impl = (hal_recorder_impl_t *)handle;

    hal_recorder_stop(handle);

    if (impl->enc_server) {
        server_close(impl->enc_server);
    }

    os_sem_del(&impl->data_sem, 0);

    if (impl->cbuf_data) {
        free(impl->cbuf_data);
    }

    free(impl);
}
