#include "server/audio_server.h"
#include "server/server_core.h"
#include "server/ai_server.h"
#include "system/app_core.h"
#include "system/wait.h"
#include "system/timer.h"
#include "system/includes.h"
#include "wifi/wifi_connect.h"
#include "http/http_cli.h"
#include "generic/circular_buf.h"
#include "os/os_api.h"
#include "syscfg/syscfg_id.h"
#include "event/key_event.h"
#include "event/device_event.h"
#include "event/net_event.h"
#include "event/bt_event.h"
#include "fs/fs.h"
#include <time.h>
#include <curl/curl.h>
#include "web_socket/websocket_api.h"

#include "app_config.h"
#include "storage_device.h"

#include "app_power_manage.h"
#include "net/assign_macaddr.h"
#include "net/config_network.h"
#include "net/assign_macaddr.h"

#include "btstack/avctp_user.h"
#include "btctrler/btctrler_task.h"
#include "classic/hci_lmp.h"

#include "json_c/json.h"
#include "json_c/json_tokener.h"

#define INIT_VOLUME_VALUE   70

#define POWER_ON_FILE       CONFIG_VOICE_PROMPT_FILE_PATH"poweron.mp3"
#define FAIL_FILE           CONFIG_VOICE_PROMPT_FILE_PATH"AsrEmpty.mp3"
#define NET_UNVALID_FILE    CONFIG_VOICE_PROMPT_FILE_PATH"AiAsrFail.mp3"
#define CANCEL_FILE         CONFIG_VOICE_PROMPT_FILE_PATH"ring.mp3"
#define BT_OPEN_FILE        CONFIG_VOICE_PROMPT_FILE_PATH"BtOpen.mp3"
#define NET_CFG_ENTER_FILE  CONFIG_VOICE_PROMPT_FILE_PATH"NetCfgEnter.mp3"
#define NET_CFG_SUCC_FILE   CONFIG_VOICE_PROMPT_FILE_PATH"NetCfgSucc.mp3"
#define NET_CFG_FAIL_FILE   CONFIG_VOICE_PROMPT_FILE_PATH"NetCfgFail.mp3"
#define NET_CFG_TO_FILE     CONFIG_VOICE_PROMPT_FILE_PATH"NetCfgTo.mp3"
#define NET_EMPTY_FILE      CONFIG_VOICE_PROMPT_FILE_PATH"NetEmpty.mp3"
#define NET_CONN_FILE       CONFIG_VOICE_PROMPT_FILE_PATH"NetConnting.mp3"
#define NET_DISC_FILE       CONFIG_VOICE_PROMPT_FILE_PATH"NetDisc.mp3"
#define SSID_RECV_FILE      CONFIG_VOICE_PROMPT_FILE_PATH"SsidRecv.mp3"
#define SER_DISC_FILE       CONFIG_VOICE_PROMPT_FILE_PATH"SerDiscon.mp3"
#define OTA_IN_FILE         CONFIG_VOICE_PROMPT_FILE_PATH"OtaInUpdate.mp3"
#define OTA_FAIL_FILE       CONFIG_VOICE_PROMPT_FILE_PATH"OtaFailed.mp3"

#define HOST_NAME           "180.101.51.191"
#define WS_DEMO_URL         "ws://"HOST_NAME"/ws_process_audio"
#define REQ_BUFFER_SIZE     (512 * 1024)
#define RES_BUFFER_SIZE     (1024 * 1024)
#define RECV_BUFFER_SIZE    (512)
#define SEND_BUFFER_SIZE    (2 * 1024)

#define STOP_MSG            ("{\"message_type\": \"text\", \"content\": \"The pickup time exceeds the threshold")
#define DONE_MSG            ("{\"message_type\": \"text\", \"content\": \"done\"")

#define SH_OS_TASKQ_POST(name,argc, ...)                       \
    do{                                                         \
        int err =  os_taskq_post(name,argc, __VA_ARGS__);       \
        if(err){                                                \
            log_e("\n %s %d err = %d\n",__func__,__LINE__,err); \
        }                                                       \
    }while(0)

enum {
    SH_WS_CONN = 0,
    SH_WS_SEND_AUDIO,
    SH_WS_SEND_AUDIO_ALL,
    SH_WS_EXIT,
};

struct ws_interact_hdl {
    struct server *enc_server;      // 编码服务
    struct server *dec_server;      // 解码服务
    u8 volume;                      // 音频播放音量，50
    u8 gain;                        // 音频采集音量，100
    u8 channel;                     // 音频采集通道数，1
    char *format;                   // 音频格式，mp3
    const char *sample_source;      // 音频采集源，mic
    char *play_source;              // 音频播放源，dac
    int sample_rate;                // 音频采集采样率，16000
    u32 enc_time_msec;              // 音频采集时长ms，0：一直录; 60*1000ms

    // 音频采集
    volatile u8 enc_flag;           // 音频采集标志位，1：开始
    void *mic_buf;                  // 音频采集缓冲区，大小1MB
    u32 write_size;                 // 音频已采集大小
    u32 send_size;                  // 音频已发送大小
    OS_SEM mic_rsem;                // 音频读信号量
    u8 vad_start_flag;
    u8 vad_end_flag;
    u32 unvalid_size;               // 无效音频数据长度

    // 音频播放
    FILE *speaker_fp;               // 音频播放文件描述符，play_file用
    void *speaker_buf;              // 音频播放（接收）缓冲区，大小1MB
    cbuffer_t speaker_cbuf;         // 音频播放（接收）循环缓冲区，基于speaker_buf
    u32 recv_size;                  // 已接收音频数据长度
    u32 play_size;                  // 当前播放长度
    OS_SEM r_sem;                   // 读音频数据信号量
    volatile u8 dec_run_flag;       // 解码器播放标志，1：开始
    volatile u8 dec_ready_flag;     // 解码器就绪标志位，1：开始
    volatile u8 dec_status;         // 解码器运行标志位，1：开始
    volatile u8 recv_status;        // 音频接收完成状态，1：完成
    u8 dec_server_status;

    // websocket连接
    OS_MUTEX websockets_op_mutex;
    struct websocket_struct websockets_info;

    // 电量
    int battery_per;

    // 网络
    int reconnecting;
    int net_dhcp_ready;
    int net_connected;
    int bt_enable;
    u16 coexistence_timer;
};

static struct ws_interact_hdl ws_interact_handler;

#define __this (&ws_interact_handler)

extern void ble_cfg_net_result_notify(int event);
extern void wifi_return_sta_mode(void);
extern void bt_connection_disable(void);
extern void bt_connection_enable(void);
extern int app_music_bt_event_handler(struct sys_event *event);

static void websockets_disconnect(struct websocket_struct *websockets_info);
static int open_audio_dec(void* priv);

static void websockets_callback(u8 *buf, u32 len, u8 type)
{
    // printf("wbs recv msg : %s, len:%d\n", buf, len);
    bool is_fin = type & 0x80;
    u8 data_type = type & 0x0f;
    switch (data_type) {
    case WCT_SEQ:
        if (!is_fin) {
            printf("------not fin\n");
        } else {
            printf("------is fin\n");
        }
        break;
    case WCT_TXTDATA:
        printf("------txt data: %s\n", buf);
        // if (len > 0 && strncmp(buf, STOP_MSG, strlen(STOP_MSG)) == 0) {
        //     // 收到停止录音消息
        //     close_audio_enc();
        //     __this->dec_run_flag = 1;
        // } else 
        if (len >= 4 && strncmp(buf, DONE_MSG, strlen(DONE_MSG)) == 0) {
            // 收到回答发送结束消息
            printf("------receive done\n");
            __this->recv_status = 1;
        }
        break;
    case WCT_BINDATA:
        // 收到二进制音频数据
        printf("------bin data, len:%d\n", len);
        if (!__this->dec_run_flag) {
            return;
        }
        // __this->dec_run_flag = 1;
        u32 wlen = 0;
        while (len > 0) {
            size_t to_write = (len > RECV_BUFFER_SIZE) ? RECV_BUFFER_SIZE : len;
            wlen = cbuf_write(&__this->speaker_cbuf, buf, to_write);
            if (wlen) {
                os_sem_post(&__this->r_sem);
                __this->recv_size += to_write;
                //音频下载成功，或缓存成功，打开解码器，开始播放
                if (__this->recv_size >= 1 * 1024 && __this->dec_status == 0) {
                    if (thread_fork("open_audio_dec", 10, 1024, 0, NULL, open_audio_dec, NULL) != OS_NO_ERR) {
                        printf("open_audio_dec thread fork fail\n");
                    }
                    __this->dec_status = 1;
                }
            }
            // 更新指针和剩余数据大小
            buf = (char *)buf + to_write; // 移动指针
            len -= to_write;          // 减少剩余大小
        }

        break;
    case WCT_DISCONN:
        printf("------disconnect\n");
        close_audio_enc();
        __this->dec_run_flag = 0;
        __this->recv_status = 1;
        break;
    case WCT_PING:
        break;
    case WCT_PONG:
        break;
    case WCT_END:
        break;
    default:
        break;
    }
}

static void websockets_client_reg(struct websocket_struct *websockets_info, char mode)
{
    memset(websockets_info, 0, sizeof(struct websocket_struct));
    websockets_info->_init           = websockets_client_socket_init;
    websockets_info->_exit           = websockets_client_socket_exit;
    websockets_info->_handshack      = webcockets_client_socket_handshack;
    websockets_info->_send           = websockets_client_socket_send;
    websockets_info->_recv_thread    = websockets_client_socket_recv_thread;
    websockets_info->_heart_thread   = websockets_client_socket_heart_thread;
    websockets_info->_recv_cb        = websockets_callback;
    websockets_info->_recv           = NULL;

    websockets_info->websocket_mode  = mode;

#if 0
    //应用层指定申请接收内存大小（申请即可，不用释放，内部会释放），默认不使用
    websockets_info->recv_buf_size	 = 30 * 1024;
    websockets_info->recv_buf		 = malloc(websockets_info->recv_buf_size);
#endif
}

static int websockets_client_init(struct websocket_struct *websockets_info, u8 *url, const char *origin_str)
{
    websockets_info->ip_or_url = url;
    websockets_info->origin_str = origin_str;
    websockets_info->recv_time_out = 1000;

    //应用层和库的版本检测，结构体不一样则返回出错
    int err = websockets_struct_check(sizeof(struct websocket_struct));
    if (err == FALSE) {
        return err;
    }
    return websockets_info->_init(websockets_info);
}

static int websockets_client_handshack(struct websocket_struct *websockets_info)
{
    return websockets_info->_handshack(websockets_info);
}

static int websockets_client_send(struct websocket_struct *websockets_info, u8 *buf, int len, char type)
{
    int ret  = -1;
    os_mutex_pend(&__this->websockets_op_mutex, 0);
    if (websockets_info->websocket_valid == ESTABLISHED) {
        //SSL加密时一次发送数据不能超过16K，用户需要自己分包
        ret = websockets_info->_send(websockets_info, buf, len, type);
    }
    os_mutex_post(&__this->websockets_op_mutex);
    if (ret <= 0) {
        websockets_disconnect(websockets_info);
    }
    return ret;
}

static void websockets_client_exit(struct websocket_struct *websockets_info)
{
    websockets_info->_exit(websockets_info);
}

static int websockets_connect(void)
{
    int ret = 0;
    char mode = WEBSOCKET_MODE;
    struct websocket_struct *websockets_info = &__this->websockets_info;

    char src_buf[256] = {0};

    os_mutex_pend(&__this->websockets_op_mutex, 0);
    if (websockets_info->websocket_valid == ESTABLISHED) {
        os_mutex_post(&__this->websockets_op_mutex);
        return -1;
    }
    if (websockets_info->websocket_valid == INVALID_ESTABLISHED) {
        websockets_disconnect(websockets_info);
    }
    /* 1 . register */
    websockets_client_reg(websockets_info, mode);
    /* 2 . init */
    ret = websockets_client_init(websockets_info, WS_DEMO_URL, NULL);
    if (FALSE == ret) {
        printf("------Cilent websocket init error !!!\n");
        os_mutex_post(&__this->websockets_op_mutex);
        return -1;
    }
    /* 3 . hanshack */
    ret = websockets_client_handshack(websockets_info);
    if (FALSE == ret) {
        printf("------Handshake error !!!\n");
        os_mutex_post(&__this->websockets_op_mutex);
        return -1;
    }
    printf("------Handshake success\n");
    /* 4 . CreateThread */
    snprintf((char *)src_buf, sizeof(src_buf), "websocket_client_heart_%d", (u16)(random32(0) & 0xFFFF));
    thread_fork((const char *)src_buf, 19, 1024, 0,
                &websockets_info->ping_thread_id,
                websockets_info->_heart_thread,
                websockets_info);
    snprintf((char *)src_buf, sizeof(src_buf), "websocket_client_recv_%d", (u16)(random32(0) & 0xFFFF));
    thread_fork((const char *)src_buf, 18, 1024, 0,
                &websockets_info->recv_thread_id,
                websockets_info->_recv_thread,
                websockets_info);

    os_mutex_post(&__this->websockets_op_mutex);
    return 0;
}

static void websockets_disconnect(struct websocket_struct *websockets_info)
{
    int ret = 0;

    if (websockets_info->websocket_valid == NOT_ESTABLISHED) {
        return;
    }

    while (1) {
        printf("------websockets_disconnect enter\n");

        ret = os_mutex_pend(&__this->websockets_op_mutex, 10);
        if (ret == OS_NO_ERR) {
            if (websockets_info->websocket_valid != NOT_ESTABLISHED) {
                /* 6 . exit */
                websockets_info->websocket_valid = INVALID_ESTABLISHED;
                if (websockets_info->recv_thread_id) {
                    thread_kill(&websockets_info->recv_thread_id, KILL_WAIT);
                }
                if (websockets_info->ping_thread_id) {
                    thread_kill(&websockets_info->ping_thread_id, KILL_WAIT);
                }
                websockets_client_exit(websockets_info);
                websockets_info->websocket_valid = NOT_ESTABLISHED;
            }
            os_mutex_post(&__this->websockets_op_mutex);
        } else {
            if (websockets_info->websocket_valid != NOT_ESTABLISHED) {
                log_e("\n %s %d\n", __func__, __LINE__);
                continue;
            }
        }
        break;
    }

    printf("------websockets_disconnect exit\n");
}

static void ws_task(void *priv)
{
    int err = 0;
    int msg[32];
    // websockets_connect();

    while (1) {
        err = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
        if (err != OS_TASKQ || msg[0] != Q_USER) {
            continue;
        }
        switch (msg[1]) {
        case SH_WS_CONN:
            websockets_connect();
        case SH_WS_SEND_AUDIO:
            if (__this->write_size - __this->send_size >= SEND_BUFFER_SIZE) {
                printf("------write size:%d, send size:%d\n", __this->write_size, __this->send_size);
                err = websockets_client_send(&__this->websockets_info, 
                    __this->mic_buf + __this->send_size, 
                    SEND_BUFFER_SIZE, 
                    WCT_BINDATA);
                if (err <= 0) {
                    close_audio_enc();
                    __this->write_size = 0;
                    if (wifi_get_sta_connect_state() == WIFI_STA_NETWORK_STACK_DHCP_SUCC) {
                        play_mix_file(SER_DISC_FILE);
                    }
                }
                __this->send_size += SEND_BUFFER_SIZE;
            }
            break;
        case SH_WS_SEND_AUDIO_ALL:
            if (__this->write_size - __this->send_size >= 512) {
                printf("------write size:%d, send size:%d\n", __this->write_size, __this->send_size);
                err = websockets_client_send(&__this->websockets_info, 
                    __this->mic_buf + __this->send_size, 
                    __this->write_size - __this->send_size, 
                    WCT_BINDATA);
                __this->send_size = __this->write_size;
            }
            break;
        case SH_WS_EXIT:
            websockets_disconnect(&__this->websockets_info);
            break;
        default:
            break;
        }
    }
    printf("\n %s  exit \n", __func__);
}

static int ws_send_start_msg() {
    json_object *root = json_object_new_object();
    json_object_object_add(root, "message_type", json_object_new_string("text"));
    json_object_object_add(root, "content", json_object_new_string("recoding done"));

    return websockets_client_send(&__this->websockets_info, (u8 *)json_object_get_string(root), 
        strlen(json_object_get_string(root)), WCT_TXTDATA);
}

// 录音自定义文件写函数
static int recorder_vfs_fwrite(void *file, void *data, u32 len)
{
    size_t current_length = __this->write_size;
    
    // 检查缓冲区是否足够
    if (current_length + len >= REQ_BUFFER_SIZE) {
        printf("------Buffer overflow, response too large!\n");
        return 0; // 返回 0 以指示错误
    }

    // 直接将新数据写入缓冲区
    memcpy(__this->mic_buf  + current_length, data, len);
    // printf("------write:start:%d, len:%d", __this->write_size, len);
    __this->write_size += len;
    if (__this->vad_start_flag == 0) {
        __this->send_size = __this->write_size > SEND_BUFFER_SIZE ? __this->write_size - SEND_BUFFER_SIZE : 0;
    } else {
        if (__this->write_size - __this->send_size >= SEND_BUFFER_SIZE) {
            SH_OS_TASKQ_POST("ws_task", 1, SH_WS_SEND_AUDIO);
        }
    }

    return len;
}

// 录音自定义文件关闭函数
static int recorder_vfs_fclose(void *file)
{
    return 0;
}

// 录音自定义虚拟文件函数集
static const struct audio_vfs_ops recorder_vfs_ops = {
    .fwrite = recorder_vfs_fwrite,
    .fclose = recorder_vfs_fclose,
};

// 开始录音
static int open_audio_enc()
{
    printf("----------open_audio_enc----------\n");
    union audio_req req = {0};

    __this->enc_flag = 1;
    __this->write_size = 0;
    __this->send_size = 0;
    __this->vad_start_flag = 0;

    req.enc.cmd = AUDIO_ENC_OPEN;
    req.enc.channel = __this->channel;
    req.enc.volume = __this->gain;
    req.enc.frame_size = 1600;
    req.enc.output_buf_len = req.enc.frame_size * 10;
    req.enc.sample_rate = __this->sample_rate;
    req.enc.format = __this->format;
    req.enc.sample_source = __this->sample_source;
    req.enc.msec = __this->enc_time_msec;
    req.enc.vfs_ops = &recorder_vfs_ops;
    req.enc.file = (FILE *)__this->mic_buf;
    if (!strcmp(req.enc.format, "aac")) {
        req.enc.bitrate = __this->sample_rate * 4;
        req.enc.no_header = 1;
    }
    if (__this->channel == 4) {
        req.enc.channel_bit_map = 0x0f;
    } else if (__this->channel == 2) {
        req.enc.channel_bit_map = BIT(CONFIG_AUDIO_ADC_CHANNEL_L) | BIT(CONFIG_AUDIO_ADC_CHANNEL_R);
    } else {
        req.enc.channel_bit_map = BIT(CONFIG_AUDIO_ADC_CHANNEL_L);
    }

    // 使能 VAD
    req.enc.use_vad = 1;
    req.enc.dns_enable = 1;
    req.enc.vad_auto_refresh = 1;

    return server_request(__this->enc_server, AUDIO_REQ_ENC, &req);
}

// 停止录音
static int close_audio_enc()
{
    printf("----------close_audio_enc----------\n");
    union audio_req req = {0};

    if (!__this->enc_flag) {
        return 0;
    }
    __this->enc_flag = 0;

    if (__this->enc_server) {
        req.enc.cmd = AUDIO_ENC_CLOSE;
        server_request(__this->enc_server, AUDIO_REQ_ENC, &req);
    }

    return 0;
}

// 播放音频文件
static int play_file(const char* file_path)
{
    printf("----------local_dec_file:%s----------\n", file_path);
    int err = 0;
    union audio_req req = {0};

    FILE *file = NULL;
    file = __this->speaker_fp = fopen(file_path, "rb");

    if (!file) {
        printf("------file:%s open failed\n", file_path);
        return -1;
    }

    req.dec.cmd             = AUDIO_DEC_OPEN;
    req.dec.volume          = __this->volume;
    req.dec.output_buf_len  = 6 * 1024;
    req.dec.file            = file;
    req.dec.channel         = 0;
    req.dec.sample_rate     = 0;
    req.dec.priority        = 1;
    req.dec.sample_source   = __this->play_source;

    err = server_request(__this->dec_server, AUDIO_REQ_DEC, &req);
    if (err) {
        printf("------audio_dec_open: err = %d\n", err);
        fclose(file);
        __this->speaker_fp = NULL;
        return err;
    }

    req.dec.cmd = AUDIO_DEC_START;

    err = server_request(__this->dec_server, AUDIO_REQ_DEC, &req);
    if (err) {
        printf("------audio_dec_start: err = %d\n", err);
        fclose(file);
        __this->speaker_fp = NULL;
        return err;
    }
    __this->dec_server_status = AUDIO_DEC_START;

    return 0;
}

// 音频播放自定义虚拟文件读函数
static int play_vfs_fread(void *file, void *data, u32 len) {
    u32 rlen = 0;
    while (__this->dec_run_flag && __this->dec_ready_flag) {
        if (__this->recv_status && __this->recv_size - __this->play_size < RECV_BUFFER_SIZE) {
            len = __this->recv_size - __this->play_size;
        }

        rlen = cbuf_read(&__this->speaker_cbuf, data, len);
        if (rlen) {
            __this->play_size += rlen;

            if (__this->recv_status && __this->play_size >= __this->recv_size) {
                __this->dec_run_flag = 0;
                __this->dec_ready_flag = 0;
                printf("------res audio play complete!, play size:%d\n", __this->play_size);
            }
            break;
        }
        printf(">>>>>read pend......\n");
        os_sem_pend(&__this->r_sem, 0);
    }

    return ((__this->recv_status && __this->play_size >= __this->recv_size) ? 0 : len);
}

// 音频播放自定义虚拟文件获取长度函数
static int play_vfs_flen(void *priv)
{
    return RES_BUFFER_SIZE;
}

// 音频播放自定义虚拟文件定位函数
static int play_vfs_seek(void *priv, u32 offset, int orig)
{
    if (offset > 0) {
        __this->dec_ready_flag = 1; //解码器开始偏移数据后，再开始播放，避免音频播放开端吞字
    }
    return 0;
}

// 音频播放自定义虚拟文件函数集
static const struct audio_vfs_ops play_vfs_ops = {
    .fread  = play_vfs_fread,
    .flen   = play_vfs_flen,
    .fseek  = play_vfs_seek,
};

// 打开解码器
static int open_audio_dec(void* priv) {
    printf("----------open_audio_dec----------\n");
    int err = 0;
    union audio_req req = {0};

    req.dec.cmd             = AUDIO_DEC_OPEN;
    req.dec.volume          = __this->volume;
    req.dec.output_buf      = NULL;
    req.dec.output_buf_len  = 12 * 1024;
    req.dec.channel         = 0;
    req.dec.sample_rate     = 0;
    req.dec.priority        = 1;
    req.dec.sample_source   = __this->play_source;
    req.dec.dec_type 		= __this->format;
    req.dec.vfs_ops         = &play_vfs_ops;
    req.dec.file            = (FILE *)&__this->speaker_cbuf;

    //打开解码器
    err = server_request(__this->dec_server, AUDIO_REQ_DEC, &req);
    if (err) {
        printf("------audio_dec_open: err = %d\n", err);
        return err;
    }

    //开始解码
    req.dec.cmd = AUDIO_DEC_START;
    err = server_request(__this->dec_server, AUDIO_REQ_DEC, &req);
    if (err) {
        printf("------audio_dec_start: err = %d\n", err);
        return err;
    }
    __this->dec_server_status = AUDIO_DEC_START;

    return 0;
}

// 关闭解码器
static int close_audio_dec() {
    printf("----------close_audio_dec----------\n");
    union audio_req req = {0};
    req.dec.cmd = AUDIO_DEC_STOP;

    if (__this->dec_server) {
        if (__this->dec_server_status != AUDIO_DEC_STOP) {
            server_request(__this->dec_server, AUDIO_REQ_DEC, &req);
            __this->dec_server_status = AUDIO_DEC_STOP;
        }
    }

    if (__this->speaker_fp) {
        fclose(__this->speaker_fp);
        __this->speaker_fp = NULL;
    }

    // 重置音频播放（接收）状态
    __this->recv_size = 0;
    __this->play_size = 0;
    __this->dec_run_flag = 0;
    __this->dec_ready_flag = 0;
    __this->dec_status = 0;
    __this->recv_status = 0;
    os_sem_post(&__this->r_sem);
    cbuf_clear(&__this->speaker_cbuf);

    return 0;
}

// 编码器事件处理handler
static void enc_server_event_handler(void *priv, int argc, int *argv)
{
    switch (argv[0]) {
    case AUDIO_SERVER_EVENT_ERR:
    case AUDIO_SERVER_EVENT_END:
        printf("------mic record end! \n");
        close_audio_enc();
        break;
    case AUDIO_SERVER_EVENT_SPEAK_START:
        printf("------speak start ! \n");
        __this->vad_start_flag = 1;
        break;
    case AUDIO_SERVER_EVENT_SPEAK_STOP:
        printf("------speak stop ! \n");
        if (__this->vad_start_flag == 1) {
            __this->vad_end_flag = 1;
            SH_OS_TASKQ_POST("ws_task", 1, SH_WS_SEND_AUDIO_ALL);
            os_time_dly(5);
            if (ws_send_start_msg() > 0) {
                __this->dec_run_flag = 1;
            }
            close_audio_enc();
        }
        break;
    default:
        break;
    }
}

// 解码器事件处理handler
static void dec_server_event_handler(void *priv, int argc, int *argv)
{
    switch (argv[0]) {
    case AUDIO_SERVER_EVENT_ERR:
    case AUDIO_SERVER_EVENT_END:
        printf("----------audio dec end! \n");
        close_audio_dec();
        break;
    default:
        break;
    }
}

static void mix_dec_server_event_handler(void *priv, int argc, int *argv)
{
    union audio_req r = {0};

    switch (argv[0]) {
    case AUDIO_SERVER_EVENT_ERR:
        puts("------mix_music: AUDIO_SERVER_EVENT_ERR\n");
    case AUDIO_SERVER_EVENT_END:
        puts("------mix_music: AUDIO_SERVER_EVENT_END\n");
        r.dec.cmd = AUDIO_DEC_STOP;
        server_request(priv, AUDIO_REQ_DEC, &r);
        server_close(priv);
        fclose((FILE *)argv[1]);
        break;
    default:
        break;
    }
}

static int play_mix_file_failed_handler(void *server, FILE *file, int err)
{
    if (server) {
        server_close(server);
    }
    if (file) {
        fclose(file);
    }

    printf("------play_mix_music_file: fail : %d\n", err);

    return err;
}

static int play_mix_file(const char *path)
{
    int err = 0;
    union audio_req req = {0};

#if !defined CONFIG_AUDIO_MIX_ENABLE
    return 0;
#endif

    printf("------play_mix_file : %s\n", path);

    FILE *file = fopen(path, "r");
    if (!file) {
        return -ENOENT;
    }

    void *dec_server = server_open("audio_server", "dec");
    if (!dec_server) {
        return play_mix_file_failed_handler(dec_server, file, err);
    }
    server_register_event_handler_to_task(dec_server, dec_server, mix_dec_server_event_handler, "app_core");

    req.dec.cmd             = AUDIO_DEC_OPEN;
    req.dec.volume          = __this->volume;
    req.dec.output_buf_len  = 6 * 1024;
    req.dec.file            = file;
    req.dec.sample_source   = __this->play_source;

    err = server_request(dec_server, AUDIO_REQ_DEC, &req);
    if (err) {
        return play_mix_file_failed_handler(dec_server, file, err);
    }

    req.dec.cmd = AUDIO_DEC_START;

    err = server_request(dec_server, AUDIO_REQ_DEC, &req);
    if (err) {
        return play_mix_file_failed_handler(dec_server, file, err);
    }

    puts("------play_mix_music_file: suss\n");

    return 0;
}

// 模式初始化
static int ws_interact_mode_init(void)
{
    printf("------ws_interact mode init\n");

    memset(__this, 0, sizeof(struct ws_interact_hdl));
    __this->volume = INIT_VOLUME_VALUE;
    __this->gain = CONFIG_AUDIO_ADC_GAIN;
    __this->channel = CONFIG_AUDIO_RECORDER_CHANNEL;
    __this->format = CONFIG_AUDIO_RECORDER_SAVE_FORMAT;
    __this->sample_source = "mic";
    __this->play_source = CONFIG_AUDIO_DEC_PLAY_SOURCE;
    __this->sample_rate = CONFIG_AUDIO_RECORDER_SAMPLERATE;
    __this->enc_time_msec = CONFIG_AUDIO_RECORDER_DURATION;

    __this->enc_server = server_open("audio_server", "enc");
    server_register_event_handler_to_task(__this->enc_server, NULL, enc_server_event_handler, "app_core");

    __this->dec_server = server_open("audio_server", "dec");
    server_register_event_handler_to_task(__this->dec_server, NULL, dec_server_event_handler, "app_core");
    __this->dec_server_status = AUDIO_DEC_STOP;

    __this->mic_buf = malloc(REQ_BUFFER_SIZE);
    if (__this->mic_buf == NULL) {
        return -1;
    }

    __this->speaker_buf = malloc(RES_BUFFER_SIZE);
    if (__this->speaker_buf == NULL) {
        return -1;
    }
    cbuf_init(&__this->speaker_cbuf, __this->speaker_buf, RES_BUFFER_SIZE);
    os_sem_create(&__this->r_sem, 0);

    os_mutex_create(&__this->websockets_op_mutex);
    play_file(POWER_ON_FILE);
    thread_fork("ws_task", 15, 2 * 1024, 256, NULL, ws_task, NULL);

    return 0;
}

// 模式退出
static void ws_interact_mode_exit(void)
{
    printf("------ws_interact mode exit\n");
    close_audio_enc();
    close_audio_dec();
    server_close(__this->dec_server);
    __this->dec_server = NULL;

    server_close(__this->enc_server);
    __this->enc_server = NULL;

    if (__this->mic_buf) {
        free(__this->mic_buf);
        __this->mic_buf = NULL;
    }

    if (__this->speaker_buf) {
        free(__this->speaker_buf);
        __this->speaker_buf = NULL;
    }
    SH_OS_TASKQ_POST("ws_task", 1, SH_WS_EXIT);
}

// 按键事件
static int ws_interact_key_click(struct key_event *key)
{
    int ret = true;
    int ready = 0;
    enum wifi_sta_connect_state state;
    printf("ws_interact---> key value: %d <---",key->value);
    switch (key->value) {
    case KEY_OK:
        // low_power_all_group_force_sleep(10000000);
        if (__this->enc_flag) {
            // 当前正在录音，忽略按键功能
        } else if (__this->dec_run_flag) {
            // 当前正在播放，发送停止生成消息，取消播放
            __this->recv_status = 1;
            close_audio_dec();
            websockets_disconnect(&__this->websockets_info);
            play_mix_file(CANCEL_FILE);
        } else {
            // 当前空闲或正在进行音频播放，结束播放，开启录音
            state = wifi_get_sta_connect_state();
            printf("**************wifi_get_sta_connect_state: %d ********************\n", state);
            if (WIFI_STA_NETWORK_STACK_DHCP_SUCC == state) {
                SH_OS_TASKQ_POST("ws_task", 1, SH_WS_CONN);
                close_audio_dec();
                printf("----------------do mic audio record");
                open_audio_enc();
            } else {
                close_audio_dec();
                play_file(NET_UNVALID_FILE);
            }
        }
        break;
    default:
        ret = false;
        break;
    }

    return ret;
}

void ws_interact_ota_event_notify(int event) {
    if (event == AI_SERVER_EVENT_UPGRADE) {
        sys_power_auto_shutdown_pause();
        key_event_disable();
        play_mix_file(OTA_IN_FILE);
#ifdef CONFIG_LOW_POWER_ENABLE
        low_power_hw_unsleep_lock();
#endif
    } else if (event == AI_SERVER_EVENT_UPGRADE_SUCC) {
        // system_reset();
    } else if (event == AI_SERVER_EVENT_UPGRADE_FAIL) {
        key_event_enable();
        play_mix_file(OTA_FAIL_FILE);
        sys_power_auto_shutdown_resume();
#ifdef CONFIG_LOW_POWER_ENABLE
        low_power_hw_unsleep_unlock();
#endif
    }
}

static int app_music_bt_event_handler_pretreatment(struct bt_event *event)
{
    return 0;
}

static void switch_rf_coexistence_timer(void *p)
{
    __this->coexistence_timer = 0;

    switch_rf_coexistence_config_unlock();

#if defined CONFIG_BT_ENABLE && !BT_SUPPORT_WIFI_CFG_COEXISTENCE
    if (!is_in_config_network_state())
#endif
    {
        switch_rf_coexistence_config_table(0);
    }
}

static void app_net_config(void)
{
    __this->reconnecting = 0;
#ifdef CONFIG_ASSIGN_MACADDR_ENABLE
    cancel_server_assign_macaddr();
#endif

    if (!is_in_config_network_state()) {
        printf("------config_network_start\n");
        sys_power_auto_shutdown_pause();

        if (__this->coexistence_timer) {
            sys_timeout_del(__this->coexistence_timer);
            __this->coexistence_timer = 0;
            switch_rf_coexistence_config_unlock();
        }

#if defined CONFIG_BT_ENABLE && !BT_SUPPORT_WIFI_CFG_COEXISTENCE
        if (__this->bt_enable) {
            __this->bt_enable = 0;
            bt_connection_disable();
        }
#endif
        __this->net_connected = 0;
        play_file(NET_CFG_ENTER_FILE);
#ifdef CONFIG_SERVER_ASSIGN_PROFILE
        dev_profile_uninit();
#endif
        config_network_start();
    } else {
        printf("------config_network_stop\n");
        play_file(NET_CONN_FILE);
        config_network_stop();
        wifi_return_sta_mode();
#if defined CONFIG_BT_ENABLE && !BT_SUPPORT_WIFI_CFG_COEXISTENCE
        if (__this->bt_enable) {
            __this->bt_enable = 0;
            bt_connection_disable();
        }
#endif
        sys_power_auto_shutdown_resume();
    }
}

// 按键事件
static int ws_interact_key_double_click(struct key_event *key)
{
    int ret = true;
    int ready = 0;
    enum wifi_sta_connect_state state;
    printf("ws_interact---> key value: %d <---",key->value);
    switch (key->value) {
    case KEY_OK:
        printf("------switch_net_config\n");
        close_audio_enc();
        close_audio_dec();
        if (__this->bt_enable == 0) {
            __this->bt_enable = 1;
            bt_connection_enable();
        }
        app_net_config();
        break;
    default:
        ret = false;
        break;
    }

    return ret;
}

extern void start_http_upgrade_task(void *priv);

// 5次按键事件
static int ws_interact_key_firth_click(struct key_event *key)
{
    int ret = true;
    int ready = 0;
    enum wifi_sta_connect_state state;
    printf("ws_interact---> 5 key value: %d <---",key->value);
    switch (key->value) {
    case KEY_OK:
        start_http_upgrade_task(NULL);
        key_event_disable();
        break;
    default:
        ret = false;
        break;
    }

    return ret;
}

static int ws_interact_key_event_handler(struct key_event *key)
{
    if (is_in_config_network_state() && (key->action != KEY_EVENT_DOUBLE_CLICK || key->value != KEY_OK)) {
        //配网模式下只有配网键能起作用
        printf("------key event filter while config network\n");
        return true;	
    }
    switch (key->action) {
    case KEY_EVENT_CLICK:
        printf("  [KEY_EVENT_CLICK]  \n");
        return ws_interact_key_click(key);
    case KEY_EVENT_LONG:
        printf("  [KEY_EVENT_LONG]  \n");
        return ws_interact_key_click(key);
    case KEY_EVENT_HOLD:
        // printf("  [KEY_EVENT_HOLD]  \n");
        break;
    case KEY_EVENT_UP:
        // printf("  [KEY_EVENT_UP]  \n");
        break;
    case KEY_EVENT_DOUBLE_CLICK:
        printf("  [KEY_EVENT_DOUBLE_CLICK]  \n");
        return ws_interact_key_double_click(key);
    case KEY_EVENT_FIRTH_CLICK:
        printf("  [KEY_EVENT_FIRTH_CLICK]  \n");
        return ws_interact_key_firth_click(key);
    default:
        break;
    }

    return true;
}

static int ws_interact_device_event_handler(struct sys_event *sys_eve)
{
    struct device_event *device_eve = (struct device_event *)sys_eve->payload;

    if (sys_eve->from == DEVICE_EVENT_FROM_POWER) {
        if (device_eve->event == POWER_EVENT_POWER_CHANGE) {
            __this->battery_per = sys_power_get_battery_persent();
            printf("-----power_change: %d\n", __this->battery_per);
        } else if (device_eve->event == POWER_EVENT_POWER_WARNING) {
            printf("-----power_warning: %d\n", __this->battery_per);
        } else if (device_eve->event == POWER_EVENT_POWER_LOW) {
            printf("-----power_low: %d\n", __this->battery_per);
        } else if (device_eve->event == POWER_EVENT_POWER_AUTOOFF) {
            printf("-----power_autooff: %d\n", __this->battery_per);
        } else if (device_eve->event == POWER_EVENT_POWER_CHARGE) {
            printf("-----power_charge: %d\n", __this->battery_per);
        }
    }

    return true;
}

static int ws_interact_net_event_handler(struct net_event *event)
{
    if (ASCII_StrCmp(event->arg, "net", 4) == 0) {
        switch (event->event) {
        case NET_CONNECT_TIMEOUT_NOT_FOUND_SSID:
        case NET_CONNECT_ASSOCIAT_FAIL:
            printf("------wifi_connect_fail\n");
            play_mix_file(NET_CFG_FAIL_FILE);
            ble_cfg_net_result_notify(event->event);
            break;
        case NET_EVENT_SMP_CFG_FIRST:
            printf("------wifi empty\n");
            play_mix_file(NET_EMPTY_FILE);
            break;
        case NET_EVENT_SMP_CFG_FINISH:
            printf("------recv ssid\n");
            if (is_in_config_network_state()) {
                play_mix_file(SSID_RECV_FILE);
                config_network_stop();
                config_network_connect();
                sys_power_auto_shutdown_resume();
            }
            break;
        case NET_EVENT_CONNECTED:
            printf("------NET_EVENT_CONNECTED\n");
            __this->net_dhcp_ready = 1;
            if (!is_in_config_network_state()) {
                ble_cfg_net_result_notify(event->event);
                play_mix_file(NET_CFG_SUCC_FILE);
                __this->reconnecting = 0;
#ifdef CONFIG_SERVER_ASSIGN_PROFILE
                dev_profile_init();
#endif
            }
            __this->net_connected = 1;
            if (__this->coexistence_timer) {
                sys_timeout_del(__this->coexistence_timer);
                __this->coexistence_timer = 0;
                switch_rf_coexistence_config_unlock();
                switch_rf_coexistence_config_table(0);
            }
            break;
        case NET_EVENT_DISCONNECTED:
            printf("------NET_EVENT_DISCONNECTED\n");
            if (!__this->net_dhcp_ready) {
                break;
            }
            canceladdrinfo();
            __this->net_dhcp_ready = 0;
            __this->recv_status = 1;
            if (__this->net_connected && !is_in_config_network_state() && !__this->reconnecting) {
                play_mix_file(NET_DISC_FILE);
            }
            __this->net_connected = 0;
            break;
        case NET_EVENT_SMP_CFG_TIMEOUT:
            printf("------wifi connect timeout\n");
            if (is_in_config_network_state()) {
                play_mix_file(NET_CFG_TO_FILE);
            }
            break;
        case NET_SMP_CFG_COMPLETED:
            break;
        case NET_EVENT_DISCONNECTED_AND_REQ_CONNECT:
            wifi_return_sta_mode();
            break;
        case NET_NTP_GET_TIME_SUCC:	//NTP获取成功事件返回
            break;
        default:
            break;
        }
    }

    return true;
}

static int ws_interact_event_handler(struct application *app, struct sys_event *event)
{
    switch (event->type) {
    case SYS_KEY_EVENT:
        return ws_interact_key_event_handler((struct key_event *)event->payload);
    case SYS_DEVICE_EVENT:
        return ws_interact_device_event_handler(event);
    case SYS_NET_EVENT:
        return ws_interact_net_event_handler((struct net_event *)event->payload);
    case SYS_BT_EVENT:
        if (event->from == BT_EVENT_FROM_CON) {
            app_music_bt_event_handler_pretreatment((struct bt_event *)event->payload);
        }
        return app_music_bt_event_handler(event);
    default:
        return false;
    }
}

static int ws_interact_state_machine(struct application *app, enum app_state state, struct intent *it)
{
    switch (state) {
    case APP_STA_CREATE:
        break;
    case APP_STA_START:
        ws_interact_mode_init();
        break;
    case APP_STA_PAUSE:
        break;
    case APP_STA_RESUME:
        break;
    case APP_STA_STOP:
        ws_interact_mode_exit();
        break;
    case APP_STA_DESTROY:
        break;
    }

    return 0;
}

static const struct application_operation ws_interact_ops = {
    .state_machine  = ws_interact_state_machine,
    .event_handler 	= ws_interact_event_handler,
};

REGISTER_APPLICATION(ws_interact) = {
    .name 	= "ws_interact",
    .ops 	= &ws_interact_ops,
    .state  = APP_STA_DESTROY,
};
