#include "xysdk_common.h"
#include "xysdk_play_list.h"
#include "xysdk_stream_play.h"

/**********************
 *  STATIC VARIABLES
 **********************/

volatile static xy_stream_status_e playing_status;//no need to save
static uint32_t player_base_timestamp=0;
static uint16_t player_process_time=0;
static xy_played_info_t *play_record = NULL;
static player_info_t *xy_play_info = NULL;
static playlist_array_t *xy_play_list = NULL;
stream_play_status_cb xy_status_cb;
/**********************
 *  STATIC PROTOTYPES
 **********************/

static void xy_local_music_set_playback_status(xy_stream_status_e play_status);
static void xy_set_base_timestamp(void);

/**********************
 *   STATIC FUNCTIONS
 **********************/

int xy_api_upload_play_record(void)
{
    int ret = 0;
    if(!play_record)
    {
        return XY_HTTP_PARAM_NULL;
    }

    play_record->played_duration = player_process_time - play_record->break_secs;
    play_record->break_secs = player_process_time;
    sprintf(play_record->end_at, "%s", xy_api_get_timestamp_ms_str());

    xy_play_info_upload_model *upload_data=(xy_play_info_upload_model *)xy_common_malloc(sizeof(xy_play_info_upload_model));
    if(!upload_data)
    {
        return XY_HTTP_MALLOC_ERR;
    }
    memset(upload_data, 0, sizeof(xy_play_info_upload_model));
    upload_data->count = 1;
    memcpy(&upload_data->play_array[0], play_record, sizeof(xy_played_info_t));
    xy_api_http_upload_play_history(upload_data);
    XY_LOG_I("HISTORY upload_data track_id: %s, ret: %d\n",upload_data->play_array[0].track_id, ret);
    if(play_record->played_duration != 0)
    {
        xy_api_http_upload_play_records(upload_data);
    }
    
    XY_LOG_I("RECORDS upload_data ret: %d\n", ret);
    xy_common_free((void **)&upload_data);

    return ret;
}


static bool xy_play_track_is_in_list(track_info_t *track_info, playlist_array_t *play_list)
{
    if(!track_info || !play_list || !play_list->track_list)
    {
        return false;
    }
    XY_LOG_I("album_id:%s-%s", track_info->album_id, play_list->album_id);
    if((!strcmp(track_info->album_id, play_list->album_id) && track_info->list_type == 0)
        || (!strcmp(track_info->listen_id, play_list->listen_id) && track_info->list_type == 1)
        || (track_info->list_type == 2))
    {
        XY_LOG_I("track_id:%s", track_info->track_id);
        if(xy_api_get_track_node(play_list->track_list, track_info->track_id)) //播放列表中存在该音频
        {
            return true;
        }
    }
    return false;
}

static int xy_save_play_list(playlist_array_t *play_list, xy_get_source_list_resp_model *tracks)
{
    int ret = XY_HTTP_OK;
    int i=0;
    if(!tracks || !play_list)
    {
        return XY_HTTP_PARAM_ERROR;
    }

    if(tracks->source_num==0 || tracks->source_total == 0)
    {
        return XY_HTTP_SERVER_DATA_ENPTY;
    }

    if(play_list->track_list)
    {
        xy_api_free_track_list(play_list->track_list);
    }
    
    play_list->track_total = tracks->source_total;
    play_list->track_num = tracks->source_num;
    play_list->cur_page = tracks->cur_page;

    play_list->track_list = xy_api_init_track_list();
    if(!play_list->track_list)
    {
        return XY_HTTP_MALLOC_ERR;
    }
   
    for(i=0;i<tracks->source_num;i++)
    {
        XY_LOG_I("tracks->source_array[%d].track_id:%s\n",i, tracks->source_array[i].track_id);   
        source_list_info_t *track_info = (source_list_info_t *)xy_common_malloc(sizeof(source_list_info_t));
        if(!track_info)
        {
            return XY_HTTP_MALLOC_ERR;
        }
        memset(track_info, 0, sizeof(source_list_info_t));
        memcpy(track_info, &tracks->source_array[i], sizeof(source_list_info_t));
        ret = xy_api_add_info_to_list(play_list->track_list, track_info);
        if(ret < 0)
        {
            return XY_HTTP_MALLOC_ERR;
        }
    }
    return ret;
}

static int xy_get_play_list_req(track_info_t *track_info)
{
    int ret = 0;

    if(!track_info || !xy_play_info || !xy_play_list)
    {
        return XY_HTTP_PARAM_ERROR;
    }

    //判断当前播放的音频是否在播放列表中，如果在播放列表中就不需要更新播放列表
    if(xy_play_track_is_in_list(track_info, xy_play_list))
    {
        XY_LOG_I("cur_track_id:%s in play_list", track_info->track_id);
        xy_play_list->cur_index = track_info->cur_index;
        return XY_HTTP_OK;
    }
    xy_get_source_list_resp_model *tracklist_resp_data = (xy_get_source_list_resp_model*)xy_common_big_mem_malloc(sizeof(xy_get_source_list_resp_model));
    if(!tracklist_resp_data)
    {
        return XY_HTTP_MALLOC_ERR;
    }

    if(track_info->list_type == 1)  //获取听单下的音频列表
    {
        xy_get_listen_list_req_model listen_list_req_data={0};
        strcpy(listen_list_req_data.id, track_info->listen_id);
        listen_list_req_data.page = track_info->cur_page;
        listen_list_req_data.limit = track_info->limit;
        ret = xy_api_http_get_listen_info(&listen_list_req_data, tracklist_resp_data);
    }
    else if(track_info->list_type == 2) //根据声音id获取列表
    {
        xy_get_track_req_model track_req_data={0};
        strcpy(track_req_data.track_id, track_info->track_id);
        strcpy(track_req_data.sort, "asc");
        track_req_data.page = track_info->cur_page;
        track_req_data.limit = track_info->limit;
        ret = xy_api_http_get_track_list_by_trackId(&track_req_data, tracklist_resp_data);
    }
    else //获取专辑下的音频列表
    {
        xy_get_track_list_req_model tracklist_req_data={0};
        strcpy(tracklist_req_data.album_id, track_info->album_id);
        strcpy(tracklist_req_data.sort, "asc");
        tracklist_req_data.page = track_info->cur_page;
        tracklist_req_data.limit = track_info->limit;
        tracklist_req_data.source_type = track_info->source_type;
        ret = xy_api_http_get_track_list_by_albumId(&tracklist_req_data, tracklist_resp_data);
    }

    if(ret == XY_HTTP_OK)
    {
        xy_play_list->list_type = track_info->list_type;
        xy_play_list->limit = track_info->limit;
        xy_play_list->album_type = track_info->album_type;
        xy_play_list->cur_index = track_info->cur_index;
     
        memset(xy_play_list->album_id, 0, sizeof(xy_play_list->album_id));
        sprintf(xy_play_list->album_id, "%s", track_info->album_id);
        memset(xy_play_list->listen_id, 0, sizeof(xy_play_list->listen_id));
        sprintf(xy_play_list->listen_id, "%s", track_info->listen_id);
        memset(xy_play_list->title, 0, sizeof(xy_play_list->title));
        sprintf(xy_play_list->title, "%s", track_info->title);
        XY_LOG_I("xy_play_list->title: %s",xy_play_list->title);
        xy_save_play_list(xy_play_list, tracklist_resp_data);
        XY_LOG_I("xy_play_list->album_id: %s",xy_play_list->album_id);
        xy_common_big_mem_free((void **)&tracklist_resp_data);
    }
    return ret;
}

static int xy_get_play_url_req(track_info_t *track_info)
{
    int ret = 0;

    if(!track_info || !xy_play_info)
    {
        return XY_HTTP_PARAM_ERROR;
    }
    
    if(strlen(xy_play_info->play_url)<5)
    {
        xy_get_url_req_model url_req_data={0};
        xy_get_url_resp_model *url_resp_data = (xy_get_url_resp_model *)xy_common_malloc(sizeof(xy_get_url_resp_model));
        if(!url_resp_data)
        {
            return XY_HTTP_MALLOC_ERR;
        }
        strcpy(url_req_data.track_id, track_info->track_id);
        url_req_data.pay_type = track_info->pay_type;
        url_req_data.source_type = track_info->source_type;
        if(track_info->pay_type == 1)
        {
            strcpy(url_req_data.album_id, track_info->album_id);  
            url_req_data.album_type = track_info->album_type;
        }
        
        ret = xy_api_http_get_play_url(&url_req_data, url_resp_data);
        if(ret == XY_HTTP_OK)
        {
            xy_play_info->play_size = url_resp_data->play_size;
            strcpy(xy_play_info->play_url, url_resp_data->url);
        }
        xy_common_free((void **)&url_resp_data);
    }
    return ret;
}

static void xy_local_music_set_playback_status(xy_stream_status_e play_status)
{
    playing_status = play_status;
}

static void xy_player_callback_func(xy_stream_status_e status)
{
    //XY_LOG_D("xy_player_callback_func: status %d \n", status);
    switch (status)
    {
        case XY_STREAM_PLAYER_SUSPEND:
            xy_local_music_set_playback_status(XY_STREAM_PLAYER_SUSPEND);
            break;

        case XY_STREAM_PLAYER_WAITING:
            xy_local_music_set_playback_status(XY_STREAM_PLAYER_WAITING);
            player_process_time = 0;
            break;

        case XY_STREAM_PLAYER_PLAY:
            xy_local_music_set_playback_status(XY_STREAM_PLAYER_PLAY);
            break;

        case XY_STREAM_PLAYER_END:
            xy_local_music_set_playback_status(XY_STREAM_PLAYER_END);
            break;

        case XY_STREAM_PLAYER_STOP:
            xy_local_music_set_playback_status(XY_STREAM_PLAYER_STOP);
            break;

        default:
            break;
    }

    if(xy_status_cb)
    {
        xy_status_cb(status);
    }
}
static int xy_music_play(void)
{
    XY_LOG_I("\n%s\n", __func__);
   
    uint32_t offset=0;
    player_info_t * info = xy_play_info;
    
    if (!info || strlen(info->play_url) == 0)
    {
        //XY_LOG_I("%s: play current mp3 ,path is NULL\n");
        return -1;
    }
    
    offset = info->play_size*player_process_time/info->cur_track.play_duration;
    XY_LOG_I("\ntrack_id: %s, player_process_time: %d, play_size: %d, play_duration: %d\n", info->cur_track.track_id, player_process_time, info->play_size, info->cur_track.play_duration);
    xy_stream_play_start(info->play_url, info->play_size, offset);
    xy_local_music_set_playback_status(XY_STREAM_PLAYER_PLAY);
    xy_set_base_timestamp();
    
    if(play_record)
    {
        memset(play_record, 0, sizeof(xy_played_info_t));
        play_record->played_duration = 0;
        play_record->break_secs = player_process_time;
        play_record->business_type = 0;
        sprintf(play_record->started_at, "%s", xy_api_get_timestamp_ms_str());
        sprintf(play_record->track_id, "%s", info->cur_track.track_id);
        sprintf(play_record->album_id, "%s", info->cur_track.album_id);
    }
    return 0;
}

uint16_t xy_api_get_play_progress(void)
{
    //XY_LOG_I("%s\n", __func__);
    track_info_t * info = xy_api_get_cur_playing_info();
    uint32_t system_time = xy_api_get_sys_time();
    //XY_LOG_I("system_time: %d, player_base_timestamp: %d\n", system_time, player_base_timestamp);
    if(info == NULL || system_time<player_base_timestamp || player_base_timestamp==0)
    {
        return 0.0f;
    }
    else
    {
        if(xy_api_get_player_status())
        {
            player_process_time += (uint16_t)(system_time - player_base_timestamp);
            player_base_timestamp = system_time;
            if(player_process_time >= info->play_duration)
            {
                player_process_time = info->play_duration;
                XY_LOG_I("%s, player_process_time: %d, info->play_duration: %d\n", __func__, player_process_time, info->play_duration);
            }
        }
        else
        {
            xy_set_base_timestamp();
        }
        
        return player_process_time;
    }
    return 0;
}

static void xy_set_base_timestamp(void)
{
    player_base_timestamp = xy_api_get_sys_time();
}

bool xy_api_get_player_status(void)
{
    if(playing_status == XY_STREAM_PLAYER_WAITING || playing_status == XY_STREAM_PLAYER_PLAY)
    {
        return true;
    }
    else
    {
        return false;
    }
}


track_info_t *xy_api_get_cur_playing_info(void)
{
    track_info_t * info = &xy_play_info->cur_track;
    if(!info || strlen(info->track_id)==0)
    {
        return NULL;
    }
    
    //XY_LOG_I("info->track_id: %s\n", info->track_id);   
    return info;
}

playlist_array_t *xy_api_get_play_list(void)
{
    playlist_array_t * list = xy_play_list;
    if(!list || list->track_num == 0)
    {
        return NULL;
    }
    
    XY_LOG_I("list->track_num: %d\n", list->track_num);   
    return list;
}

int xy_api_player_play(track_info_t *track_info)
{
    int ret=0;
    if(!track_info || !xy_play_info)
    {
        return XY_HTTP_PARAM_ERROR;
    }
    XY_LOG_I("%s: track_id: %s, playing track_id: %s\n", __func__, track_info->track_id, xy_play_info->cur_track.track_id);
    if (strlen(track_info->track_id) != 0 && !strcmp(xy_play_info->cur_track.track_id, track_info->track_id))
    {
        //播放同一个音频
        if(!xy_api_get_player_status())
        {
            xy_api_player_stop();
        }
        else
        {
            return XY_HTTP_OK;
        }
    }
    else 
    {
        xy_api_player_stop();
        memset(xy_play_info, 0, sizeof(player_info_t));
    }

    if(strlen(xy_play_info->play_url)<5)
    {
        memset(xy_play_info, 0, sizeof(player_info_t));
        memcpy(&xy_play_info->cur_track, track_info, sizeof(track_info_t));    
    }
    
    xy_get_play_list_req(track_info);  //先获取音频列表再获取播放地址，

    //获取播放URL
    ret = xy_get_play_url_req(track_info);
    if(ret != XY_HTTP_OK)
    {
        XY_LOG_W("get play url fail\n");
        return ret;
    }
    XY_LOG_I("%s: listen_id: %s, album_id: %s, list_type: %d\n", __func__, track_info->listen_id, track_info->album_id, track_info->list_type);
    XY_LOG_I("%s: cur_page: %d, pay_type: %d, track_id: %s\n", __func__, track_info->cur_page, track_info->pay_type, track_info->track_id);
    XY_LOG_I("%s: cur_index: %d, album_type: %d, play_duration: %d\n", __func__, track_info->cur_index, track_info->album_type, track_info->play_duration);
    
    player_process_time = track_info->play_offset;
    
    if(!xy_api_get_player_status())
    {
        ret = xy_music_play();
    }
    return ret;
}

int xy_api_player_resume(void)
{
    return xy_stream_play_resume();
}

int xy_api_player_pause(void)
{
    xy_api_get_play_progress();
    xy_local_music_set_playback_status(XY_STREAM_PLAYER_PAUSE);
    return xy_stream_play_pause();
}


int xy_api_player_stop(void)
{
    XY_LOG_I("%s\n", __func__);
    if(xy_api_get_player_status())
    {
        xy_api_get_play_progress();
    }
 
    xy_api_upload_play_record();
    player_process_time = 0;
    xy_local_music_set_playback_status(XY_STREAM_PLAYER_STOP);
    xy_stream_play_stop();
    return 0;
}

static int xy_set_track_common_info(track_info_t *track_info)
{
    if(!xy_play_list || !track_info)
    {
        return XY_HTTP_PARAM_NULL;
    }

    track_info->list_type = xy_play_list->list_type;
    track_info->limit = xy_play_list->limit;
    track_info->album_type = xy_play_list->album_type;
    memset(track_info->album_id, 0, sizeof(track_info->album_id));
    sprintf(track_info->album_id, "%s", xy_play_list->album_id);
    memset(track_info->listen_id, 0, sizeof(track_info->listen_id));
    sprintf(track_info->listen_id, "%s", xy_play_list->listen_id);
    memset(track_info->title, 0, sizeof(track_info->title));
    sprintf(track_info->title, "%s", xy_play_list->title);
    XY_LOG_I("xy_set_track_common_info album_title:%s", track_info->title);
    return 0;
}

static int xy_set_track_info(track_info_t *track_info, source_list_info_t *track_src)
{
    if(!track_src || !track_info)
    {
        return XY_HTTP_PARAM_NULL;
    }

    track_info->source_type = track_src->source_type;
    track_info->pay_type = track_src->pay_type;
    track_info->play_duration = track_src->play_duration;
    track_info->play_offset = 0;
    
    memset(track_info->track_id, 0,sizeof(track_info->track_id));
    sprintf(track_info->track_id, "%s", track_src->track_id);
    memset(track_info->track_name, 0,sizeof(track_info->track_name));
    sprintf(track_info->track_name, "%s", track_src->title);
    XY_LOG_I("xy_set_track_info track_name:%s", track_info->track_name);
    return 0;
}

//dir  0:上一页， 1:下一页
static int xy_play_list_change(track_info_t *track_info, uint8_t dir)
{
    int ret=0;
    uint16_t cur_page=0;
    uint16_t cur_list_index=0;
    if(!xy_play_list || !xy_play_info || !track_info)
    {
        return XY_HTTP_PARAM_NULL;
    }
    memset(track_info, 0, sizeof(track_info_t));
    track_info->source_type = xy_play_info->cur_track.source_type;

    if(dir == 0)
    {
        if(xy_play_list->cur_index == 0)
        {
            xy_play_list->cur_index = xy_play_list->track_total - 1;
        }
        else
        {
            xy_play_list->cur_index--;
        }
    }
    else
    {
        if(xy_play_list->cur_index == xy_play_list->track_total - 1)
        {
            xy_play_list->cur_index = 0;
        }
        else
        {
            xy_play_list->cur_index++;
        }
    }
    cur_page = xy_play_list->cur_index/xy_play_list->limit+1;
    XY_LOG_I("%s, track_info->cur_index :%d, cur_index: %d", __func__, track_info->cur_index, xy_play_list->cur_index);
    track_info->cur_index = xy_play_list->cur_index;
    
    xy_set_track_common_info(track_info);
    if(cur_page == xy_play_list->cur_page)
    {
        track_info->cur_page = xy_play_list->cur_page;
        ret = XY_HTTP_OK;
    }
    else
    {
        xy_play_list->cur_page = cur_page;
        track_info->cur_page = xy_play_list->cur_page;
        ret = xy_get_play_list_req(track_info);  //切换分页，更新播放列表
    }
    
    if(ret == XY_HTTP_OK)
    {
        cur_list_index =  xy_play_list->cur_index%xy_play_list->limit;
        XY_LOG_I("%s, cur_list_index :%d",__func__, cur_list_index);
        source_list_info_t *track_src = xy_api_get_track_info(xy_play_list->track_list, cur_list_index);
        if(track_src)
        {
            xy_set_track_info(track_info, track_src);
        }
        else
        {
            XY_LOG_I("xy_play_list_change track is null");
            return XY_HTTP_UNKNOW_ERR;
        }
    }
    return ret;
}

int xy_api_player_next(void)
{
    XY_LOG_I("%s\n", __func__);
    int ret=XY_HTTP_OK;

    if(!xy_play_list)
    {
        return XY_HTTP_PARAM_NULL;
    }
    track_info_t *track_info = (track_info_t*)xy_common_malloc(sizeof(track_info_t));
    ret = xy_play_list_change(track_info, 1);
    if(ret == XY_HTTP_OK)
    {
        xy_node_t* cur_node = xy_api_get_track_node(xy_play_list->track_list, track_info->track_id);
        if (cur_node == NULL)
        {
            XY_LOG_I("%s: no music find\n", __func__);
            xy_common_free((void **)&track_info);
            return -1;
        }

        ret = xy_api_player_play(track_info);
    }
    xy_common_free((void **)&track_info);
    
    return ret;
}

int xy_api_player_prev(void)
{
    XY_LOG_I("%s\n", __func__);
    int ret=XY_HTTP_OK;

    if(!xy_play_list)
    {
        return XY_HTTP_PARAM_NULL;
    }
    track_info_t *track_info = (track_info_t*)xy_common_malloc(sizeof(track_info_t));
    ret = xy_play_list_change(track_info, 0);
    if(ret == XY_HTTP_OK)
    {
        xy_node_t* cur_node = xy_api_get_track_node(xy_play_list->track_list, track_info->track_id);
        if (cur_node == NULL)
        {
            XY_LOG_I("%s: no music find\n", __func__);
            xy_common_free((void **)&track_info);
            return -1;
        }

        ret = xy_api_player_play(track_info);
        XY_LOG_I("xy_api_player_play ret: %d\n", ret);
    }
    xy_common_free((void **)&track_info);
    
    return ret;
}

int xy_api_player_init(stream_play_status_cb status_cb)
{
    if(!xy_play_info)
    {
        xy_play_info = (player_info_t *)xy_common_malloc(sizeof(player_info_t));
        if(!xy_play_info)
        {
            return XY_HTTP_MALLOC_ERR;
        }
    }

    if(!xy_play_list)
    {
        xy_play_list = (playlist_array_t *)xy_common_malloc(sizeof(playlist_array_t));
        if(!xy_play_list)
        {
            return XY_HTTP_MALLOC_ERR;
        }
    }

    if(!play_record)
    {
        play_record = (xy_played_info_t *)xy_common_malloc(sizeof(xy_played_info_t));
        if(!play_record)
        {
            return XY_HTTP_MALLOC_ERR;
        }
    }

    xy_status_cb = status_cb;
    xy_stream_play_init(xy_player_callback_func);  
    return XY_HTTP_OK;
}

int xy_api_player_deinit(void)
{
    xy_api_player_stop();
    xy_stream_play_destory();

    if(xy_play_info)
    {
        xy_common_free((void **)&xy_play_info);
    }

    if(xy_play_list)
    {
        if(xy_play_list->track_list)
        {
            xy_api_free_track_list(xy_play_list->track_list);
        }
        xy_common_free((void **)&xy_play_list);
    }

    if(play_record)
    {
        xy_common_free((void **)&play_record);
    }
    return XY_HTTP_OK;
}