#include "mqtt_emms2.h"
#include <bits/pthreadtypes.h>
#include <pthread.h>
#include <string.h>
#include <sys/syslog.h>
#include "../ems/jsonct.h"

#define SYNC_CABINET_INFO_RECORD "/app/temp/sync_cabinet_info_record.json"

extern int               mqtt_emms2_var_list_num;
extern mqtt_emms2_var_t* mqtt_emms2_var_list[];

typedef struct sync_cabinet_info_t
{
    time_t          set_time;
    char            source[32];
    pthread_mutex_t sync_cabinet_info_mutex;

} sync_cabinet_info_t;

sync_cabinet_info_t cabinet_info_record = {0, "default", PTHREAD_MUTEX_INITIALIZER};
extern void         write_response(mqtt_emms2_var_t* var, int seq, RESPONSE_RESULT result, char* function);

void init_sync_cabinet_info_record()
{
    char* file = read_file_data(SYNC_CABINET_INFO_RECORD);
    if (file != NULL)
    {
        cJSON* root = cJSON_Parse(file);
        if (root != NULL)
        {
            cJSON* item = cJSON_GetObjectItem(root, "set_time");
            if (item != NULL && item->type == cJSON_Number)
                cabinet_info_record.set_time = item->valueint;

            item = cJSON_GetObjectItem(root, "source");
            if (item != NULL && item->type == cJSON_String)
                snprintf(cabinet_info_record.source, sizeof(cabinet_info_record.source), "%s", item->valuestring);

            cJSON_Delete(root);
        }
        free(file);
    }
}
int publish_sync_cabinet_info_payload(mqtt_emms2_var_t* var, char* source, time_t set_time);

void send_sync_cabinet_info(mqtt_emms2_var_t* var)
{
    publish_sync_cabinet_info_payload(var, cabinet_info_record.source, cabinet_info_record.set_time);
}

void read_cabinet_info(struct lnxall_buff* lbuf)
{
    cabinet_info_t* pcfg = &cabinet_info;
    cJSON* root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "name", pcfg->name);
    cJSON_AddNumberToObject(root, "capacity", pcfg->cab_capacity);
    cJSON_AddNumberToObject(root, "power", pcfg->cab_power);
    cJSON_AddStringToObject(root, "station_name", pcfg->cab_station_name);
    cJSON_AddStringToObject(root, "tenant_id", pcfg->tenant_id);
    cJSON_AddStringToObject(root, "cnt_id", pcfg->cnt_id);
    cJSON_AddNumberToObject(root, "rated_power", pcfg->rated_power);

    char* json_str = cJSON_PrintUnformatted(root);
    lbuff_sprintf(lbuf, "%s", json_str);

    cJSON_Delete(root);
    free(json_str);
}

int set_lc_cabname_info(cJSON* info)
{
    cabinet_info_t* pcfg = &cabinet_info;

    const char* new_name = NULL;
    cJSON *name_item = cJSON_GetObjectItem(info, "name");
    if (name_item && cJSON_IsString(name_item)) {
        new_name = name_item->valuestring;
    }
    
    cJSON *cabinfo_json = cJSON_CreateObject();
    if (cabinfo_json == NULL) {
        ems_syslog(LOG_ERR, "lc creat cabinfo json cJSON_CreateObject error");
        return -1;
    }
    
    cJSON_AddStringToObject(cabinfo_json, "name", new_name ? new_name : pcfg->name);
    cJSON_AddNumberToObject(cabinfo_json, "capacity", pcfg->cab_capacity);
    cJSON_AddNumberToObject(cabinfo_json, "power", pcfg->cab_power);
    cJSON_AddStringToObject(cabinfo_json, "station_name", pcfg->cab_station_name);
    cJSON_AddStringToObject(cabinfo_json, "tenant_id", pcfg->tenant_id);
    cJSON_AddStringToObject(cabinfo_json, "id", pcfg->cab_id);

    set_cabinet_info(cabinfo_json, "webui", time(NULL));
    cJSON_Delete(cabinfo_json);
    return 0;
}

int mqtt_set_cabinet_info(mqtt_emms2_var_t* var, cJSON* message, int seq)
{
    cJSON* info = cJSON_GetObjectItem(message, "info");
    if (info == NULL) return -1;

    time_t st       = 0;
    cJSON* set_time = cJSON_GetObjectItem(message, "time");
    if (set_time != NULL && set_time->valueint > 0)
        st = set_time->valueint;

    pthread_mutex_lock(&cabinet_info_record.sync_cabinet_info_mutex);
    if (st >= cabinet_info_record.set_time)
    {
        int ret = set_cabinet_info(info, var->station_id, st);
        write_response(var, seq, ret, FUNCTION_CABINETINFO);
    }
    else
    {
        publish_sync_cabinet_info_payload(var, cabinet_info_record.source, cabinet_info_record.set_time);
    }
    pthread_mutex_unlock(&cabinet_info_record.sync_cabinet_info_mutex);
    return -1;
}

int save_cabinet_info_record(char* source, time_t set_time)
{
    cJSON* root = cJSON_CreateObject();
    cabinet_info_record.set_time = set_time;
    snprintf(cabinet_info_record.source, sizeof(cabinet_info_record.source), "%s", source);
    cJSON_AddStringToObject(root, "source", cabinet_info_record.source);
    cJSON_AddNumberToObject(root, "set_time", cabinet_info_record.set_time);

    char* str = cJSON_Print(root);
    if (str)
    {
        write_file_data(SYNC_CABINET_INFO_RECORD, str, strlen(str));
        free(str);
    }
    cJSON_Delete(root);
    return 0;
}

static int is_sync_cabinet_info(cJSON *it)
{
    char *name = it->string;
    int ok = 0;
    if (cJSON_IsString(it))
    {
        static const char *target_name[] = {"name", "station_name"}; // 只同步这些配置项
        for (int i = 0; i < sizeof(target_name) / sizeof(target_name[0]); i++)
        {
            if (strcmp(name, target_name[i]) == 0)
            {
                if ((cabinet_info_cmp_by_name(name, it->valuestring, &ok) != 0) && (ok != 0))
                {
                    return 1;
                }
            }
        }
    }
    return 0;
}

int set_cabinet_info(cJSON* info, char* source, time_t set_time)
{
    if (info == NULL || source == NULL || source[0] == '\0') return -1;
    if (set_time <= cabinet_info_record.set_time) return -1;

    cJSON* item = NULL;
    int need_sync = 0;
    cJSON_ArrayForEach(item, info)
    {
        char* name = item->string;
        if (is_sync_cabinet_info(item))
        {
            need_sync = 1;
        }
        
        if (item->valuestring != NULL && item->valuestring[0] != '\0')
            write_cabinet_info_by_name(name, item->valuestring);
        else
            write_cabinet_info_by_name(name, &item->valueint);
    }
    get_pcs_ctrl_var()->cabinet_save = true;
    if (need_sync != 0)
    {
        save_cabinet_info_record(source, set_time);
        sync_cabinet_info_all();
    }
    return 0;
}

int sync_cabinet_info_all()
{
    for (int i = 0; i < mqtt_emms2_var_list_num; i++)
    {
        mqtt_emms2_var_t* var = mqtt_emms2_var_list[i];
        if (strcmp(cabinet_info_record.source, var->station_id) != 0)
            publish_sync_cabinet_info_payload(var, cabinet_info_record.source, cabinet_info_record.set_time);
    }
    return 0;
}

extern void package_based_field(mqtt_emms2_var_t* var, char* dist, char* functionId, int seq, char* ExData); //seq=0会自动产生累加值 ExData会直接添加到大括号内部

int publish_sync_cabinet_info_payload(mqtt_emms2_var_t* var, char* source, time_t set_time)
{
	cJSON *message = NULL, *info = NULL;
    char topic[256] = {0};
	char *str = NULL, *pl = NULL, *dist = NULL;

    if (var == NULL)
		return -1;
	snprintf(topic, sizeof(topic), "emms2/" TYPE_POST "/%s/%s", var->topic_sn, FUNCTION_CABINETINFO);

    message = cJSON_CreateObject();
	if (message == NULL)
		return -1;

    cJSON_AddStringToObject(message, "sour", source == NULL ? "" : source);
    cJSON_AddNumberToObject(message, "time", set_time);

    info = cJSON_AddObjectToObject(message, "info");
	if (info == NULL)
		goto exit;
    cJSON_AddStringToObject(info, "name", cabinet_info.name);
    cJSON_AddNumberToObject(info, "capacity", cabinet_info.cab_capacity);
    cJSON_AddNumberToObject(info, "power", cabinet_info.cab_power);
    cJSON_AddStringToObject(info, "station_name", cabinet_info.cab_station_name);
    cJSON_AddStringToObject(info, "tenant_id", cabinet_info.tenant_id);
    cJSON_AddStringToObject(info, "id", cabinet_info.cab_id);

    str = cJSON_Print(message);
	if (str == NULL)
		goto exit;
    pl  = malloc(strlen(str) + 32);
	if (pl == NULL)
		goto exit;
    sprintf(pl, "\"message\":%s", str);

    dist = malloc(strlen(pl) + 512);
	if (dist == NULL)
		goto exit;
    package_based_field(var, dist, FUNCTION_CABINETINFO, 0, pl);

    if (mqtt_publish_message(var, topic, dist, strlen(dist)) < 0)
    {
        ems_syslog(LOG_ERR, "mqtt_publish_message failed, topic: %s", topic);
    }

exit:
    if (dist) free(dist);
    if (pl) free(pl);
    if (str) free(str);
	if (message) cJSON_Delete(message);

    return 0;
}

int sync_cabinet_info_response(mqtt_emms2_var_t* var, cJSON* root)
{
    if (var == NULL || root == NULL) return -1;
    cJSON* result = cJSON_GetObjectItem(root, "result");
    if (result != NULL && result->valueint == 0)
    {
    }
    else
    {
        ems_syslog(LOG_WARNING, "sync_cabinet_info_response failed, result: %d", result ? result->valueint : -1);
    }
    return 0;
}
