#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "app_protocol_api.h"
#include "system/includes.h"
#include "vm.h"
#include "audio_config.h"
#include "app_power_manage.h"
#include "user_cfg.h"

#if APP_PROTOCOL_GMA_CODE

#if 1
#define APP_GMA_LOG       printf
#define APP_GMA_DUMP      put_buf
#else
#define APP_GMA_LOG(...)
#define APP_GMA_DUMP(...)
#endif

//*********************************************************************************//
//                                 GMA认证信息                                      //
//*********************************************************************************//

#define GMA_GMA_FROM_FLASH      0
#define GMA_GMA_FROM_FILE       1

#define GMA_GMA_SOURCH     GMA_GMA_FROM_FLASH


extern int le_controller_set_mac(void *addr);
extern void lmp_hci_write_local_address(const u8 *addr);
extern void lmp_hci_read_local_address(u8 *addr);
extern void bt_update_testbox_addr(u8 *addr);

typedef struct {
    uint8_t mac[6];
    uint32_t pid;
    uint8_t secret[16];
} ali_para_s;

static ali_para_s ali_para;
static ali_para_s *active_ali_para = NULL;

///mac reverse
void gma_mac_addr_reverse_get(uint8_t *buf)
{
    memcpy(buf, (const void *)active_ali_para->mac, 6);
}

#define LEGAL_PID_NUM(cha) (cha>='0' && cha<='9')
#define LEGAL_MAC_NUM(cha) ((cha>='0'&&cha<='9') || (cha>='a'&&cha<='f') || (cha>='A'&&cha<='F') || (cha==':'))
#define LEGAL_SECRET_NUM(cha) ((cha>='0'&&cha<='9') || (cha>='a'&&cha<='f') || (cha>='A'&&cha<='F'))

#define USELESS_CHAR ':'
#define GMA_ALI_PARA_END_CHAR		','
#define GMA_ALI_PARA_MAC_CHAR_NUMS		(sizeof(((ali_para_s *)0)->mac))
#define GMA_ALI_PARA_PID_CHAR_NUMS		4//(sizeof(((ali_para_s *)0)->pid))
#define GMA_ALI_PARA_SECRET_CHAR_NUMS	(sizeof(((ali_para_s *)0)->secret))

static u8 gma_ali_para_char2num(u8 cha)
{
    u8 num = 0;

    if (cha >= '0' && cha <= '9') {
        num = cha - '0';
    } else if (cha >= 'a' && cha <= 'f') {
        num = cha - 'a' + 10;
    } else if (cha >= 'A' && cha <= 'F') {
        num = cha - 'A' + 10;
    }

    return num;
}

static int gma_license_set(ali_para_s *ali_para)
{
    const u8 *gma_ptr = (u8 *)app_protocal_get_license_ptr();

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

    ///license fill
    //pid
    memcpy((u8 *) & (ali_para->pid), gma_ptr, sizeof(ali_para->pid));
    gma_ptr += sizeof(ali_para->pid);
    APP_GMA_LOG("gma pid:%d \n", ali_para->pid);
    //secret
    memcpy((u8 *)(ali_para->secret), gma_ptr, sizeof(ali_para->secret));
    gma_ptr += sizeof(ali_para->secret);
    APP_GMA_LOG("gma secret:");
    APP_GMA_DUMP(ali_para->secret, sizeof(ali_para->secret));
    //mac
    memcpy((u8 *)(ali_para->mac), gma_ptr, sizeof(ali_para->mac));
    gma_ptr += sizeof(ali_para->mac);
    {
        //mac reverse
        u8 mac_backup_buf[6];
        memcpy(mac_backup_buf, ali_para->mac, 6);
        int i;
        for (i = 0; i < 6; i++) {
            ali_para->mac[i] = (mac_backup_buf)[5 - i];
        }
    }
    APP_GMA_LOG("gma mac:");
    APP_GMA_DUMP(ali_para->mac, sizeof(ali_para->mac));

    return 0;
}

#if GMA_GMA_SOURCH == GMA_GMA_FROM_FILE

#define ALI_PARA_ACTIVE_NUM               1

static const char *ali_para_string[] = {
    "jl_auif",
    //Product ID,Device Secret,Mac,Md5
    //此处可以用户自行填写从阿里申请的三元组信息
    " ",
};

static bool gma_ali_para_info_fill(const u8 *para, ali_para_s *ali_para)
{
    const u8 *para_string = para;
    u8 highbit_en = 0;
    uint32_t pid = 0;
    uint32_t char_nums = 0;
    uint8_t *secret = ali_para->secret;
    uint8_t *mac = ali_para->mac;

    while (*para_string && *para_string != GMA_ALI_PARA_END_CHAR) {
        if (!LEGAL_PID_NUM(*para_string)) {
            /* APP_GMA_LOG("pid illegal character !!! \n"); */
            para_string++;
            continue;
        }

        ///check pid character numbers legal scope
        char_nums++;
        if (char_nums > GMA_ALI_PARA_PID_CHAR_NUMS) {
            APP_GMA_LOG("pid character numbers overflow !!! \n");
            return false;
        }

        pid *= 10;
        pid += gma_ali_para_char2num(*para_string);
        para_string++;
    }

    ///check pid character numbers legal scope
    if (char_nums != GMA_ALI_PARA_PID_CHAR_NUMS) {
        APP_GMA_LOG("pid character numbers error:%d !!! \n", char_nums);
        return false;
    }

    APP_GMA_LOG(">>pid:%d \n", pid);
    ali_para->pid = pid;

    para_string++;
    char_nums = 0;
    memset(ali_para->secret, 0x00, sizeof(ali_para->secret));
    while (*para_string != GMA_ALI_PARA_END_CHAR) {
        if (!LEGAL_SECRET_NUM(*para_string)) {
            APP_GMA_LOG("secret illegal character !!! \n");
            para_string++;
            continue;
        }

        ///assignment secret
        if (!highbit_en) {
            *secret += gma_ali_para_char2num(*para_string);
            highbit_en ^= 1;
        } else {
            ///check secret character numbers legal scope
            char_nums++;
            if (char_nums > GMA_ALI_PARA_SECRET_CHAR_NUMS) {
                APP_GMA_LOG("secret character number overflow !!! \n");
                return false;
            }

            *secret <<= 4;
            *secret++ += gma_ali_para_char2num(*para_string);
            highbit_en ^= 1;
        }

        para_string++;
    }

    ///check secret character numbers legal scope
    if (char_nums != GMA_ALI_PARA_SECRET_CHAR_NUMS) {
        APP_GMA_LOG("secret character number error !!! :%d \n", char_nums);
        return false;
    }

    ///print secret
    APP_GMA_LOG(">>ali_para secret: ");
    for (int i = 0; i < sizeof(ali_para->secret) / sizeof(ali_para->secret[0]); i++) {
        APP_GMA_LOG("%x ", ali_para->secret[i]);
    }

    memset(ali_para->mac, 0x00, sizeof(ali_para->mac));
    para_string++;
    highbit_en = 0;
    char_nums = 0;
    while (*para_string != GMA_ALI_PARA_END_CHAR) {
        //if legal character
        if (!LEGAL_MAC_NUM(*para_string)) {
            APP_GMA_LOG("mac illegal character !!! \n");
            para_string++;
            continue;
//            return false;
        }

        if (*para_string == USELESS_CHAR) {
            para_string++;
            continue;
        }

        ///assignment mac
        if (!highbit_en) {
            *mac += gma_ali_para_char2num(*para_string);
            highbit_en ^= 1;
        } else {
            //check mac character numbers legal scope
            char_nums++;
            if (char_nums > GMA_ALI_PARA_MAC_CHAR_NUMS) {
                APP_GMA_LOG("mac character numbers overflow !!! \n");
                return false;
            }

            *mac <<= 4;
            *mac++ += gma_ali_para_char2num(*para_string);
            highbit_en ^= 1;
        }

        para_string++;
    }

    //check mac character numbers legal scope
    if (char_nums != GMA_ALI_PARA_MAC_CHAR_NUMS) {
        APP_GMA_LOG("mac character numbers error !!! \n");
        return false;
    }

    ///mac reverse
    for (int i = 0, tmp_mac = 0, array_size = (sizeof(ali_para->mac) / sizeof(ali_para->mac[0])); \
         i < (sizeof(ali_para->mac) / sizeof(ali_para->mac[0]) / 2); i++) {
        tmp_mac = ali_para->mac[i];
        ali_para->mac[i] = ali_para->mac[array_size - 1 - i];
        ali_para->mac[array_size - 1 - i] = tmp_mac;
    }

    ///print secret
    APP_GMA_LOG(">>ali_para mac: ");
    for (int i = 0; i < sizeof(ali_para->mac) / sizeof(ali_para->mac[0]); i++) {
        APP_GMA_LOG("%x ", ali_para->mac[i]);
    }
    return true;
}

static int gma_license2flash(const ali_para_s *ali_para)
{
    int i;
    u8 mac[6];
    u8 rdata[sizeof(ali_para_s)];

    for (i = 0; i < sizeof(mac); i++) {
        mac[i] = ali_para->mac[5 - i];
    }
    memcpy(rdata, &ali_para->pid, sizeof(ali_para->pid));
    memcpy(rdata + sizeof(ali_para->pid), ali_para->secret, sizeof(ali_para->secret));
    memcpy(rdata + sizeof(ali_para->pid) + sizeof(ali_para->secret), mac, sizeof(mac));

    return app_protocol_license2flash(rdata, sizeof(rdata));
}

#endif


#if TCFG_USER_TWS_ENABLE
#include "bt_tws.h"
static ali_para_s ali_para_remote; //对耳的三元组

//VM_GMA_MAC    对耳的地址
//VM_GMA_ALI_PARA   对耳的三元组

static int gma_strcmp(const u8 *ptr1, const u8 *ptr2, u8 len)
{
    while (len--) {
        if (*ptr1 != *ptr2) {
            return (*ptr1 - *ptr2);
        }

        ptr1++;
        ptr2++;
    }

    return 0;
}

///mac reverse
u8 *gma_sibling_mac_get() //获取地址较小的那个
{
    ali_para_s *sibling_ali_para = NULL;//&ali_para;
    if (active_ali_para == &ali_para) {
        printf("ali_para active \n");
        sibling_ali_para = &ali_para_remote;
    }

    if (active_ali_para == &ali_para_remote) {
        printf("ali_para active \n");
        sibling_ali_para = &ali_para;
    }

    return (sibling_ali_para ? sibling_ali_para->mac : NULL);
}

int gma_select_ali_para_by_common_mac()
{
    u8 ret = 0;
    u8 mac[6];
    u8 mac_buf_tmp[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
    ret = syscfg_read(CFG_TWS_COMMON_ADDR, mac, 6);
    if (ret != 6 || !memcmp(mac, mac_buf_tmp, 6)) {
        printf("tws no conn\n");
        return -1;
    }
    APP_GMA_LOG("active mac:");
    APP_GMA_DUMP(mac, 6);
    ///select para
    ali_para_s ali_para_temp;
    syscfg_read(VM_GMA_ALI_PARA, (u8 *) &ali_para_temp, sizeof(ali_para_s));
    if (ali_para_temp.pid == ali_para.pid) {
        memcpy(&ali_para_remote, &ali_para_temp, sizeof(ali_para_s));
        APP_GMA_LOG("remote mac:");
        APP_GMA_DUMP(ali_para_remote.mac, 6);
        APP_GMA_LOG("remote pid:%d \n", ali_para_remote.pid);
        APP_GMA_LOG("remote secret:");
        APP_GMA_DUMP(ali_para_remote.secret, sizeof(ali_para_remote.secret));
        if (gma_strcmp(mac, ali_para_remote.mac, 6) == 0) {
            APP_GMA_LOG("used remote para \n");
            active_ali_para = &ali_para_remote;
            return 0;
        } else if (gma_strcmp(mac, ali_para.mac, 6) == 0) {
            APP_GMA_LOG("used local para \n");
            active_ali_para = &ali_para;
            return 0;
        } else {
            APP_GMA_LOG("MAC ERROR !!!!!!!!!!!!!!!!\n");
            return -1;
        }
    } else {
        APP_GMA_LOG("no remote mac \n");
    }
    return -1;
}

void gma_slave_sync_remote_addr(u8 *buf)
{
    u8 common_addr[6];
    ///remote ali_para fill
    memcpy(&ali_para_remote, buf, sizeof(ali_para_remote));
    syscfg_write(VM_GMA_MAC, ali_para_remote.mac, 6);

    ///write ali para to vm
    syscfg_write(VM_GMA_ALI_PARA, (u8 *)&ali_para_remote, sizeof(ali_para_remote));

    tws_api_get_local_addr(common_addr);
    if (memcmp(active_ali_para->mac, common_addr, 6)) { //common地址发生变化
        APP_GMA_LOG("gma addr change");
        ///used slave address
        active_ali_para = &ali_para_remote;
        app_protocol_set_tws_sibling_mac(ali_para.mac);
        app_protocol_set_info_group(GMA_HANDLER_ID, active_ali_para); //设置三元组
        //断开APP接口
        if (is_tws_master_role()) {
            APP_GMA_LOG("gma need reconn app");
            app_protocol_disconnect(NULL);
            app_protocol_ble_adv_switch(0);
            le_controller_set_mac(active_ali_para->mac);
            app_protocol_ble_adv_switch(1);
        }
    }
}

#ifdef CONFIG_NEW_BREDR_ENABLE
void tws_host_get_common_addr(u8 *remote_addr, u8 *common_addr, char channel)
#else
void tws_host_get_common_addr(u8 *local_addr, u8 *remote_addr, u8 *common_addr, char channel)
#endif
{
    APP_GMA_LOG(">>>>>>>>>tws_host_get_common_addr ch:%c \n", channel);

    u8 mac_buf[6];
    gma_mac_addr_reverse_get(mac_buf);
    APP_GMA_LOG(">>>local mac: ");
    APP_GMA_DUMP(mac_buf, 6);
    ///used the bigger one as host bt mac
    if (gma_strcmp(mac_buf, (const u8 *)remote_addr, 6) < 0) {
        ///used slave mac addr;remote_addr from slave addr reverse
        memcpy(common_addr, remote_addr, 6);
    } else {
        ///used master mac addr
        gma_mac_addr_reverse_get(common_addr);
    }
    APP_GMA_LOG("common_addr: ");
    APP_GMA_DUMP((const u8 *)common_addr, 6);
    APP_GMA_LOG("remote_addr: ");
    APP_GMA_DUMP((const u8 *)remote_addr, 6);
}

void gma_kick_license_to_sibling(void)
{
    APP_GMA_LOG("send license info to sibling\n");
    app_protocol_tws_send_to_sibling(GMA_TWS_CMD_SYNC_LIC, (u8 *) & (ali_para), sizeof(ali_para));;
}

void gma_tws_remove_paired(void)
{
    ali_para_s ali_para_temp;
    memset(&ali_para_temp, 0xff, sizeof(ali_para_s));
    syscfg_write(VM_GMA_ALI_PARA, (u8 *)&ali_para_temp, sizeof(ali_para_s));

    active_ali_para = &ali_para;
    app_protocol_set_tws_sibling_mac(ali_para_temp.mac);
    app_protocol_set_info_group(GMA_HANDLER_ID, active_ali_para); //设置三元组

    app_protocol_disconnect(NULL);
    app_protocol_ble_adv_switch(0);
    le_controller_set_mac(active_ali_para->mac);
    app_protocol_ble_adv_switch(1);
}

#endif

__attribute__((weak))
void bt_update_testbox_addr(u8 *addr)
{

}
int gma_prev_init(void)
{
    int err = 0;
    /* ali_para_s ali_para; */
#if GMA_GMA_SOURCH == GMA_GMA_FROM_FLASH
    err = gma_license_set(&ali_para);
#elif GMA_GMA_SOURCH == GMA_GMA_FROM_FILE
    u8 *ali_str = ali_para_string[ALI_PARA_ACTIVE_NUM];
    u8 ali_license[128] = {0};

    //check if exist flash file
    if (read_cfg_file(ali_license, sizeof(ali_license), SDFILE_RES_ROOT_PATH"license.txt") == TRUE) {
        ali_str = ali_license;
    }
    APP_GMA_LOG("ali_str:%s\n", ali_str);
    if (gma_ali_para_info_fill((const u8 *)ali_str, &ali_para) == false) {
        APP_GMA_LOG("array context not good \n");
///read license from flash
        err = gma_license_set(&ali_para);
    }
///write license to flash
    if (!err) {
        /* gma_license2flash(&ali_para); */
    }
#endif
    if (!err) {
        active_ali_para = &ali_para;
#if TCFG_USER_TWS_ENABLE
        if (!gma_select_ali_para_by_common_mac()) {
            app_protocol_set_tws_sibling_mac(gma_sibling_mac_get());
        }
#endif
        app_protocol_set_info_group(GMA_HANDLER_ID, active_ali_para); //设置三元组
        bt_update_mac_addr(active_ali_para->mac);
        lmp_hci_write_local_address(active_ali_para->mac);
        app_protocol_ble_adv_switch(0);
        le_controller_set_mac(active_ali_para->mac); //修改BLE地址
        bt_update_testbox_addr(ali_para.mac);
    }
    return err;
}


//*********************************************************************************//
//                                 GMA 提示音                                     //
//*********************************************************************************//
const char *gma_tone_tab[APP_RROTOCOL_TONE_MAX] = {
    [APP_RROTOCOL_TONE_SPEECH_KEY_START]	    	= TONE_NORMAL,
};

//*********************************************************************************//
//                                 DMA私有消息处理                                 //
//*********************************************************************************//
#if TCFG_USER_TWS_ENABLE
void gma_rx_tws_data_deal(u16 opcode, u8 *data, u16 len)
{
    switch (opcode) {
    case GMA_TWS_CMD_SYNC_LIC:
        printf(">>> TWS_AI_GMA_START_SYNC_LIC \n");
        gma_slave_sync_remote_addr(data);
        break;
    }
}

static void gma_bt_tws_event_handler(struct bt_event *bt)
{
    int role = bt->args[0];
    int phone_link_connection = bt->args[1];
    int reason = bt->args[2];

    switch (bt->event) {
    case TWS_EVENT_CONNECTED:
        gma_kick_license_to_sibling();
        break;
    case TWS_EVENT_REMOVE_PAIRS:
        gma_tws_remove_paired();
        break;
    }
}
#endif

static int gma_bt_status_event_handler(struct bt_event *bt)
{
    return 0;
}

int gma_sys_event_deal(struct sys_event *event)
{
    switch (event->type) {
    case SYS_BT_EVENT:
        if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
            gma_bt_status_event_handler(&event->u.bt);
        }
#if TCFG_USER_TWS_ENABLE
        else if (((u32)event->arg == SYS_BT_EVENT_FROM_TWS)) {
            gma_bt_tws_event_handler(&event->u.bt);
        }
#endif
        break;

    }

    return 0;

}

struct app_protocol_private_handle_t gma_private_handle = {
#if TCFG_USER_TWS_ENABLE
    .tws_rx_from_siblling = gma_rx_tws_data_deal,
#endif
    /* .tws_sync_func = ; */
    .sys_event_handler = gma_sys_event_deal,
};
#endif

