#include "rgb_player.h"

#include <string.h>



/**
 * @brief 输出缓存中的数据
 * 
 * @param player 播放器实例
 * @param count 要输出的帧数
 */ 
static void rgb_player_output(rgb_player_t *player, uint16_t count)
{
    if (!player || !player->output_cb || !player->frame_cache || count == 0) {
        rt_kprintf("func: %s, invalid params.\r\n", __func__);
        return;
    }
    if (player->output_lock) {
        rt_mutex_take(player->output_lock, RT_WAITING_FOREVER);
    }
    player->output_cb(player->frame_cache, count);
    if (player->output_lock) {
        rt_mutex_release(player->output_lock);
    }
}

/**
 * @brief 清空缓存中的数据
 * 
 * @param player 播放器实例
 */ 
static void rgb_player_clear(rgb_player_t *player)
{
    if (!player || !player->frame_cache || player->frame_cache_size == 0) {
        return;
    }
    memset(player->frame_cache, 0, (size_t)player->frame_cache_size * sizeof(player->frame_cache[0]));
    rgb_player_output(player, player->frame_cache_size);
}

/**
 * @brief 查找指定名称的效果
 * 
 * @param player 播放器实例
 * @param name 效果名称
 * @return const rgb_effect_t* 效果指针
 */
static const rgb_effect_t *rgb_player_find_effect(const rgb_player_t *player, const char *name)
{
    if (!player || !name) {
        return RT_NULL;
    }
    return rgb_effect_find_by_name(player->effects, player->effect_count, name);
}

/**
 * @brief 获取当前播放效果的LED数量
 * 
 * @param player 播放器实例
 * @return uint32_t LED数量
 */
static uint32_t rgb_player_led_count(const rgb_player_t *player)
{
    if (!player || !player->fore_effect || player->frame_cache_size == 0) {
        rt_kprintf("func: %s, invalid params.\r\n", __func__);
        return 0;
    }

    uint32_t count = player->fore_effect->led_count;
    if (count > player->frame_cache_size) {
        count = player->frame_cache_size;
    }

    return count;
}

/**
 * @brief 获取当前帧的显示时间间隔
 * @param player rgb播放器对象
 * @return rt_tick_t 显示时间间隔（单位：毫秒）
 */ 
static rt_tick_t rgb_player_frame_interval(const rgb_player_t *player)
{
    if (!player) {
        return rt_tick_from_millisecond(10);
    }

    uint32_t ms = (player->fore_effect && player->fore_effect->frame_interval_ms) 
                  ? player->fore_effect->frame_interval_ms 
                  : 10;

    return rt_tick_from_millisecond(ms);
}

/**
 * @brief 渲染一帧数据
 * 
 * @param player 播放器实例
 * @return rt_err_t RT_EOK 成功, -RT_ERROR 失败
 */
static rt_err_t rgb_player_render(rgb_player_t *player)
{
    if (!player || player->state != RGB_PLAYER_STATE_PLAYING || !player->fore_effect || !player->fore_effect->frames || player->fore_effect->frame_count == 0) {
        rt_kprintf("func: %s, invalid params.\r\n", __func__);
        return -RT_ERROR;
    }

    const uint32_t *frame = rgb_effect_get_frame(player->fore_effect, player->frame_index);
    if (!frame) {
        player->state = RGB_PLAYER_STATE_STOPPED;
        player->frame_index = 0;
        return -RT_ERROR;
    }
    
    uint32_t count = rgb_player_led_count(player);
    if (count) {
        memcpy(player->frame_cache, frame, (size_t)count * sizeof(player->frame_cache[0]));
        rgb_player_output(player, count);
    }

    return RT_EOK;
}

/**
 * @brief 处理播放器事件
 * 
 * @param player 播放器实例
 * @param msg 事件消息
 */ 
static void rgb_player_event_handle(rgb_player_t *player, const rgb_player_msg_t *msg)
{
    if (!player || !msg) {
        rt_kprintf("func: %s, invalid params.\r\n", __func__);
        return;
    }

    switch (msg->event) {
    case RGB_PLAYER_EVENT_PLAY:
        /* 如果播放器是非播放状态，则先开启播放器后再播放 */
        if (player->state != RGB_PLAYER_STATE_PLAYING) {
            player->state = RGB_PLAYER_STATE_PLAYING;
            rgb_player_render(player);
        }
        break;
    case RGB_PLAYER_EVENT_PAUSE:
        /* 如果播放器是播放状态，则暂停播放 */
        if (player->state == RGB_PLAYER_STATE_PLAYING) {
            player->state = RGB_PLAYER_STATE_PAUSED;
        }
        break;
    case RGB_PLAYER_EVENT_STOP:  
        player->state = RGB_PLAYER_STATE_STOPPED;
        player->frame_index = 0;
        rgb_player_clear(player);
        break;
    case RGB_PLAYER_EVENT_SET_FORE_EFFECT:
        const rgb_effect_t *fore_eff = rgb_player_find_effect(player, msg->effect_name);
        if (fore_eff) {
            player->fore_effect = fore_eff;
            player->is_loop = msg->is_loop;
            if (msg->frame_index < fore_eff->frame_count) {
                player->frame_index = msg->frame_index;
            } else {
                player->frame_index = 0;
            }
            player->state = RGB_PLAYER_STATE_PLAYING;
            rgb_player_render(player);
        }
        break;
    case RGB_PLAYER_EVENT_SET_BACK_EFFECT:
        const rgb_effect_t *back_eff = rgb_player_find_effect(player, msg->effect_name);
        if (back_eff) {
            player->back_effect = back_eff;
        }
        break;
    case RGB_PLAYER_EVENT_NEXT_EFFECT:
        /* 如果当前播放器状态不是停止状态，则无法切换下一个灯效 */
        if (player->state != RGB_PLAYER_STATE_STOPPED) {
            const rgb_effect_t *next_eff = rgb_effect_next(player->effects, player->effect_count, player->fore_effect);
            if (next_eff) {
                uint16_t frame_index = msg->frame_index;
                if (frame_index >= next_eff->frame_count) {
                    frame_index = 0;
                }
                player->fore_effect = next_eff;
                player->frame_index = frame_index;
                player->is_loop = msg->is_loop;
                player->state = RGB_PLAYER_STATE_PLAYING;
                rgb_player_render(player);
            }
        }
        break;
    case RGB_PLAYER_EVENT_PREV_EFFECT:
        /* 如果当前播放器状态不是停止状态，则无法切换上一个灯效 */
        if (player->state != RGB_PLAYER_STATE_STOPPED) {
            const rgb_effect_t *prev_eff = rgb_effect_prev(player->effects, player->effect_count, player->fore_effect);
            if (prev_eff) {
                uint16_t frame_index = msg->frame_index;
                if (frame_index >= prev_eff->frame_count) {
                    frame_index = 0;
                }
                player->fore_effect = prev_eff;
                player->frame_index = frame_index;
                player->is_loop = msg->is_loop;
                player->state = RGB_PLAYER_STATE_PLAYING;
                rgb_player_render(player);
            }
        }
        break;
    case RGB_PLAYER_EVENT_SET_LOOP:
        player->is_loop = msg->is_loop;
        break;
    case RGB_PLAYER_EVENT_AUDIO_RHYTHM:
        /* 如果当前播放器状态是播放状态，则将播放器状态设置为暂停状态 */
        if ((player->state == RGB_PLAYER_STATE_PLAYING || player->state == RGB_PLAYER_STATE_PAUSED)
            && player->frame_cache && msg->frames && msg->led_count > 0 && player->frame_cache_size > 0) {
            uint16_t count = msg->led_count;
            if (count > player->frame_cache_size) {
                count = player->frame_cache_size;
            }
            player->state = RGB_PLAYER_STATE_PAUSED;
            if (count > 0) {
                memcpy(player->frame_cache, msg->frames, (size_t)count * sizeof(player->frame_cache[0]));
                rgb_player_output(player, count);
            }
        }
        break;
    case RGB_PLAYER_EVENT_SET_FIXED_COLORS:
        /* 如果当前播放器状态是播放状态，则将播放器状态设置为暂停状态 */
        if ((player->state == RGB_PLAYER_STATE_PLAYING || player->state == RGB_PLAYER_STATE_PAUSED)
            && player->frame_cache && msg->frames && msg->led_count > 0 && player->frame_cache_size > 0) {
            uint16_t count = msg->led_count;
            if (count > player->frame_cache_size) {
                count = player->frame_cache_size;
            }
            player->state = RGB_PLAYER_STATE_PAUSED;
            if (count > 0) {
                memcpy(player->frame_cache, msg->frames, (size_t)count * sizeof(player->frame_cache[0]));
                rgb_player_output(player, count);
            }
        }
        break;
    case RGB_PLAYER_EVENT_EXIT:
        player->exit_thread = true;
        break;
    default:
        rt_kprintf("func: %s, invalid event: %d.\r\n", __func__, msg->event);
        break;
    }
}

/**
 * @brief 渲染线程入口函数
 *
 * @param parameter 播放器实例指针
 */
static void rgb_player_thread_entry(void *parameter)
{
    rgb_player_t *player = (rgb_player_t *)parameter;
    rgb_player_msg_t msg;

    while (!player->exit_thread) {
        rt_kprintf("func: %s, state: %d.\r\n", __func__, player->state);
        rt_tick_t timeout = RT_WAITING_FOREVER;
        if (player->state == RGB_PLAYER_STATE_PLAYING && player->fore_effect && player->fore_effect->frames && player->fore_effect->frame_count) {
            timeout = rgb_player_frame_interval(player);
        }
        if (rt_mq_recv(&player->mq, &msg, sizeof(msg), timeout) == RT_EOK) {
            rgb_player_event_handle(player, &msg);
            continue;
        }
        if (player->state != RGB_PLAYER_STATE_PLAYING || !player->fore_effect || !player->fore_effect->frames || player->fore_effect->frame_count == 0) {
            continue;
        }

        rgb_player_render(player);

        player->frame_index++;
        if (player->frame_index >= player->fore_effect->frame_count) {
            if (player->is_loop) {
                player->frame_index = 0;
                continue;
            }
            if (player->back_effect) {
                player->fore_effect = player->back_effect;
                player->is_loop = true;
                player->frame_index = 0;
                rgb_player_render(player);
            } else {
                player->state = RGB_PLAYER_STATE_STOPPED;
                player->frame_index = 0;
            }
        }
    }
    player->state = RGB_PLAYER_STATE_STOPPED;
    player->frame_index = 0;
    rgb_player_clear(player);
    if (player->has_sem) {
        rt_sem_release(&player->sem);
    }
}

/**
 * @brief 打开RGB播放器
 *
 * @param player 播放器实例指针
 * @param cfg 播放器配置指针
 * @return rt_err_t 错误码
 */ 
rt_err_t rgb_player_open(rgb_player_t *player, const rgb_player_cfg_t *cfg)
{
    rt_err_t err;

    if (!player || !cfg) {
        rt_kprintf("func: %s, invalid parameter.\r\n", __func__);
        return -RT_ERROR;
    }
    if (!cfg->frame_cache || cfg->frame_cache_size == 0 || !cfg->output_cb) {
        rt_kprintf("func: %s, invalid parameter: frame_cache or frame_cache_size or output_cb.\r\n", __func__);
        return -RT_ERROR;
    }
    if (!cfg->mq_pool || cfg->mq_pool_size == 0 || !cfg->mq_name) {
        rt_kprintf("func: %s, invalid parameter: mq_pool or mq_pool_size or mq_name.\r\n", __func__);
        return -RT_ERROR;
    }
    if (!cfg->thread_name || !cfg->stack || cfg->stack_size == 0) {
        rt_kprintf("func: %s, invalid parameter: thread_name or stack or stack_size.\r\n", __func__);
        return -RT_ERROR;
    }

    memset(player, 0, sizeof(*player));
    player->is_inited = true;
    player->state = RGB_PLAYER_STATE_STOPPED;
    player->effects = cfg->effects;
    player->effect_count = cfg->effect_count;
    player->fore_effect = (cfg->fore_effect && cfg->effect_count > 0) ? cfg->fore_effect : RT_NULL;
    player->back_effect = cfg->back_effect;
    player->frame_index = 0;
    player->is_loop = false;
    player->frame_cache = cfg->frame_cache;
    player->frame_cache_size = cfg->frame_cache_size;
    player->output_cb = cfg->output_cb;
    player->output_lock = cfg->output_lock;
    player->exit_thread = false;

    err = rt_sem_init(&player->sem, cfg->sem_name ? cfg->sem_name : "rgbpm_sem", 0, RT_IPC_FLAG_FIFO);
    if (err != RT_EOK) {
        rt_kprintf("func: %s, init sem failed, err: %d.\r\n", __func__, err);
        return -RT_ERROR;
    }
    player->has_sem = true;

    err = rt_mq_init(&player->mq, cfg->mq_name, cfg->mq_pool, sizeof(rgb_player_msg_t), cfg->mq_pool_size, RT_IPC_FLAG_FIFO);
    if (err != RT_EOK) {
        rt_kprintf("func: %s, init mq failed, err: %d.\r\n", __func__, err);
        rt_sem_detach(&player->sem);
        player->has_sem = false;
        return -RT_ERROR;
    }

    err = rt_thread_init(&player->thread, cfg->thread_name, rgb_player_thread_entry, player, cfg->stack, cfg->stack_size, cfg->priority, cfg->timeslice);
    if (err != RT_EOK) {
        rt_kprintf("func: %s, init thread failed, err: %d.\r\n", __func__, err);
        rt_mq_detach(&player->mq);
        rt_sem_detach(&player->sem);
        player->has_sem = false;
        return -RT_ERROR;
    }

    rt_kprintf("func: %s, thread_name: %s, stack_size: %d, priority: %d, timeslice: %d.\r\n", __func__, cfg->thread_name, cfg->stack_size, cfg->priority, cfg->timeslice);
    rt_thread_startup(&player->thread);

    rt_kprintf("func: %s, started.\r\n", __func__);

    return RT_EOK;
}

/**
 * @brief 关闭RGB播放器
 *
 * @param player 播放器实例指针
 * @return rt_err_t 错误码
 */ 
rt_err_t rgb_player_close(rgb_player_t *player)
{
    rgb_player_msg_t msg;

    if (!player || !player->is_inited) {
        return -RT_ERROR;
    }

    if (rt_thread_self() != &player->thread) {
        memset(&msg, 0, sizeof(msg));
        msg.event = RGB_PLAYER_EVENT_EXIT;
        (void)rt_mq_send(&player->mq, &msg, sizeof(msg));
        if (player->has_sem) {
            (void)rt_sem_take(&player->sem, RT_WAITING_FOREVER);
        }
    }

    rt_thread_detach(&player->thread);
    rt_mq_detach(&player->mq);
    if (player->has_sem) {
        rt_sem_detach(&player->sem);
    }

    player->is_inited = false;

    return RT_EOK;
}

/**
 * @brief 发送RGB播放器事件
 *
 * @param player 播放器实例指针
 * @param msg 事件消息指针
 * @return rt_err_t 错误码
 */ 
rt_err_t rgb_player_send(rgb_player_t *player, const rgb_player_msg_t *msg)
{
    if (!player || !player->is_inited || !msg) {
        return -RT_ERROR;
    }
    return rt_mq_send(&player->mq, msg, sizeof(*msg));
}

/**
 * @brief 获取RGB播放器状态
 *
 * @param player 播放器实例指针
 * @return rgb_player_state_e 播放器状态
 */ 
rgb_player_state_e rgb_player_get_state(const rgb_player_t *player)
{
    if (!player || !player->is_inited) {
        return RGB_PLAYER_STATE_STOPPED;
    }
    return player->state;
}



