/**
 * @file audio_buffer.c
 * @brief 环形缓冲区实现
 */

#include "audio/audio_buffer.h"
#include <string.h>

/**
 * @brief 初始化环形缓冲区
 * @param cbuf 环形缓冲区结构体指针
 * @param buffer 外部提供的缓冲区内存
 * @param size 缓冲区大小（字节）
 * @return 0 成功，-1 参数错误
 */
int audio_cbuf_init(audio_cbuf_t *cbuf, uint8_t *buffer, size_t size)
{
    if (!cbuf || !buffer || size < 2) {
        return -1;
    }

    cbuf->buffer = buffer;
    cbuf->size = size;
    cbuf->read_pos = 0;
    cbuf->write_pos = 0;

    return 0;
}

/**
 * @brief 获取环形缓冲区中已有数据的大小
 * @param cbuf 环形缓冲区结构体指针
 * @return 已有数据字节数
 */
size_t audio_cbuf_get_data_size(const audio_cbuf_t *cbuf)
{
    if (!cbuf) {
        return 0;
    }

    return (cbuf->write_pos - cbuf->read_pos + cbuf->size) % cbuf->size;
}

/**
 * @brief 获取环形缓冲区中剩余空闲空间大小
 * @param cbuf 环形缓冲区结构体指针
 * @return 空闲空间字节数
 */
size_t audio_cbuf_get_free_size(const audio_cbuf_t *cbuf)
{
    if (!cbuf) {
        return 0;
    }

    size_t data_size = audio_cbuf_get_data_size(cbuf);
    return cbuf->size - 1 - data_size;
}

/**
 * @brief 向环形缓冲区写入数据
 * @param cbuf 环形缓冲区结构体指针
 * @param data 待写入数据指针
 * @param len 待写入数据长度
 * @return 实际写入的字节数
 */
size_t audio_cbuf_write(audio_cbuf_t *cbuf, const void *data, size_t len)
{
    if (!cbuf || !data || len == 0) {
        return 0;
    }

    /* 计算可用空闲空间 */
    size_t free_size = audio_cbuf_get_free_size(cbuf);
    if (len > free_size) {
        len = free_size;
    }
    if (len == 0) {
        return 0;
    }

    const uint8_t *src = (const uint8_t *)data;
    size_t write_pos = cbuf->write_pos;

    /* 计算从 write_pos 到缓冲区末尾的连续空间 */
    size_t tail_space = cbuf->size - write_pos;

    if (len <= tail_space) {
        /* 数据不需要绕回，直接拷贝 */
        memcpy(cbuf->buffer + write_pos, src, len);
    } else {
        /* 数据需要绕回，分两段拷贝 */
        memcpy(cbuf->buffer + write_pos, src, tail_space);
        memcpy(cbuf->buffer, src + tail_space, len - tail_space);
    }

    /* 更新写指针 */
    cbuf->write_pos = (write_pos + len) % cbuf->size;

    return len;
}

/**
 * @brief 从环形缓冲区读取数据
 * @param cbuf 环形缓冲区结构体指针
 * @param data 读取数据存放的缓冲区
 * @param len 期望读取的长度
 * @return 实际读取的字节数
 *
 * 如果可读数据不足，只读取实际可用的部分。
 */
size_t audio_cbuf_read(audio_cbuf_t *cbuf, void *data, size_t len)
{
    if (!cbuf || !data || len == 0) {
        return 0;
    }

    /* 计算可读数据量 */
    size_t data_size = audio_cbuf_get_data_size(cbuf);
    if (len > data_size) {
        len = data_size;
    }
    if (len == 0) {
        return 0;
    }

    uint8_t *dst = (uint8_t *)data;
    size_t read_pos = cbuf->read_pos;

    /* 计算从 read_pos 到缓冲区末尾的连续数据 */
    size_t tail_data = cbuf->size - read_pos;

    if (len <= tail_data) {
        /* 数据不需要绕回，直接拷贝 */
        memcpy(dst, cbuf->buffer + read_pos, len);
    } else {
        /* 数据需要绕回，分两段拷贝 */
        memcpy(dst, cbuf->buffer + read_pos, tail_data);
        memcpy(dst + tail_data, cbuf->buffer, len - tail_data);
    }

    /* 更新读指针 */
    cbuf->read_pos = (read_pos + len) % cbuf->size;

    return len;
}

/**
 * @brief 清空环形缓冲区
 * @param cbuf 环形缓冲区结构体指针
 *
 * 将读写指针复位为零，不清除实际内存内容。
 */
void audio_cbuf_clear(audio_cbuf_t *cbuf)
{
    if (!cbuf) {
        return;
    }

    cbuf->read_pos = 0;
    cbuf->write_pos = 0;
}
