#include "base.h"
#include "buffer.h"
#include "cae.h"
#include "cae_thread.h"
#include "dbus.h"
#include "error.h"
#include "msc.h"
#include "srcwsapi.h"
#include <cutils/cpu_info.h>
#include <jansson.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <uvdbus/crypto.h>
#include <uvdbus/libuv_dbus.h>
#include <uvdbus/log.h>
#include <uvdbus/server_addr.h>
#ifndef USED_NETEASE_AI
#include <msc/msp_cmn.h>
#include <msc/msp_errors.h>
#include <msc/qisr.h>
#else
#include "msp_errors.h"
#include "msp_types.h"
#endif

#if USED_NETEASE_DC
#include "dcapi.h"

//#define DC_URL ("https://vbox-server.3.163.com/vbox/uploadFile")

// static unsigned int g_isSessionOn = 0;
#endif

#define CUID ("1215468784532")

#if 0
#define APP_KEY_TEST ("vbox-dev")
#define APP_SECRET_TEST ("b1ec33c03df80ea3035bc9ccaa4af09c")
#define APP_POSTURL_TEST ("ws://vbox-test.netease.com/netty3/websocket")

#define APP_KEY ("vbox-online")
#define APP_SECRET ("8714d6de1c83f21dda5fc9a905a59ac1")
#define APP_POSTURL ("wss://vbox-asr.3.163.com/websocket")
#endif

#define AISPEECH_SDK_VERSION "aispeech_1806060936"

// extern unsigned int g_bIsUsedTestServer;

#ifdef USED_NETEASE_AI
int netease_audio_write(const char *sessionID, const void *waveData,
                        unsigned int waveLen, int audioStatus, int *epStatus,
                        int *recogStatus) {
    int ret;
    int vadstatus = getVadStatus();

    if (waveData == NULL || waveLen == 0) {
        return (MSP_SUCCESS);
    }
    // n_debug("Begint to write data!%d\n", waveLen);
    ret = SRCWsAudioWrite(sessionID, (const short *)waveData,
                          waveLen / sizeof(short), vadstatus, recogStatus);

    if (ret != SRC_SUCCESS) {
        LOG_EX(LOG_Error, "SRCWsAudioWrite Error: %d\n", ret);
        return (-1);
    }
    if (VoiceSession_Creating == getVss()) {
        if (VadStatus_Finish == vadstatus) {
            *epStatus = MSP_EP_AFTER_SPEECH;
        } else {
            *epStatus = MSP_EP_IN_SPEECH;
            *recogStatus = MSP_REC_STATUS_INCOMPLETE;
        }

        return (MSP_SUCCESS);
    }

    if (vadstatus == VadStatus_Finish) {
        *epStatus = MSP_EP_AFTER_SPEECH;
        return (MSP_SUCCESS);
    }

    if (*recogStatus != SRC_REC_SENT_AUDIO_SUCCESS) {
        if (*recogStatus == SRC_REC_SENT_AUDIO_END_DETECTED ||
            *recogStatus == SRC_REC_NLU_SUCCESS) {
            *epStatus = MSP_EP_AFTER_SPEECH;
            return (MSP_SUCCESS);
        }

        LOG_EX(LOG_Error, "Write Error: %d\n", *recogStatus);

        return -3;
    }

    // printf("+++++++++++++++++++++++++++++++++epStatus = %d, recogStatus =
    // %d\n", *epStatus, *recogStatus);
#if 0
    if (*epStatus == SRC_VAD_END_SPEECH)
    {
        *epStatus = MSP_EP_AFTER_SPEECH;
    }
    else {
        *epStatus = MSP_EP_IN_SPEECH;
    }

    if (*recogStatus == SRC_REC_SENT_AUDIO_SUCCESS) {
        *recogStatus = MSP_REC_STATUS_INCOMPLETE;
    }

    if (*recogStatus == SRC_REC_SENT_AUDIO_END_DETECTED) {
        *recogStatus = MSP_REC_STATUS_INCOMPLETE;
        *epStatus = MSP_EP_AFTER_SPEECH;        
    }
#endif
    *epStatus = MSP_EP_IN_SPEECH;

    // printf("---------------------------------epStatus = %d, recogStatus =
    // %d\n", *epStatus, *recogStatus);

    return (MSP_SUCCESS);
}

static void __logoutput(int level, const char *plogs) {}

const char *netease_get_result(const char *sessionID, int *rsltStatus,
                               int waitTime, int *errorCode) {
    const char *pSvrRet = NULL;

    *errorCode = MSP_SUCCESS;

    pSvrRet = SRCWsGetResult(sessionID, rsltStatus);

    if (*rsltStatus == SRC_REC_NLU_FAILED) {
        *errorCode = -1;
        return NULL;
    }

#if 0
    if (*rsltStatus == SRC_REC_NLU_SUCCESS) {
        *rsltStatus = MSP_REC_STATUS_COMPLETE;
    } else if(*rsltStatus == SRC_REC_SENT_AUDIO_SUCCESS) {        
        *rsltStatus = MSP_REC_STATUS_SUCCESS;
        pSvrRet = NULL;
    } else {
        LOG_EX(LOG_Error, "SRCWsGetResult Error:sessionID = %s, pSvrRet = [%s], rsltStatus = %d\n", 
               sessionID, pSvrRet, *rsltStatus);
        
        *rsltStatus = MSP_REC_STATUS_NO_MATCH;
        pSvrRet = NULL;
        *errorCode = -1;        
    }
#endif

    if (pSvrRet && SRC_REC_NLU_SUCCESS == *rsltStatus) {
        *rsltStatus = MSP_REC_STATUS_COMPLETE;
    } else {
        *rsltStatus = MSP_REC_STATUS_SUCCESS;
    }

    return (pSvrRet);
}

int netease_session_destroy(struct IAT_HD *hd) {
    int ret = -1;

    if (!hd)
        return ret;

#if USED_NETEASE_DC
    DCEndSession();
#endif

#if USED_NETEASE_AI
    ret = MSP_SUCCESS;
    SRCWsSessionEnd(hd->sessionId);
    hd->sessionId = NULL;
#else
    if (hd->sessionId) {
        n_debug("Del session:%s,%d\n", hd->sessionId, ret);
        ret = SRCWsSessionEnd(hd->sessionId);
        hd->sessionId = NULL;
    }
#endif

    if (ret == MSP_SUCCESS)
        hd->sessionId = NULL;

    return ret;
}

static char g_doabuf[32];

int netease_session_create(struct IAT_HD *hd, char *recType, char *confirmParam,
                           char *playerStatus) {
    int errcode;
#if USED_NETEASE_DC
    json_t *js = NULL;
    char *tmpdata;
#endif
    SRCParam srcParam;

    char *Uuid = getUuid();
    if (Uuid[0] == '\0') {
        Netease_dbus_initargs();
        Uuid = "this is default uuid";
    }

    memset(&srcParam, 0, sizeof(SRCParam));

    BaseLock();

    srcParam.appSecret = GetCurVoiceKeyValue(VOICE_APP_SECRET);
    srcParam.appKey = GetCurVoiceKeyValue(VOICE_APP_KEY);
    srcParam.URL = GetCurServerAddr(VOICE_MODULE);

    LOG_EX(LOG_Info, "URL: %s\n", srcParam.URL);
    LOG_EX(LOG_Info, "AppKey: %s\n", srcParam.appKey);
    // LOG_EX(LOG_Info, "AppSecret: %s\n", srcParam.appSecret);

#if 0
    if (g_bIsUsedTestServer) {
        srcParam.appSecret = APP_SECRET_TEST;
        srcParam.appKey = APP_KEY_TEST;
        srcParam.URL = APP_POSTURL_TEST;
    } else {
        srcParam.appSecret = APP_SECRET;
        srcParam.appKey = APP_KEY;
        srcParam.URL = APP_POSTURL;
    }
#endif

    srcParam.cuid = CUID;
    srcParam.severVadThresh1 = "1.5";
    srcParam.severVadThresh2 = "1.5";
    srcParam.timeOutResponseInMsec = "10000";
    srcParam.timeOutSpeechInMsec = "10000";
    srcParam.userId = Uuid;
    srcParam.speakerId = getChipId();
    srcParam.useClientVad = "0";
    srcParam.waitConnectTimeInMsec = "5000";
    srcParam.wkupSdkVersion = AISPEECH_SDK_VERSION;

    // fprintf(stdout, "userId = %s, speekId = %s\n", srcParam.userId,
    // srcParam.speakerId);

    SRCWsSetUPParam("aes", "0");
    SRCWsSetUPParam("uuid", Uuid);

    if (NULL != recType) {
        SRCWsSetUPParam("recType", recType);
        n_toast("RecType:%s\n", recType);
    } else {
        // 0  means normal
        SRCWsSetUPParam("recType", "0");
        n_toast("RecType:%s\n", "0");
    }

    if (NULL != confirmParam) {
        SRCWsSetUPParam("confirmParam", confirmParam);
        n_toast("Params:%s\n", confirmParam);
    }

    if (NULL != playerStatus) {
        n_toast("Set voice song info! %s\n", getSongInfo());
        SRCWsSetUPParam("sparam", playerStatus);
    } else if (strlen(getSongInfo()) > 0) {
        // printf("sonInfo: %s\n", getSongInfo());
        SRCWsSetUPParam("sparam", getSongInfo());
        n_toast("Song: %s\n", getSongInfo());
    }

    BaseUnlock();

    if (!hd)
        return (-1);

    // hd->sessionId = (char *)SRCWsSessionBegin(srcParam, &errcode, LogFunc,
    // NULL);
    hd->sessionId = NULL;
    hd->sessionId = (char *)SRCWsSessionBegin(srcParam, &errcode);

    // LOG_EX(LOG_Debug, "key = [%s], hd->sessionId = [%s], errcode = %d\n",
    // srcParam.appKey, hd->sessionId, errcode);

    if (SRC_REC_AUTHEN_SUCCESS != errcode || hd->sessionId == NULL ||
        strlen(hd->sessionId) == 0) {
        LOG_EX(LOG_Error, "Create Session Error: (%d)[%s]\n", errcode,
               SAFE_STRING_VALUE(hd->sessionId));
        hd->sessionId = NULL;
        return (-2);
    } else {
        LOG_EX(LOG_Debug, "Create new session(%s): [%s]\n", srcParam.appKey,
               hd->sessionId);
    }

#if USED_NETEASE_DC

    DCEndSession();

    DataColleParam dcParam;

    memset(g_doabuf, 0, 32);
    // sprintf(g_doabuf, "%d", hd->angle);
    sprintf(g_doabuf, "%d", getAng());

    dcParam.URL = GetCurServerAddr(DC_MODULE);

    LOG_EX(LOG_Info, "DC URL: %s\n", dcParam.URL);
    // dcParam.userId = Uuid;
    // dcParam.speakerId = getChipId();
    // dcParam.sessionId = hd->sessionId;
    // dcParam.doa = g_doabuf;

    // wakeupWord 	思必驰唤醒回调提供
    // major 	思必驰唤醒回调提供
    // status 	思必驰唤醒回调提供
    // confidence 	思必驰唤醒回调提供
    // doa 	思必驰唤醒回调提供
    // sessionid 	会话创建成功id号
    // wakeupsdk 	sdk厂家及版本
    // deviceid 	音箱ID
    // userid 	用户ID
    js = json_pack("{s:s, s:i, s:i, s:f, s:i, s:s, s:s, s:s, s:s}",
                   "wakeupWord", getVoiceWakeupword(), "major", getVoiceMajor(),
                   "status", getVoiceStatus(), "confidence",
                   getVoiceConfidence(), "doa", getAng(), "sessionid",
                   hd->sessionId, "wakeupsdk", AISPEECH_SDK_VERSION, "deviceid",
                   getChipId(), "userid", Uuid);

    if (js) {
        tmpdata = json_dumps(js, 0);
        if (tmpdata) {
            dcParam.info = tmpdata;
        }
        n_debug("Dc config:%s\n", tmpdata);
        json_decref(js);
    }
    // printf("+++++++++++dcParam.doa = %s\n", dcParam.doa);
    DCStartSession(dcParam);

    if (tmpdata) {
        free(tmpdata);
    }

    LOG_EX(LOG_Debug, "Beging WK Data\n");
    DCWriteAudioWk(getDCCachebuf(), WAKE_CACHE_DATA_SIZE);
    LOG_EX(LOG_Debug, "End WK Data\n");
    // g_isSessionOn = 1;
#endif

    return MSP_SUCCESS;
}

#if USED_NETEASE_DC
// unsigned int netease_dc_status(void) { return g_isSessionOn; }
// void netease_dc_clean_status(void) { g_isSessionOn = 0; }
#endif
#endif
