#include "bmser.h"
#include "common.h"
#ifdef EN_BMSER_DB_CTROL_LIB
#include "bmser_ems_db_control_db.h"
#endif
// 设备配置项:{"no":"bms","name":"PCS","channel":"192.168.12.115:1883","protocol":"bmser_bin","user_def":"","addr":"","template":"template_pcs.json"}
bmser_data_t bmser_protocol_to_type(char *t)
{
    char *type[BMSER_DATA_MAX] = {"U16", "S16", "U32", "S32", "FLOAT", "BIT16"};
    for (bmser_data_t i = BMSER_DATA_U16; i < BMSER_DATA_MAX; i++)
    {
        if (strcmp(t, type[i]) == 0)
        {
            return i;
        }
    }
    return BMSER_DATA_MAX;
}

static int bms_extract_pack(void *buff, uint32_t len, bmser_bin_pack *p)
{
    const uint8_t *p_tmp = (const uint8_t *)buff;
    // p->trans_id = *((uint32_t*)p_tmp);
    p->trans_id = (*p_tmp << 24) | (*(p_tmp + 1) << 16) | (*(p_tmp + 2) << 8) | *(p_tmp + 3);

    p->dev_len = *(p_tmp + 4);
    if (p->dev_len > 0)
    {
        // p->dev
        // 没有操作
    }

    p->cmd_len = *(p_tmp + 5 + p->dev_len);
    if (p->cmd_len > 0)
    {
        // p->cmd
        // 没有操作
    }

    // p->payload_len = *(uint16_t*)(p_tmp + 6 + p->dev_len + p->cmd_len);
    const uint8_t *pt = p_tmp + 6 + p->dev_len + p->cmd_len;
    p->payload_len = (*pt << 8) | *(pt + 1);
    // 校验
    if ((p->payload_len + 8 + p->dev_len + p->cmd_len) != len)
    {
        return -1;
    }

    p->payload = (bmser_payload *)(pt + 2);
    // printf("0x%0x, 0x%x, 0x%x, 0x%x\n", p->trans_id, p->dev_len, p->cmd_len, p->payload_len);

    return 0;
}

block_data *new_block_data(uint32_t block_id, uint16_t start_sub_id, void *content, uint16_t sub_num, uint16_t bytes)
{
    block_data *new_block = (block_data *)calloc(1, sizeof(block_data) + bytes);
    if (new_block != NULL)
    {
        new_block->block_id = TOGGLE_ENDIAN_32(block_id);
        new_block->start_sub_id = TOGGLE_ENDIAN_16(start_sub_id);
        new_block->sub_num = TOGGLE_ENDIAN_16(sub_num);
        new_block->bytes = TOGGLE_ENDIAN_16(bytes);
        memcpy(new_block->content, content, bytes);
    }

    return new_block;
}

int new_bmser_proto_pack(bmser_bin_pack *pack_info, block_data *block_arr[], uint8_t block_num, void *ret_pack)
{
    int need_byte = pack_info->cmd_len + pack_info->dev_len + 8;
    int payload_len = sizeof(bmser_payload);
    for (int i = 0; i < block_num; i++)
    {
        payload_len += TOGGLE_ENDIAN_16(block_arr[i]->bytes) + sizeof(block_data);
    }
    need_byte += payload_len;
    uint8_t *pack = (uint8_t *)calloc(1, need_byte);
    if (pack == NULL)
    {
        return 0;
    }

    *((uint8_t **)ret_pack) = pack;
    *((uint32_t *)pack) = TOGGLE_ENDIAN_32(pack_info->trans_id);

    *(pack + 4) = pack_info->dev_len;
    if (pack_info->dev_len != 0)
    {
        //
    }
    *(pack + 5 + pack_info->dev_len) = pack_info->cmd_len;
    if (pack_info->dev_len != 0)
    {
        //
    }
    *((uint16_t *)(pack + 6 + pack_info->dev_len + pack_info->cmd_len)) = TOGGLE_ENDIAN_16((uint16_t)payload_len);
    bmser_payload *payload = (bmser_payload *)(pack + 8 + pack_info->dev_len + pack_info->cmd_len);
    payload->block_num = block_num;
    block_data *cur_block = payload->block;
    for (int i = 0; i < block_num; i++)
    {
        memcpy(cur_block, block_arr[i], TOGGLE_ENDIAN_16(block_arr[i]->bytes) + sizeof(block_data));
        cur_block = BMSER_BLOCK_NEXT(cur_block);
    }

    return need_byte;
}

static int bmser_protocol_mqtt_recv_handle(void *obj, ipc_msg_t *mqtt_msg)
{
    bmser_protocol *bmser = (bmser_protocol *)obj;
    proto_syslog(LOG_DEBUG, "[%s:%d]received MQTT topic:%s payload length:%d", bmser->ip, bmser->port, mqtt_msg->topic, mqtt_msg->payloadLen);
    proto_syslog_hex(LOG_DEBUG, mqtt_msg->payload, mqtt_msg->payloadLen, "[%s:%d] rx:%d", bmser->ip, bmser->port, mqtt_msg->payloadLen);
    bmser_bin_pack payload = {0};
    bms_extract_pack(mqtt_msg->payload, mqtt_msg->payloadLen, &payload);
    proto_syslog(LOG_INFO, "blockNum:0x%02x\n", payload.payload->block_num);

    if (bmser->data_report != NULL)
    {
        for (int i = 0; i < payload.payload->block_num; i++)
        {
            bmser->cb_par.proto_data = &payload.payload->block[i];
            bmser->data_report(&bmser->cb_par);
            //
        }
    }
    return 0;
}

static const char *bmser_protocol_get_gw_sn(void)
{
    static int sn_max_len = 64;
    static char *sn = NULL;
    if (sn != NULL)
    {
        return sn;
    }
    else
    {
        char *tmp = NULL;
        char *tag_str = "sn = ";
        char line_buff[512] = {0};
        sn = (char *)calloc(1, sn_max_len);
        FILE *fp = fopen("/app/config/fac.ini", "r");
        if (fp != NULL)
        {
            while (fgets(line_buff, sizeof(line_buff), fp) != NULL)
            {
                tmp = strstr(line_buff, tag_str);
                if (tmp != NULL)
                {
                    tmp = tmp + strlen(tag_str);
                    int len = strlen(tmp);
                    if (len > sn_max_len - 1)
                    {
                        len = sn_max_len - 1;
                    }
                    for (int i = 0; i < len; i++)
                    {
                        if (((tmp[i] >= '0') && (tmp[i] <= '9')) || ((tmp[i] >= 'a') && (tmp[i] <= 'z')) || ((tmp[i] >= 'A') && (tmp[i] <= 'Z')))
                        {
                            sn[i] = tmp[i];
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
            pclose(fp);
        }

        if (strlen(sn) < 1)
        {
            snprintf(sn, sn_max_len, "21012C00FFFF");
        }
    }

    return sn;
}

int bmser_protocol_send_pack(bmser_protocol *this_p, char *dev_no, void *pack, int len)
{
    char top[128] = {0};
    snprintf(top, sizeof(top), "ipc/%s/bms/%s/bcudata/Set/binaryFlow", bmser_protocol_get_gw_sn(), dev_no);
    return mqtt_session_publish(this_p->mqtt, top, pack, len);
}

bmser_protocol *new_bmser_protocol(char *ip, uint16_t port, int (*data_report)(const bmser_cb_par *p), void *top)
{
    char client_id[48] = {0};
    snprintf(client_id, sizeof(client_id), "%s_client_id_%lld", bmser_protocol_get_gw_sn(), clock_get_ms());
    proto_syslog(LOG_NOTICE, "bmser client_id:%s", client_id);

    bmser_protocol *bmser = calloc(1, sizeof(bmser_protocol));
    mqtt_session_t *session = mqtt_session_new(client_id, bmser);
    if (session == NULL)
    {
        free(bmser);
        return NULL;
    }

    bmser->mqtt = session;
    snprintf(bmser->ip, sizeof(bmser->ip), "%s", ip);
    bmser->port = port;
    bmser->data_report = data_report;
    bmser->cb_par.top = top;

    mqtt_session_set_address(bmser->mqtt, bmser->ip, bmser->port, "", "");
    mqtt_session_set_opts(bmser->mqtt, BMSER_DEFAULT_IPC_QOS, BMSER_KEEP_ALIVE_MAX);
    mqtt_session_set_callbacks(bmser->mqtt, bmser_protocol_mqtt_recv_handle, NULL);
    return bmser;
}

int delete_bmser_protocol(bmser_protocol *bmser)
{
    mqtt_session_disconn(bmser->mqtt);
    mqtt_session_destroy_and_free(bmser->mqtt);
    free(bmser);
    return 0;
}

int bmser_protocol_add_dev(bmser_protocol *bmser, char *dev_no)
{
    char top[96] = {0};
    snprintf(top, sizeof(top), "ipc/%s/bms/%s/bcudata/GetResp/binaryFlow", bmser_protocol_get_gw_sn(), dev_no);
    proto_syslog(LOG_NOTICE, "sub top: %s", top);
    mqtt_session_subscribe(bmser->mqtt, top);

    snprintf(top, sizeof(top), "ipc/%s/bms/%s/bcudata/SetResp/binaryFlow", bmser_protocol_get_gw_sn(), dev_no);
    proto_syslog(LOG_NOTICE, "sub top: %s", top);
    return mqtt_session_subscribe(bmser->mqtt, top);
}

int bmser_protocol_start(bmser_protocol *bmser)
{
    if (bmser == NULL)
    {
        return -1000;
    }
    // mqtt_session_subscribe(bmser->mqtt, "ipc/gw_/bms/bau123/baudata/GetResp/binaryFlow");
    // mqtt_session_subscribe(bmser->mqtt, "ipc/xx/ems/pcs456/pcsdata/Set/binaryFlow");
    return mqtt_session_start(bmser->mqtt);
}

#ifdef EN_BMSER_DB_CTROL_LIB
#define OPRT_ALREADY_INITED (-10010)
// 直接读共享内存
int bmser_init(void)
{
    int ret = -1;
    BMSER_EMS_DB_CONTROL_INIT_S db_init = {.mode = SLAVE_MODE, .msgcb = NULL};
    ret = BmserProtocolExt_DBInit(&db_init);
    if (ret == OPRT_ALREADY_INITED)
    {
        ret = 0;
    }

    return ret;
}

int bmser_read(void *buff, void *valid_flag, uint16_t max, uint32_t bank_rack, uint16_t start_sub_id, uint16_t reg_count)
{
    int ret = 0;
    EMS_DEV_REG_DATA_S read_par = {.dataType = BMS_DATA};
    read_par.bankId = (bank_rack >> 16) & 0xffff;
    read_par.rackId = bank_rack & 0xffff;
    read_par.startAddr = start_sub_id;
    read_par.regCount = reg_count;
    read_par.len = reg_count * 2;
    read_par.dbValid = (uint8_t *)valid_flag;

    ret = BmserProtocolExt_ReadRegisterDb(&read_par, (uint8_t *)buff, max);
    if (ret == -10011) // 数据检查错误
    {
        ret = 0;
    }

    return ret;
}

int bmser_write(void *buff, uint32_t bank_rack, uint16_t start_sub_id, uint16_t reg_count)
{
    EMS_DEV_REG_DATA_S write_par = {.dataType = BMS_DATA};
    write_par.bankId = (bank_rack >> 16) & 0xffff;
    write_par.rackId = bank_rack & 0xffff;
    write_par.startAddr = start_sub_id;
    write_par.regCount = reg_count;
    write_par.len = reg_count * 2;
    write_par.data = (uint8_t *)buff;

    return BmserProtocolExt_WriteRegisterDb_No_Waiting_Result(&write_par);
}
#endif
