#include "common.h"
#include "dy_utils/dy_mqtt.h"
#include "dy_utils/dy_common.h"
#include "libubox/utils.h"

#define SUB_TOPIC "ipc/+/BLE/device/+/data/Set_Rglt_Raw"

static ble_slave_dev_t *find_slave_dev_by_sn(ble_var_t *var, char *sn)
{
    ble_slave_cfg_t *slave_cfg = NULL;
    int i;
    GList *list;

    for (list = g_list_first(var->ctrl_list); list; list = g_list_next(list))
    {
        struct adapter *adapter;

        adapter = list->data;
        if (adapter == NULL)
        {
            continue;
        }

        slave_cfg = &adapter->slave_cfg;
        for (i = 0; i < slave_cfg->dev_cnt; i++)
        {
            ble_slave_dev_t *slave = &slave_cfg->slave[i];
            if (strcmp(slave->SN, sn) == 0)
            {
                return slave;
            }
        }
    }

    return NULL;
}

static int ble_send_data_to_sn(ble_var_t *var, char *sn, char *uuid, char *data_str, char *opcode)
{
    unsigned char buf[1024];
    int len;
    ble_slave_dev_t *dev = NULL;
    GDBusProxy *proxy;

    dev = find_slave_dev_by_sn(var, sn);
    if (dev == NULL)
    {
        dy_syslog(LOG_DEBUG, "cannot find the device by sn");
        return -1;
    }

    proxy = gatt_select_attribute(dev->proxy, uuid);

    if (!proxy)
    {
        dy_syslog(LOG_DEBUG, "cannot find the attribute for uuid:%s", uuid);
        return -1;
    }

    if (strcmp(opcode, "read") == 0)
    {
        dy_syslog(LOG_DEBUG, "read:");
        gatt_read_attribute(proxy, 1, NULL);
    }
    else if (strcmp(opcode, "write") == 0)
    {
        dy_syslog(LOG_DEBUG, "write:");
        len = b64_decode(data_str, buf, 1024);
        write_attribute_bin(proxy, buf, len);
    }

    dy_syslog(LOG_DEBUG, "sending data\n");
    return 0;
}

static int ble_handle_mqtt_recv_msg(void *obj, mqtt_message_t *mqtt_msg)
{
    dy_syslog(LOG_DEBUG, " MQTT client: received MQTT topic:%s payload:%s",
              mqtt_msg->topic, mqtt_msg->payload);

    ble_var_t *var = (ble_var_t *)obj;
    char *data_str = NULL;
    char *sn = NULL;
    char *uuid = NULL;
    char *raw_data = NULL;
    char *opcode = NULL;
    cJSON *root = cJSON_Parse(mqtt_msg->payload);
    if (!root)
    {
        return -1;
    }
    GET_JSON_VALUE_DY_STRING(root, "data_b64", data_str);
    GET_JSON_VALUE_DY_STRING(root, "sn", sn);
    cJSON_Delete(root);

    cJSON *data = cJSON_Parse(data_str);
    GET_JSON_VALUE_DY_STRING(data, "uuid", uuid);
    GET_JSON_VALUE_DY_STRING(data, "data", raw_data);
    GET_JSON_VALUE_DY_STRING(data, "opcode", opcode);

    ble_send_data_to_sn(var, sn, uuid, raw_data, opcode ? opcode : "read");

    free(sn);
    free(uuid);
    free(raw_data);
    free(data_str);
    free(opcode);
    cJSON_Delete(data);
    return 0;
}

void ble_send_raw_data_to_pp(ble_var_t *var, int dev_id, ble_slave_dev_t *slave, char *uuid, char *ops, uint8_t *value, int value_len)
{

    if (slave != NULL)
    {
        long long ms = get_time_stamp_ms();

        if (ms - slave->last_ms < 100)
        {
            //return;
        }
        slave->last_ms = ms;

        cJSON *rt_data = cJSON_CreateObject();
        char buf[512] = {0};
        char topic[TOPIC_MAX_LEN] = {0};
        time_t ts = time(NULL);
        cJSON_AddStringToObject(rt_data, "port", "BLE");
        cJSON_AddStringToObject(rt_data, "sn", slave->SN);
        cJSON_AddNumberToObject(rt_data, "ts", ts);

        cJSON *data = cJSON_CreateObject();
        cJSON_AddStringToObject(data, "sn", slave->SN);
        cJSON_AddStringToObject(data, "uuid", uuid);
        if (value != NULL && value_len > 0)
        {
            b64_encode(value, value_len, buf, 512);
            cJSON_AddStringToObject(data, "data", buf);
        }
        cJSON_AddStringToObject(data, "opcode", ops);
        char *tmp = cJSON_Print(data);
        b64_encode(tmp, strlen(tmp), buf, 512);
        cJSON_AddNumberToObject(rt_data, "len", strlen(tmp));
        cJSON_AddStringToObject(rt_data, "data_b64", buf);
        char *data_tmp = cJSON_Print(rt_data);

        snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/%s/device/%s/data/%s", var->sn_str, "BLE",
                 slave->SN, "raw_data");

        dy_mqtt_session_publish(var->session, topic, data_tmp, strlen(data_tmp));
        free(data_tmp);
        free(tmp);
        cJSON_Delete(data);
        cJSON_Delete(rt_data);
    }
    else
    {
        static long long last_ms = 0;

        long long ms = get_time_stamp_ms();

        dy_syslog(LOG_DEBUG, "send out the raw data to pp, no slave\n");
        if (ms - last_ms < 100)
        {
            //return;
        }
        last_ms = ms;

        cJSON *rt_data = cJSON_CreateObject();
        char buf[512] = {0};
        char topic[TOPIC_MAX_LEN] = {0};
        time_t ts = time(NULL);
        cJSON_AddStringToObject(rt_data, "port", "BLE");
        cJSON_AddStringToObject(rt_data, "sn", var->sn_str);
        cJSON_AddNumberToObject(rt_data, "ts", ts);
        cJSON *data = cJSON_CreateObject();
        cJSON_AddNumberToObject(data, "dev_id", dev_id);
        cJSON_AddStringToObject(data, "uuid", uuid);
        if (value != NULL && value_len > 0)
        {
            b64_encode(value, value_len, buf, 512);
            cJSON_AddStringToObject(data, "data", buf);
        }
        cJSON_AddStringToObject(data, "opcode", ops);
        char *tmp = cJSON_Print(data);
        b64_encode(tmp, strlen(tmp), buf, 512);
        cJSON_AddNumberToObject(rt_data, "len", strlen(tmp));
        cJSON_AddStringToObject(rt_data, "data_b64", buf);
        char *data_tmp = cJSON_Print(rt_data);

        snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/%s/device/%s/data/%s", var->sn_str, "BLE",
                 var->sn_str, "raw_data");

        dy_mqtt_session_publish(var->session, topic, data_tmp, strlen(data_tmp));
        free(data_tmp);
        free(tmp);
        cJSON_Delete(data);
        cJSON_Delete(rt_data);
    }
}

bool ble_mqtt_init(ble_var_t *var)
{
    char clientId[MAX_CLIENT_ID_LEN] = {0};

    get_board_sn(var->sn_str);
    snprintf(clientId, MAX_CLIENT_ID_LEN, "ble_%s", var->sn_str);
    var->session = dy_mqtt_session_new(clientId);
    if (var->session == NULL)
        return false;

    dy_mqtt_session_set_address(var->session, INTERNAL_BROKER_ADDR, INTERNAL_BROKER_PORT, INTERNAL_BROKER_USER, INTERNAL_BROKER_PASS);
    dy_mqtt_session_set_opts(var->session, DEFAULT_IPC_QOS, KEEP_ALIVE_MAX);
    dy_mqtt_session_set_callbacks(var->session, ble_handle_mqtt_recv_msg, NULL);

    dy_mqtt_session_init(var->session, (void *)var);
    dy_mqtt_session_subscribe(var->session, SUB_TOPIC);

    return true;
}