#include "rtp.h"
#include "rtsp.h"
#include "rtsp_server.h"
#include "tuya_g711_utils.h"
#include "tuya_ipc_media.h"
#include "tuya_ring_buffer.h"
#include "ty_log.h"
#include "ty_user_types.h"
#include "ty_user_server.h"
#include <stdio.h>

typedef struct {
    int active;
    IPC_STREAM_E vchn;
    IPC_STREAM_E achn;
    RING_BUFFER_USER_HANDLE_T v_handle;
    RING_BUFFER_USER_HANDLE_T a_handle;
    int got_first_frame;
} RTSP_USER_INFO_T;

#define MAX_RTSP_USERS 2
#define RTSP_G711_BUFFER_LEN (1600)
static RTSP_USER_INFO_T sg_rtsp_users[MAX_RTSP_USERS] = { { 0 } };
static IPC_MEDIA_INFO_T sg_media_profiles;
static int sg_rtsp_init_flag = 0;

static int onvif_rtsp_user_start(void)
{
    int i = 0;
    for (i = 0; i < MAX_RTSP_USERS; i++) {
        if (0 == sg_rtsp_users[i].active) {
            sg_rtsp_users[i].active = 1;
            if (sg_rtsp_users[i].v_handle != NULL) {
                tuya_ipc_ring_buffer_close(sg_rtsp_users[i].v_handle);
                sg_rtsp_users[i].v_handle = NULL;
            }
            if (sg_rtsp_users[i].a_handle != NULL) {
                tuya_ipc_ring_buffer_close(sg_rtsp_users[i].a_handle);
                sg_rtsp_users[i].a_handle = NULL;
            }
            sg_rtsp_users[i].got_first_frame = 0;
            return i;
        }
    }
    return -1;
}

static int onvif_rtsp_user_stop(int user_id)
{
    sg_rtsp_users[user_id].active = 0;
    if (sg_rtsp_users[user_id].v_handle) {
        tuya_ipc_ring_buffer_close(sg_rtsp_users[user_id].v_handle);
        sg_rtsp_users[user_id].v_handle = NULL;
    }
    if (sg_rtsp_users[user_id].a_handle) {
        tuya_ipc_ring_buffer_close(sg_rtsp_users[user_id].a_handle);
        sg_rtsp_users[user_id].a_handle = NULL;
    }
    return 0;
}

static RTP_CODEC_E onvif_rtsp_get_codec(RTSP_MEDIA_TYPE_E type, IPC_STREAM_E index)
{
    switch (type) {
    case RTSP_MEDIA_TYPE_VIDEO: {
        if (sg_media_profiles.video_codec[index] == TUYA_CODEC_VIDEO_H265) {
            return RTP_CODEC_H265;
        } else {
            return RTP_CODEC_H264;
        }
    } break;
    case RTSP_MEDIA_TYPE_AUDIO: {
        if (sg_media_profiles.audio_codec[E_IPC_STREAM_AUDIO_MAIN] == TUYA_CODEC_AUDIO_G711U) {
            return RTP_CODEC_G711U;
        } else if (sg_media_profiles.audio_codec[E_IPC_STREAM_AUDIO_MAIN] == TUYA_CODEC_AUDIO_G711A) {
            return RTP_CODEC_G711A;
        } else if (sg_media_profiles.audio_codec[E_IPC_STREAM_AUDIO_MAIN] == TUYA_CODEC_AUDIO_PCM) {
            return RTP_CODEC_G711U; // RTSP 不支持 PCM, 需要转码
        } else {
            return RTP_CODEC_PCM;
        }
    } break;
    default:
        return RTP_CODEC_INVALID;
    }
}

static RTP_CODEC_E onvif_rtsp_get_codec_main(RTSP_MEDIA_TYPE_E type)
{
    return onvif_rtsp_get_codec(type, E_IPC_STREAM_VIDEO_MAIN);
}

static RTP_CODEC_E onvif_rtsp_get_codec_sub(RTSP_MEDIA_TYPE_E type)
{
    return onvif_rtsp_get_codec(type, E_IPC_STREAM_VIDEO_SUB);
}

static int onvif_rtsp_get_frame(int user_id, RTSP_MEDIA_TYPE_E type, char** buf, int* plen, UINT64_T* pts, IPC_STREAM_E index)
{
    static unsigned char s_g711_buffer[RTSP_G711_BUFFER_LEN] = { 0 }; // PCM 音频转换用
    unsigned int g711_buffer_len = RTSP_G711_BUFFER_LEN;              // PCM 音频转换用
    RTSP_USER_INFO_T* puser = &sg_rtsp_users[user_id];
    RING_BUFFER_NODE_T* pnode = NULL;

    puser->vchn = index;
    puser->achn = E_IPC_STREAM_AUDIO_MAIN;

    if (NULL == puser->v_handle) {
        puser->v_handle = tuya_ipc_ring_buffer_open(0, 0, puser->vchn, E_RBUF_READ);
        if (NULL == puser->v_handle) {
            TYERROR("users[%d] tuya_ipc_ring_buffer_open failed", user_id);
            return -1;
        }
    }
    if (NULL == puser->a_handle) {
        puser->a_handle = tuya_ipc_ring_buffer_open(0, 0, puser->achn, E_RBUF_READ);
        if (NULL == puser->a_handle) {
            TYERROR("users[%d] tuya_ipc_ring_buffer_open failed", user_id);
            return -1;
        }
    }

    if (puser->got_first_frame == 0) {
        tuya_ipc_ring_buffer_get_frame(puser->v_handle, 0);
        tuya_ipc_ring_buffer_anchor_user(puser->v_handle, 1, 1);
        puser->got_first_frame = 1;
    }

    if (type == RTSP_MEDIA_TYPE_VIDEO) {
        pnode = tuya_ipc_ring_buffer_get_frame(puser->v_handle, 0);
    } else {
        pnode = tuya_ipc_ring_buffer_get_frame(puser->a_handle, 0);
    }

    if (NULL == pnode) {
        return -1;
    }

    // PCM 格式的音频需要转码才能被RTSP客户端播放
    if (RTSP_MEDIA_TYPE_AUDIO == type
        && TUYA_CODEC_AUDIO_PCM == sg_media_profiles.audio_codec[E_IPC_STREAM_AUDIO_MAIN]) {
        // PCM  音频转换
        if (TUYA_AUDIO_SAMPLE_16K == sg_media_profiles.audio_sample[E_IPC_STREAM_AUDIO_MAIN]) {
            tuya_g711_encode_16K(TUYA_G711_MU_LAW, (unsigned short*)pnode->raw_data,
                                 pnode->size, s_g711_buffer, &g711_buffer_len);
        } else if (TUYA_AUDIO_SAMPLE_8K == sg_media_profiles.audio_sample[E_IPC_STREAM_AUDIO_MAIN]) {
            tuya_g711_encode(TUYA_G711_MU_LAW, (unsigned short*)pnode->raw_data,
                             pnode->size, s_g711_buffer, &g711_buffer_len);
        }

        *buf = (char*)s_g711_buffer;
        *plen = g711_buffer_len;
    } else {
        *buf = (char*)pnode->raw_data;
        *plen = pnode->size;
    }

    *pts = pnode->timestamp;

    return 0;
}

static int onvif_rtsp_get_frame_main(int user_id, RTSP_MEDIA_TYPE_E type, char** buf, int* plen, UINT64_T* pts)
{
    return onvif_rtsp_get_frame(user_id, type, buf, plen, pts, E_IPC_STREAM_VIDEO_MAIN);
}

static int onvif_rtsp_get_frame_sub(int user_id, RTSP_MEDIA_TYPE_E type, char** buf, int* plen, UINT64_T* pts)
{
    return onvif_rtsp_get_frame(user_id, type, buf, plen, pts, E_IPC_STREAM_VIDEO_SUB);
}

static int onvif_rtsp_get_sample_rate(RTSP_MEDIA_TYPE_E type, IPC_STREAM_E index)
{
    int sample = 8000;

    switch (type) {
    case RTSP_MEDIA_TYPE_VIDEO: {
        sample = 90000;
        break;
    }
    case RTSP_MEDIA_TYPE_AUDIO: {
        if (TUYA_CODEC_AUDIO_PCM == sg_media_profiles.audio_codec[E_IPC_STREAM_AUDIO_MAIN]) {
            // PCM 音频转换
            sample = 8000;
        } else {
            sample = sg_media_profiles.audio_sample[E_IPC_STREAM_AUDIO_MAIN];
        }
        break;
    }
    default: {
        sample = 8000;
    }
    }

    return sample;
}

static int onvif_rtsp_get_sample_rate_main(RTSP_MEDIA_TYPE_E type)
{
    return onvif_rtsp_get_sample_rate(type, E_IPC_STREAM_VIDEO_MAIN);
}

static int onvif_rtsp_get_sample_rate_sub(RTSP_MEDIA_TYPE_E type)
{
    return onvif_rtsp_get_sample_rate(type, E_IPC_STREAM_VIDEO_SUB);
}


static int onvif_rtsp_get_name(char* buf, int* buf_len, IPC_STREAM_E index)
{
    if (buf == NULL) {
        return -1;
    }

    sprintf(buf, "stream%d", index);
    return 0;
}

static int onvif_rtsp_get_name_main(char* buf, int* buf_len)
{
    return onvif_rtsp_get_name(buf, buf_len, E_IPC_STREAM_VIDEO_MAIN);
}

static int onvif_rtsp_get_name_sub(char* buf, int* buf_len)
{
    return onvif_rtsp_get_name(buf, buf_len, E_IPC_STREAM_VIDEO_SUB);
}

void __dump_ipc_media_info()
{
    int i = 0;
    for (i = 0; i < E_IPC_STREAM_MAX; i++) {
        if (sg_media_profiles.stream_enable[i]) {
            printf("===>%d, v_fps:%u,v_gop:%u,v_bitrate:%u,v_width:%u,v_height:%u,v_freq:%u,\
                            ,v_codec:%u,a_codec:%u,a_fps:%u,a_sample:%u,a_databits:%u,a_channel:%u\
                            \n", i, sg_media_profiles.video_fps[i], sg_media_profiles.video_gop[i],
                            sg_media_profiles.video_bitrate[i], sg_media_profiles.video_width[i],
                            sg_media_profiles.video_height[i], sg_media_profiles.video_freq[i], sg_media_profiles.video_codec[i],
                            sg_media_profiles.audio_codec[i], sg_media_profiles.audio_fps[i], sg_media_profiles.audio_sample[i],
                            sg_media_profiles.audio_databits[i], sg_media_profiles.audio_channel[i]);
        }
    }
}

int ty_user_rtsp_server_start(char *username, char *password, unsigned short rtsp_port, IPC_MEDIA_INFO_T* info)
{
    if (0 != sg_rtsp_init_flag) {
        TYERROR("rtsp already init");
        return 0;
    }

    if (username == NULL || password == NULL || info == NULL) {
        TYERROR("rtsp init param err");
        return -1;
    }

    memcpy(&sg_media_profiles, info, sizeof(IPC_MEDIA_INFO_T));

    tuya_ipc_rtsp_server_start(username, password, rtsp_port);

    RTSP_STREAM_SRC_T srcs[E_IPC_STREAM_VIDEO_4TH + 1] = { { 0 } };
    // main
    if (sg_media_profiles.stream_enable[E_IPC_STREAM_VIDEO_MAIN]) {
        srcs[E_IPC_STREAM_VIDEO_MAIN].get_codec = onvif_rtsp_get_codec_main;
        srcs[E_IPC_STREAM_VIDEO_MAIN].get_frame = onvif_rtsp_get_frame_main;
        srcs[E_IPC_STREAM_VIDEO_MAIN].get_sample_rate = onvif_rtsp_get_sample_rate_main;
        srcs[E_IPC_STREAM_VIDEO_MAIN].get_name = onvif_rtsp_get_name_main;
        srcs[E_IPC_STREAM_VIDEO_MAIN].start = onvif_rtsp_user_start;
        srcs[E_IPC_STREAM_VIDEO_MAIN].stop = onvif_rtsp_user_stop;
        tuya_ipc_rtsp_server_register_stream_src(&srcs[E_IPC_STREAM_VIDEO_MAIN]);
    }

    // sub
    if (sg_media_profiles.stream_enable[E_IPC_STREAM_VIDEO_SUB]) {
        srcs[E_IPC_STREAM_VIDEO_SUB].get_codec = onvif_rtsp_get_codec_sub;
        srcs[E_IPC_STREAM_VIDEO_SUB].get_frame = onvif_rtsp_get_frame_sub;
        srcs[E_IPC_STREAM_VIDEO_SUB].get_sample_rate = onvif_rtsp_get_sample_rate_sub;
        srcs[E_IPC_STREAM_VIDEO_SUB].get_name = onvif_rtsp_get_name_sub;
        srcs[E_IPC_STREAM_VIDEO_SUB].start = onvif_rtsp_user_start;
        srcs[E_IPC_STREAM_VIDEO_SUB].stop = onvif_rtsp_user_stop;
        tuya_ipc_rtsp_server_register_stream_src(&srcs[E_IPC_STREAM_VIDEO_SUB]);
    }

    sg_rtsp_init_flag = 1;
    return 0;
}

int ty_user_rtsp_server_stop(void)
{
    tuya_ipc_rtsp_server_stop();
    sg_rtsp_init_flag = 0;

    return 0;
}

int ty_user_rtsp_server_set_password(char* password)
{
    return tuya_ipc_rtsp_server_set_password(password);
}

int ty_user_rtsp_server_set_username(char* username)
{
    return tuya_ipc_rtsp_server_set_username(username);
}

int ty_user_get_rtsp_user_num()
{
    int i = 0;
    int num = 0;

    // 统计RTSP客户端数量
    for (i = 0; i < MAX_RTSP_USERS; i++) {
        if (1 == sg_rtsp_users[i].active) {
            num++;
        }
    }

    return num;
}

int ty_user_rtsp_server_set_port(unsigned short port)
{
    return tuya_ipc_rtsp_server_set_port(port);
}