/**
 * @file hal_audio_player.c
 * @brief HAL 流式音频播放实现（JieLi 平台）
 */

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

#define TAG  "HAL_PLY"

/* 播放启动期预置静音时长 */
#define HAL_PLY_LEAD_SILENCE_MS    80

typedef struct {
    hal_player_config_t     config;
    void                   *dec_server;
    cbuffer_t               cbuf;
    u8                     *cbuf_data;
    int                     cbuf_size;
    OS_SEM                  data_sem;
    OS_MUTEX                mutex;
    volatile bool           running;
    volatile bool           started;
    u8                      volume;
} hal_player_impl_t;

/* VFS ops —— dec server 通过 fread 从循环缓冲区读取PCM数据 */
static int player_vfs_fread(void *file, void *data, u32 len)
{
    hal_player_impl_t *impl = (hal_player_impl_t *)file;
    if (!impl || !impl->running) {
        return 0;
    }

    /* 尝试读取数据 */
    int rlen = cbuf_read(&impl->cbuf, data, len);
    if (rlen > 0) {
        return rlen;
    }

    /* 没有数据，阻塞等待(永久等待直到有数据或停止) */
    os_sem_pend(&impl->data_sem, 0);

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

    /* 再次尝试读取 */
    rlen = cbuf_read(&impl->cbuf, data, len);
    if (rlen > 0) {
        return rlen;
    }

    /* 仍然没有数据时填充静音数据，让解码器继续请求后续数据。 */
    memset(data, 0, len);
    return len;
}

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

static int player_vfs_flen(void *file)
{
    /* 返回 0 表示流式数据，大小未知 */
    return 0;
}

static int player_vfs_fseek(void *file, u32 offset, int orig)
{
    (void)file;
    (void)offset;
    (void)orig;
    return 0;
}

static const struct audio_vfs_ops player_vfs_ops = {
    .fread  = player_vfs_fread,
    .fclose = player_vfs_fclose,
    .flen   = player_vfs_flen,
    .fseek  = player_vfs_fseek,
};

hal_player_handle_t hal_player_create(const hal_player_config_t *config)
{
    if (!config) {
        return NULL;
    }

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

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

    /* 分配播放缓冲区 (2秒数据) */
    int bytes_per_sec = config->sample_rate * config->channels * (config->bits_per_sample / 8);
    impl->cbuf_size = bytes_per_sec * 2;
    impl->cbuf_data = (u8 *)malloc(impl->cbuf_size);
    if (!impl->cbuf_data) {
        free(impl);
        return NULL;
    }
    cbuf_init(&impl->cbuf, impl->cbuf_data, impl->cbuf_size);

    os_sem_create(&impl->data_sem, 0);
    os_mutex_create(&impl->mutex);
    impl->running = false;
    impl->started = false;
    impl->volume = 30;

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

    return (hal_player_handle_t)impl;
}

int hal_player_prepare(hal_player_handle_t handle)
{
    if (!handle) {
        return -1;
    }
    hal_player_impl_t *impl = (hal_player_impl_t *)handle;

    int bytes = (int)impl->config.sample_rate
              * impl->config.channels
              * (impl->config.bits_per_sample / 8)
              * HAL_PLY_LEAD_SILENCE_MS / 1000;

    static const uint8_t s_silence_chunk[640] = {0};
    int written = 0;
    while (bytes > 0) {
        int chunk = bytes > (int)sizeof(s_silence_chunk)
                    ? (int)sizeof(s_silence_chunk) : bytes;
        os_mutex_pend(&impl->mutex, 0);
        int w = cbuf_write(&impl->cbuf, (void *)s_silence_chunk, chunk);
        os_mutex_post(&impl->mutex);
        if (w <= 0) {
            break;
        }
        bytes -= w;
        written += w;
    }
    BD_LOGI(TAG, "prepare lead silence %dB", written);
    return 0;
}

int hal_player_start(hal_player_handle_t handle)
{
    if (!handle) {
        return -1;
    }
    hal_player_impl_t *impl = (hal_player_impl_t *)handle;

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

    impl->running = true;

    /* 配置并启动 dec server */
    union audio_req req = {0};
    req.dec.cmd = AUDIO_DEC_OPEN;
    req.dec.channel = impl->config.channels;
    req.dec.sample_rate = impl->config.sample_rate;
    req.dec.output_buf_len = 1280;   /* WS_PCM_FRAME_BYTES */
    req.dec.dec_type = "pcm";
    req.dec.priority = 1;
    req.dec.sample_source = "dac";
    req.dec.vfs_ops = &player_vfs_ops;
    req.dec.file = (FILE *)impl;
    req.dec.volume = impl->volume;

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

    req.dec.cmd = AUDIO_DEC_START;
    server_request(impl->dec_server, AUDIO_REQ_DEC, &req);

    impl->started = true;

    if (impl->config.on_event) {
        impl->config.on_event(HAL_PLAYER_EVENT_STARTED, impl->config.user_ctx);
    }

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

int hal_player_write(hal_player_handle_t handle, const void *data, size_t len)
{
    if (!handle || !data || len == 0) {
        return -1;
    }
    hal_player_impl_t *impl = (hal_player_impl_t *)handle;

    /* 允许在 dec_server 启动前写入数据 (预缓冲模式) */
    os_mutex_pend(&impl->mutex, 0);
    int wlen = cbuf_write(&impl->cbuf, (void *)data, len);
    os_mutex_post(&impl->mutex);

    if (wlen > 0 && impl->running) {
        os_sem_post(&impl->data_sem);
    }

    return wlen;
}

int hal_player_stop(hal_player_handle_t handle)
{
    if (!handle) {
        return -1;
    }
    hal_player_impl_t *impl = (hal_player_impl_t *)handle;

    if (!impl->started) {
        /* 即使未启动也清空缓冲区(支持预缓冲模式下重新开始) */
        cbuf_clear(&impl->cbuf);
        return 0;
    }

    union audio_req req = {0};
    req.dec.cmd = AUDIO_DEC_STOP;
    server_request(impl->dec_server, AUDIO_REQ_DEC, &req);

    impl->running = false;
    impl->started = false;
    os_sem_post(&impl->data_sem); /* 唤醒可能阻塞的fread */

    cbuf_clear(&impl->cbuf);

    if (impl->config.on_event) {
        impl->config.on_event(HAL_PLAYER_EVENT_STOPPED, impl->config.user_ctx);
    }

    BD_LOGI(TAG, "player stopped");
    return 0;
}

int hal_player_set_volume(hal_player_handle_t handle, uint8_t volume)
{
    if (!handle) {
        return -1;
    }
    hal_player_impl_t *impl = (hal_player_impl_t *)handle;
    impl->volume = volume;

    /* dec 处于 STOP 时也下发，下次启动沿用此音量 */
    if (impl->dec_server) {
        union audio_req req = {0};
        req.dec.cmd = AUDIO_DEC_SET_VOLUME;
        req.dec.volume = volume;
        int ret = server_request(impl->dec_server, AUDIO_REQ_DEC, &req);
        BD_LOGI(TAG, "set_volume=%u started=%d ret=%d",
                (unsigned)volume, (int)impl->started, ret);
    }
    return 0;
}

int hal_player_get_volume(hal_player_handle_t handle)
{
    if (!handle) {
        return -1;
    }
    return ((hal_player_impl_t *)handle)->volume;
}

bool hal_player_is_started(hal_player_handle_t handle)
{
    if (!handle) {
        return false;
    }
    return ((hal_player_impl_t *)handle)->started;
}

int hal_player_buffered_size(hal_player_handle_t handle)
{
    if (!handle) {
        return 0;
    }
    hal_player_impl_t *impl = (hal_player_impl_t *)handle;
    return cbuf_get_data_size(&impl->cbuf);
}

void hal_player_destroy(hal_player_handle_t handle)
{
    if (!handle) {
        return;
    }
    hal_player_impl_t *impl = (hal_player_impl_t *)handle;

    hal_player_stop(handle);

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

    os_sem_del(&impl->data_sem, 0);
    os_mutex_del(&impl->mutex, 0);

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

    free(impl);
}
