#include "mqtt_it.h"
#include "../common.h"
#include "../ems/jsonct.h"
#include <time.h>
#include "../ems/income.h"
/*
xiaochenglong@userroot:~/tttttt/proto_forward$ mosquitto_sub -v -h mqtt.lnxall.com -p 3883 -u localuser -P dywl@galaxy -t "/emms/test123456789/#"
/emms/test123456789/set {"i":"getProfitBms","m":68501680,"p":{"beginDate":"2022-10-20T09:21:51.480","endDate":"2023-10-20T09:21:51.480"},"s":"test123456789","t":1697764911}
/emms/test123456789/set {"i":"getDeviceInfo","m":38029311,"s":"test123456789","t":1697764911}
/emms/test123456789/set {"i":"getCellStruct","m":30880806,"s":"test123456789","t":1697764911}
*/
#if 0
extern income_host ems_income_host;
static int get_runing_days(void)
{
    static char start_time[128] = {0};
    struct tm tm_target = {0};

    read_cabinet_info_by_name("time", start_time);
    int sum = sscanf(start_time, "%d-%d-%d", &tm_target.tm_year, &tm_target.tm_mon, &tm_target.tm_mday);

    time_t now = time(NULL);
    if (sum == 3)
    {
        tm_target.tm_year -= 1900;
        tm_target.tm_mon -= 1;
        time_t target = mktime(&tm_target);
        return (int)(difftime(now, target) / (24 * 3600));
    }

    return -1;
}

int usage_message_creat(const cloud_mqtt_its *its, void *payload, int max_len)
{
    // d:效率单位(%),运行天数,运行设备数,节约电费数,总充电量(kwh),总放电量(kwh)
    // 88.19,215,2,140387.99,177683.50,156691.00
    int income = dev_get_dev_tag_int(DEV_NO_EMS, INCOME);
    double charg = dev_get_dev_tag_float(DEV_NO_PCS_MT, "ActiveEnergy");
    double discharg = dev_get_dev_tag_int(DEV_NO_PCS_MT, "ReactiveEnergy");
    int effi = (discharg / charg) * 10000; // dev_get_dev_tag_int(DEV_NO_EMS, EFFICIENCY);
    return snprintf(payload, max_len, "{\"c\":%ld,\"d\":\"%g,%d,%d,%g,%g,%g\",\"s\":\"%s\"}",
                    time(NULL), effi / 100.0, get_runing_days(), 1, income / 100.0, charg, discharg, its->station_id);
}

int basedata_message_creat(const cloud_mqtt_its *its, void *payload, int max_len)
{
    // d:设备编码,工作状态,通讯状态
    // 工作状态( -1静置 0放电  1充电)
    // 通讯状态(1在线，0离线 -1未知）
    int work_sta = -1;
    double power = get_meter_active_power(DEV_NO_PCS_MT);
    if (power < -0.2)
    {
        work_sta = 1;
    }
    else if (power > 0.2)
    {
        work_sta = 0;
    }

    return snprintf(payload, max_len, "{\"c\":%ld,\"d\":\"%s,%d,%d\",\"s\":\"%s\"}",
                    time(NULL), "bms_no", work_sta, 1, its->station_id);
}

int info_message_creat(const cloud_mqtt_its *its, void *payload, int max_len)
{
    const cabinet_info_t *cab = get_cabinet_info();
    // d:站点编号,站点名称,租户编码,站点用户编码,站点web地址,站控软件版本号
    return snprintf(payload, max_len, "{\"c\":%ld,\"d\":\"%s,%s,%s,,http://,V2.0\",\"s\":\"%s\"}",
                    time(NULL), its->station_id, cab->cab_station_name, cab->tenant_id, its->station_id);
}

int runInfo_message_creat(const cloud_mqtt_its *its, void *payload, int max_len)
{
    // d:时间戳,功率,soc
    time_t t = time(NULL);
    double soc = dev_get_dev_tag_float(DEV_NO_BMS, CURRENT_SOC);
    return snprintf(payload, max_len, "{\"c\":%ld,\"d\":\"%ld,999,%.02f\",\"s\":\"%s\"}",
                    t, t, soc, its->station_id);
}

int income_to_cloud_string(const income_host *income, void *buff, int max_len, time_t t)
{
    struct tm *local = localtime(&t);
    const ele_price *pri = &income->price[local->tm_mon].price;
    return snprintf(buff, max_len, "%d-%02d-%02d,"
                                   "%.2f,%.2f,%.2f,%.2f,"
                                   "%.2f,%.2f,%.2f,%.2f,"
                                   "%.2f,%.2f,%.2f,%.2f,"
                                   "%g,%g,%g,%g,"
                                   "%g,%g,%g,%g,0",
                    local->tm_year + 1900, local->tm_mon + 1, local->tm_mday,
                    income->today_energy.active_diff.total, income->today_energy.reactive_diff.total, income->chgFee, income->dischgFee,
                    income->today_energy.active_diff.top, income->today_energy.active_diff.peak, income->today_energy.active_diff.flat, income->today_energy.active_diff.valley,
                    income->today_energy.reactive_diff.top, income->today_energy.reactive_diff.peak, income->today_energy.reactive_diff.flat, income->today_energy.reactive_diff.valley,
                    pri->top, pri->peak, pri->flat, pri->valley, pri->top, pri->peak, pri->flat, pri->valley);
}

int cloud_lnxall_write_history(time_t t)
{
    int re = 0;
    char tmp_buff[512] = {0};
    struct tm target_time = {0};
    const char *cfg_f = "/app/config/history.json";
    char *f_data = read_file_data(cfg_f);
    if (f_data == NULL)
    {
        ems_syslog(LOG_ERR, "load sys config file error, file:%s\n", cfg_f);
        f_data = strdup("[]");
    }

    cJSON *root = json_parse_string_with_comments(f_data);
    if (!root)
    {
        ems_syslog(LOG_ERR, "parse file to json obj error, file:%s\n", cfg_f);
        re = -2;
        goto cloud_lnxall_write_history_exit;
    }

    if (!cJSON_IsArray(root))
    {
        cJSON_Delete(root);
        root = cJSON_CreateArray();
    }

    cJSON *new_obj = cJSON_CreateObject();

    struct tm *local = &target_time;
    localtime_r(&t, local);
    income_to_cloud_string(&ems_income_host, tmp_buff, sizeof(tmp_buff), t);
    cJSON_AddNumberToObject(new_obj, "time", ((local->tm_year + 1900) * 10000) + ((local->tm_mon + 1) * 100) + local->tm_mday);
    cJSON_AddStringToObject(new_obj, "data", tmp_buff);

    cJSON_AddItemToArray(root, new_obj);
    int arrLen = cJSON_GetArraySize(root);
    for (int i = 0; i < arrLen - 10; i++) // 留最后10个
    {
        cJSON_DeleteItemFromArray(root, 0);
    }
    arrLen = cJSON_GetArraySize(root);

    char *json = cJSON_Print(root);
    write_file_data(cfg_f, json, strlen(json));
    cJSON_free(json);
    cJSON_Delete(root);
cloud_lnxall_write_history_exit:
    free(f_data);
    return re;
}

cJSON *cloud_lnxall_get_history(int start_date, int end_date)
{
    cJSON *re = NULL;
    ems_syslog(LOG_ERR, "cloud lnxall get history:start date:%d, end date:%d\n", start_date, end_date);
    const char *cfg_f = "/app/config/history.json";
    char *f_data = read_file_data(cfg_f);
    if (f_data == NULL)
    {
        ems_syslog(LOG_ERR, "load sys config file error, file:%s\n", cfg_f);
        return NULL;
    }

    cJSON *root = json_parse_string_with_comments(f_data);
    if (!root)
    {
        ems_syslog(LOG_ERR, "parse file to json obj error, file:%s\n", cfg_f);
        re = NULL;
        goto cloud_lnxall_write_history_exit;
    }

    int arrLen = cJSON_GetArraySize(root);
    cJSON *obj = NULL;
    cJSON *tmp_obj = NULL;
    cJSON *arr = cJSON_CreateArray();
    for (int i = 0; i < arrLen; i++)
    {
        obj = cJSON_GetArrayItem(root, i);
        tmp_obj = cJSON_GetObjectItemCaseSensitive(obj, "time");
        if ((tmp_obj->valueint >= start_date) && (tmp_obj->valueint <= end_date))
        {
            tmp_obj = cJSON_GetObjectItemCaseSensitive(obj, "data");
            cJSON_AddItemToArray(arr, cJSON_CreateString(tmp_obj->valuestring));
        }
    }
    cJSON_Delete(root);
    re = arr;
cloud_lnxall_write_history_exit:
    free(f_data);
    return re;
}

int profit_bms_message_creat(const cloud_mqtt_its *its, void *payload, int max_len)
{
    /* d:[统计日期statisDate,
        总充电量cnChargeByGrid,总放电量cnUncharge ,
        充电费用cnFee ,放电费用cnTotalUnchargeFee ,
        尖充cnJdCharge,峰充cnFdCharge ,平充cnPdCharge ,谷充cnGdCharge,
        尖放cnJdUncharge,峰放cnFdUncharge ,平放cnPdUncharge ,谷放cnGdUncharge ,
        尖充费cnJdChargeFee ,峰充费cnFdChargeFee ,平充费cnPdChargeFee ,谷充费cnGdChargeFee ,
        尖放费cnJdUnchargeFee ,峰放费cnFdUnchargeFee ,平放费cnPdUnchargeFee ,谷放费cnGdUnchargeFee ,
        是否删除isDeleted]*/
    time_t t = time(NULL);
    char data_buff[256] = {0};
    income_to_cloud_string(&ems_income_host, data_buff, sizeof(data_buff), t);
    return snprintf(payload, max_len, "{\"c\":%ld,\"d\":[\"%s\"],\"s\":\"%s\"}",
                    t, data_buff, its->station_id);
}

int pcs_basedata_message_creat(const cloud_mqtt_its *its, void *payload, int max_len)
{
    // TODO:现在是直接写死的，最后最好调用pcs的adapter的接口来读取pcs状态，方便适配多个型号的PCS
    /* d:设备编码,并网状态,通信状态,工作状态,告警状态
        注意：
        并网状态: 0-离网 1-并网 -1未知
        通信状态: 1-在线，0-离线
        工作状态: -1静置 0放电  1充电
        告警状态: 1-告警 0-正常*/
    int work_sta = -1;
    double power = get_meter_active_power(DEV_NO_PCS_MT);
    if (power < -0.2)
    {
        work_sta = 1;
    }
    else if (power > 0.2)
    {
        work_sta = 0;
    }
    return snprintf(payload, max_len, "{\"c\":%ld,\"d\":\"-1,1,%d,0\",\"s\":\"%s\"}",
                    time(NULL), work_sta, its->station_id);
}

int dev_info_message_creat(const cloud_mqtt_its *its, void *payload, int max_len)
{
    /* d:*/
    return snprintf(payload, max_len, "{\"c\":%ld,\"d\":[\"bms_no,储能柜1,BMS,,0\"],\"s\":\"%s\"}",
                    time(NULL), its->station_id);
}


static const cloud_mqtt_tx_it tx_it[] = {
    {.topic = "/emms/%s/usage", .create_message = usage_message_creat},
    {.topic = "/emms/%s/bms/baseData", .create_message = basedata_message_creat},
    {.topic = "/emms/%s/info", .create_message = info_message_creat},
    {.topic = "/emms/%s/runInfo", .create_message = runInfo_message_creat},
    {.topic = "/emms/%s/profit/bms", .create_message = profit_bms_message_creat},
    //{.topic = "/emms/%s/pcs/baseData", .create_message = pcs_basedata_message_creat},
    {.topic = "/emms/%s/device/info", .create_message = dev_info_message_creat}
};

cJSON *getProfitBms(cJSON *ask_obj)
{
    int y = 0, m = 0, d = 0;
    int start = 0, end = 0;
    cJSON *date = cJSON_GetObjectItemCaseSensitive(ask_obj, "beginDate");
    if (3 != sscanf(date->valuestring, "%d-%d-%d", &y, &m, &d))
    {
        ems_syslog(LOG_ERR, "beginDate form error:%s", date->valuestring);
        return NULL;
    }
    start = y * 10000 + m * 100 + d;

    date = cJSON_GetObjectItemCaseSensitive(ask_obj, "endDate");
    if (3 != sscanf(date->valuestring, "%d-%d-%d", &y, &m, &d))
    {
        ems_syslog(LOG_ERR, "endDate form error:%s", date->valuestring);
    }
    end = y * 10000 + m * 100 + d;
    cJSON *tmp = cloud_lnxall_get_history(start, end);
    if (tmp == NULL)
    {
        ems_syslog(LOG_ERR, "cloud lnxall get history fail");
    }
    return tmp;
}
static struct
{
    const char *cmd;
    cJSON *(*creat_ack)(cJSON *ask_obj);
} cmd_to_fun_map[] = {
    {.cmd = "getProfitBms", .creat_ack = getProfitBms},
};

int set_parse_message(const cloud_mqtt_its *its, const void *payload, int payload_len, void *out_buff, int out_buff_max)
{
    cJSON *d_obj = NULL;
    cJSON *root = json_parse_string_with_comments((char *)payload);
    if (root == NULL)
    {
        ems_syslog(LOG_ERR, "cJSON Parse error:%s", (char *)payload);
        return -1;
    }

    cJSON *i_obj = cJSON_GetObjectItemCaseSensitive(root, "i");
    for (int i = 0; i < sizeof(cmd_to_fun_map) / sizeof(cmd_to_fun_map[0]); i++)
    {
        if (strcmp(i_obj->valuestring, cmd_to_fun_map[i].cmd) == 0)
        {
            d_obj = cmd_to_fun_map[i].creat_ack(cJSON_GetObjectItemCaseSensitive(root, "p"));
        }
    }

    cJSON_DeleteItemFromObject(root, "p");
    cJSON_AddItemToObject(root, "d", d_obj);
    i_obj = cJSON_GetObjectItemCaseSensitive(root, "t");
    cJSON_SetIntValue(i_obj, time(NULL));
    cJSON_PrintPreallocated(root, out_buff, out_buff_max, 1);
    //
    cJSON_Delete(root);
    return strlen((char *)out_buff);
}

static const cloud_mqtt_rx_it rx_it[] = {
    {.rx_topic = "/emms/%s/set", .tx_topic = "/emms/%s/reply", .parse_message = set_parse_message},
};

cloud_mqtt_its *new_lnxall_its(void)
{
    char tmp[256] = {0};
    cloud_mqtt_its *lnxall_its = NULL;

    get_board_sn(tmp);

    lnxall_its = calloc(1, sizeof(cloud_mqtt_its));
    if (lnxall_its == NULL)
    {
        ems_syslog(LOG_ERR, "calloc error for lnxall_its!!!");
        return NULL;
    }

    lnxall_its->station_id = strdup(tmp);
    lnxall_its->name = strdup("lnxall");
    // 发送
    int it_sum = sizeof(tx_it) / sizeof(tx_it[0]);
    if (it_sum > 0)
    {
        lnxall_its->tx_it = calloc(it_sum, sizeof(cloud_mqtt_tx_it));
        if (lnxall_its->tx_it == NULL)
        {
            ems_syslog(LOG_ERR, "calloc error for tx_it!!!");
            return NULL;
        }

        for (int i = 0; i < it_sum; i++)
        {
            lnxall_its->tx_it[i].create_message = tx_it[i].create_message;
            snprintf(tmp, sizeof(tmp), tx_it[i].topic, lnxall_its->station_id);
            lnxall_its->tx_it[i].topic = strdup(tmp);
        }
        lnxall_its->tx_it_sum = it_sum;
    }
    // 接收
    it_sum = sizeof(rx_it) / sizeof(rx_it[0]);
    if (it_sum > 0)
    {
        lnxall_its->rx_it = calloc(it_sum, sizeof(cloud_mqtt_rx_it));
        if (lnxall_its->rx_it == NULL)
        {
            ems_syslog(LOG_ERR, "calloc error for rx_it!!!");
            return NULL;
        }

        for (int i = 0; i < it_sum; i++)
        {
            lnxall_its->rx_it[i].parse_message = rx_it[i].parse_message;
            snprintf(tmp, sizeof(tmp), rx_it[i].rx_topic, lnxall_its->station_id);
            lnxall_its->rx_it[i].rx_topic = strdup(tmp);
            snprintf(tmp, sizeof(tmp), rx_it[i].tx_topic, lnxall_its->station_id);
            lnxall_its->rx_it[i].tx_topic = strdup(tmp);
        }
        lnxall_its->rx_it_sum = it_sum;
    }
    return lnxall_its;
}
mqtt_platform lnxall_platform = {.name = "lnxall", .new_its = new_lnxall_its, .delete_its = NULL};
#endif