#include "define.h"
#include "mqtt_emms2.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syslog.h>
#include "../ems/jsonct.h"

// 同步模板文件给站控和云平台
#define ALARM_ZH_FILE_PATH "/app/global/alarminfo/zh_CN/alarm_def.json"
#define ALARM_EN_FILE_PATH "/app/global/alarminfo/en_US/alarm_def.json"
#define GLOBAL_TEMPLATE_FILE_PATH "/app/global/template"
#define SYNC_RECORD_FILE_HEAD "/app/temp/sync_record_"
#define SYNC_RECORD_DIR     "/app/temp/"
// 获取同步记录

static int check_temp_dir(const char* dir)
{
    if (dir == NULL)
        return -1;

    if (access(dir, F_OK) != 0)
    {
        if (mkdir(dir, 0755) != 0)
        {
            ems_syslog(LOG_ERR, "MQTT check template dir fail, dir %s", dir);
            return -1;
        }
    }
    return 0;
}

static cJSON* get_sync_record_json(const mqtt_emms2_var_t* var)
{
    char file_path[256] = {0};
    char *buf = NULL;

    snprintf(file_path, sizeof(file_path), "%s%s.json", SYNC_RECORD_FILE_HEAD, var->station_id);

    buf = read_file_data(file_path);
    if (buf == NULL)
    {
        return cJSON_CreateObject();
    }
    else
    {
        cJSON* root = cJSON_Parse(buf);
        free(buf);
        if (root == NULL)
        {
            return cJSON_CreateObject();
        }
        else
        {
            return root;
        }
    }
    return NULL;
}

// 发送文件
extern int mqtt_publish_message(const mqtt_emms2_var_t* var, char* pub_topic, char* data, int data_len);

static int mqtt_upload_temp_or_alarm(const mqtt_emms2_var_t* var, const char* topic_post, const char* Funcid, const char* lang, const char* filename, const char* file_path)
{
    if (var == NULL || filename == NULL || file_path == NULL) return -1;
    if (access(file_path, F_OK) != 0) return -1;

    char* topic        = NULL;
    char* payload      = NULL;
    int   payload_size = 0;
    int   ret          = -1;

    char* file = read_file_data(file_path);
    cJSON* root = NULL;
    char* file_data = NULL;
    if (file == NULL) goto END;
    root = cJSON_Parse(file);
    if (root == NULL) goto END;
    file_data = cJSON_PrintUnformatted(root);
    if (file_data == NULL) goto END;

    topic = malloc(256);
    if (topic == NULL)
        goto END;

    payload_size = strlen(file_data) + 512;
    payload      = malloc(payload_size);

    if (payload == NULL)
        goto END;
    snprintf(topic, 256, "emms2/%s/%s/%s", topic_post, var->topic_sn, Funcid);

    snprintf(payload,
             payload_size,
             "{\"funcId\":\"%s\", \"lcSN\":\"%s\",\"seq\" : %d,\"time\" : %ld,\"lang\" : \"%s\",\"file\":\"%s\" , \"%s\":%s}",
             Funcid,
             var->topic_sn,
             var->seq,
             time(NULL),
             lang,
             filename,
             strcmp(Funcid, FUNCTION_TEMPLATE) == 0 ? "template" : "alarm",
             file_data);

    ret = mqtt_publish_message(var, topic, payload, strlen(payload));

    ems_syslog(LOG_INFO, "MQTT upload template:%s,topic %s", filename, Funcid);
END:
    if (file) free(file);
    if (file_data) free(file_data);
    if (root) cJSON_Delete(root);
    if (topic) free(topic);
    if (payload) free(payload);
    return ret;
}

// 检查并上传模板文件(单个文件中英文)
static int check_and_upload_the_template(const mqtt_emms2_var_t* var, char* filename, cJSON* record)
{
    if (var == NULL || filename == NULL || record == NULL)
        return -1;

    char        file_path[128] = {0};
    char        md5[33]        = {0};
    const char* languages[2]   = {"zh_CN", "en_US"};

    for (int i = 0; i < 2; i++)
    {
        snprintf(file_path, sizeof(file_path), "%s/%s/%s", GLOBAL_TEMPLATE_FILE_PATH, languages[i], filename);
        if (access(file_path, F_OK) != 0) return -1;

        get_file_md5(file_path, md5);

        cJSON* item = cJSON_GetObjectItem(record, filename);
        if (item == NULL)
        {
            if (mqtt_upload_temp_or_alarm(var, TYPE_POST, FUNCTION_TEMPLATE, languages[i], filename, file_path) == 0)
            {
                item = cJSON_CreateObject();
                cJSON_AddItemToObject(record, filename, item);
                cJSON_AddStringToObject(item, languages[i], md5);
            }
        }
        else
        {
            cJSON* lang_item = cJSON_GetObjectItem(item, languages[i]);
            if (lang_item == NULL)
            {
                if (mqtt_upload_temp_or_alarm(var, TYPE_POST, FUNCTION_TEMPLATE, languages[i], filename, file_path) == 0)
                    cJSON_AddStringToObject(item, languages[i], md5);
            }
            else if (strcmp(lang_item->valuestring, md5) != 0)
            {
                if (mqtt_upload_temp_or_alarm(var, TYPE_POST, FUNCTION_TEMPLATE, languages[i], filename, file_path) == 0)
                    cJSON_ReplaceItemInObject(item, languages[i], cJSON_CreateString(md5));
            }
        }
    }

    return 0;
}
// 检查并上传告警文件(中英文)
static int check_and_upload_alarms(const mqtt_emms2_var_t* var, cJSON* record)
{
    if (var == NULL || record == NULL)
        return -1;

    char        md5[33]       = {0};
    const char* filename      = "alarm_def.json";
    const char* file_paths[2] = {ALARM_ZH_FILE_PATH, ALARM_EN_FILE_PATH};
    const char* languages[2]  = {"zh_CN", "en_US"};
    for (int i = 0; i < 2; i++)
    {
        if (access(file_paths[i], F_OK) != 0)
        {
            ems_syslog(LOG_NOTICE, "MQTT upload alarm file , file %s not exist", file_paths[i]);
            continue;
        }

        get_file_md5(file_paths[i], md5);

        cJSON* item = cJSON_GetObjectItem(record, filename);
        if (item == NULL)
        {
            if (mqtt_upload_temp_or_alarm(var, TYPE_POST, FUNCTION_ALARMFILE, languages[i], filename, file_paths[i]) == 0)
            {
                cJSON* new_item = cJSON_CreateObject();
                cJSON_AddItemToObject(record, filename, new_item);
                cJSON_AddStringToObject(new_item, languages[i], md5);
            }
        }
        else
        {
            cJSON* lang_item = cJSON_GetObjectItem(item, languages[i]);
            if (lang_item == NULL)
            {
                if (mqtt_upload_temp_or_alarm(var, TYPE_POST, FUNCTION_ALARMFILE, languages[i], filename, file_paths[i]) == 0)
                    cJSON_AddStringToObject(item, languages[i], md5);
            }
            else if (strcmp(lang_item->valuestring, md5) != 0)
            {
                if (mqtt_upload_temp_or_alarm(var, TYPE_POST, FUNCTION_ALARMFILE, languages[i], filename, file_paths[i]) == 0)
                    cJSON_ReplaceItemInObject(item, languages[i], cJSON_CreateString(md5));
            }
        }
    }
    return 0;
}
// 保存同步记录
static void save_sync_record_json(const mqtt_emms2_var_t* var, cJSON* record)
{
    if (var == NULL || record == NULL)
        return;

    char* data = cJSON_Print(record);
    if (data == NULL)
    {
        ems_syslog(LOG_ERR, "MQTT save sync record json fail");
        return;
    }

    char file[256] = {0};
    snprintf(file, sizeof(file), "%s%s.json", SYNC_RECORD_FILE_HEAD, var->station_id);
    write_file_data(file, data, strlen(data));
    free(data);
}

static int check_and_upload_the_ems_template(const mqtt_emms2_var_t* var, cJSON* record)
{
    if (var == NULL || record == NULL)
        return -1;

    char file_path[128] = {0};
    char md5[33]        = {0};
    char language[8]    = {0};

    // 获取当前系统语言
    char* lang = getenv("LANG");
    if (lang != NULL) sscanf(lang, "%[^.]", language);

    if (strlen(language) != 5) snprintf(language, sizeof(language), "zh_CN");

    snprintf(file_path, sizeof(file_path), "%s/%s", TEMPLATE_DIR, EMS_TEMP_MASTER_FILE);
    if (access(file_path, F_OK) != 0) return -1;
    get_file_md5(file_path, md5);

    cJSON* item = cJSON_GetObjectItem(record, EMS_TEMP_MASTER_FILE);
    if (item == NULL)
    {
        if (mqtt_upload_temp_or_alarm(var,TYPE_POST, FUNCTION_TEMPLATE, language, EMS_TEMP_MASTER_FILE, file_path) == 0)
            cJSON_AddStringToObject(record, EMS_TEMP_MASTER_FILE, md5);
    }
    else if (strcmp(item->valuestring, md5) != 0)
    {
        if (mqtt_upload_temp_or_alarm(var,TYPE_POST, FUNCTION_TEMPLATE, language, EMS_TEMP_MASTER_FILE, file_path) == 0)
            cJSON_ReplaceItemInObject(record, EMS_TEMP_MASTER_FILE, cJSON_CreateString(md5));
    }
    return 0;
}

cJSON* get_device_config()
{
    cJSON* root = NULL;
    char file_path[256] = {0};
    snprintf(file_path, sizeof(file_path), "%s/%s", CONFIG_PATH, COLLECTOR_DEVICE);
    char* data = read_file_data(file_path);
    if (data == NULL)
    {
        ems_syslog(LOG_ERR, "MQTT get device config fail");
        goto END;
    }
    root = cJSON_Parse(data);
    free(data);

    if (get_cabinet_info()->en_lc_ctrl)
    {
        char* data = read_file_data(EMS_LC_ALL_DEVICE_CFG);
        if (data != NULL)
        {
            
            cJSON* lc_root = cJSON_Parse(data);
            if (lc_root != NULL)
            {
                cJSON* root_dev = cJSON_GetObjectItem(root, "dev_class");
                if (root_dev == NULL)
                {
                    root_dev = cJSON_CreateArray();
                    cJSON_AddItemToObject(root, "dev_class", root_dev);
                }
                cJSON* lc_devs = cJSON_GetObjectItem(lc_root, "dev_class");
                if (lc_devs != NULL)
                {
                    int size = cJSON_GetArraySize(lc_devs);
                    while (size > 0)
                    {
                        cJSON* obj = cJSON_DetachItemFromArray(lc_devs, 0);
                        cJSON_AddItemToArray(root_dev, obj);
                        size = cJSON_GetArraySize(lc_devs);
                    }
                }
                cJSON_Delete(lc_root);
            }
            free(data);
        }
    }
END:
    return root;
}

// 检查并上传告警和模板文件(入口)
int check_and_upload_templates_and_alarm(const mqtt_emms2_var_t* var)
{
    if (check_temp_dir(SYNC_RECORD_DIR) < 0) return -1;

    char   file_path[256] = {0};
    cJSON* record = get_sync_record_json(var);


    cJSON* root = get_device_config();
    if (root == NULL) goto END;
    cJSON* dev_class = cJSON_GetObjectItem(root, "dev_class");
    if (dev_class == NULL || !cJSON_IsArray(dev_class) || cJSON_GetArraySize(dev_class) == 0)
        goto END;
    int dev_class_size = cJSON_GetArraySize(dev_class);

    for (int i = 0; i < dev_class_size; i++)
    {
        cJSON* dev_class_item = cJSON_GetArrayItem(dev_class, i);
        if (dev_class_item == NULL)
            continue;
        cJSON* type = cJSON_GetObjectItem(dev_class_item, "type");
        if (type == NULL || !cJSON_IsString(type) || strlen(type->valuestring) == 0 || strcmp(type->valuestring, "CELL") == 0){
            continue;
        }

        cJSON* devs = cJSON_GetObjectItem(dev_class_item, "devs");
        if (devs == NULL || !cJSON_IsArray(devs))
            continue;

        int dev_size = cJSON_GetArraySize(devs);
        for (int j = 0; j < dev_size; j++)
        {
            cJSON* dev = cJSON_GetArrayItem(devs, j);
            if (dev == NULL || !cJSON_IsObject(dev))
                continue;
            cJSON* template = cJSON_GetObjectItem(dev, "template");
            if (template == NULL || !cJSON_IsString(template) || strlen(template->valuestring) == 0)
                continue;
            char* file_name = NULL;
            if (template->valuestring[0] == '/') //绝对路径
            {
                file_name = strrchr(file_path, '/') + 1;
            }
            else
            {
                file_name = template->valuestring;
            }
            check_and_upload_the_template(var, file_name, record);
        }
    }
    check_and_upload_the_ems_template(var, record);
    if (strcmp(var->station_id, MQTT_STACTRL_STATION_ID) == 0)
    {
        check_and_upload_alarms(var, record);
    }
    // 保存同步记录
    save_sync_record_json(var, record);
END:
    if (record) cJSON_Delete(record);
    if (root) cJSON_Delete(root);
    return 0;
}

int upload_template_by_dev_no(const mqtt_emms2_var_t* var, const char* dev_no, const char* languages, char* topic_post)
{
    char*  lc_device_cfg_str = NULL;
    char*  device_cfg_str    = NULL;
    char   file_path[256]    = {0};
    int    ret               = -1;
    lc_device_cfg_str     = read_file_data(CONFIG_PATH"/lc/device_config.json");
    device_cfg_str        = read_file_data(CONFIG_PATH"/device_config.json");
    cJSON* root_lc        = cJSON_Parse(lc_device_cfg_str);
    cJSON* root           = cJSON_Parse(device_cfg_str);
    
    cJSON* roots[2] = {root, root_lc};

    for (int k = 0; k < 2; k++)
    {
        cJSON* curr_root = roots[k];
        if (curr_root == NULL) continue;

        cJSON* dev_class = cJSON_GetObjectItem(curr_root, "dev_class");
        if (dev_class == NULL || !cJSON_IsArray(dev_class) || cJSON_GetArraySize(dev_class) == 0)
            continue;
        
        int dev_class_size = cJSON_GetArraySize(dev_class);

        for (int i = 0; i < dev_class_size; i++)
        {
            cJSON* dev_class_item = cJSON_GetArrayItem(dev_class, i);
            if (dev_class_item == NULL)
                continue;
            cJSON* devs = cJSON_GetObjectItem(dev_class_item, "devs");
            if (devs == NULL || !cJSON_IsArray(devs))
                continue;

            int dev_size = cJSON_GetArraySize(devs);
            for (int j = 0; j < dev_size; j++)
            {
                cJSON* dev = cJSON_GetArrayItem(devs, j);
                if (dev == NULL || !cJSON_IsObject(dev))
                    continue;

                cJSON* no = cJSON_GetObjectItem(dev, "no");
                if (no != NULL && cJSON_IsString(no) && strcmp(no->valuestring, dev_no) == 0)
                {
                    cJSON* template = cJSON_GetObjectItem(dev, "template");
                    if (template == NULL || !cJSON_IsString(template) || strlen(template->valuestring) == 0)
                        continue;

                    char* file_name = NULL;
                    if (template->valuestring[0] == '/') //绝对路径
                    {
                        file_name = strrchr(template->valuestring, '/') + 1;
                    }
                    else
                    {
                        file_name = template->valuestring;
                    }
                    snprintf(file_path, sizeof(file_path), "%s/%s/%s", GLOBAL_TEMPLATE_FILE_PATH, languages, file_name);
                    if (mqtt_upload_temp_or_alarm(var, TYPE_GET_RESP, FUNCTION_TEMPLATE, languages, file_name, file_path) == 0)
                    {
                        ret = 0;
                    }
                    goto END;
                }
            }
        }
    }

END:
    if (lc_device_cfg_str) free(lc_device_cfg_str);
    if (device_cfg_str) free(device_cfg_str);
    if (root_lc) cJSON_Delete(root_lc);
    if (root) cJSON_Delete(root);
    return ret;
}

int upload_alarminfo_by_language(const mqtt_emms2_var_t* var, const char* lang, char* topic_post)
{
    if (var == NULL)
        return -1;

    const char* filename      = "alarm_def.json";
    const char* file_paths[2] = {ALARM_ZH_FILE_PATH, ALARM_EN_FILE_PATH};
    const char* languages[2]  = {"zh_CN", "en_US"};

    int ret = -1;
    for (int i = 0; i < 2; i++)
    {
        if (strcmp(lang, languages[i]) != 0) continue;

        if (access(file_paths[i], F_OK) != 0)
        {
            ems_syslog(LOG_NOTICE, "MQTT upload alarm file , file %s not exist", file_paths[i]);
            continue;
        }

        if (mqtt_upload_temp_or_alarm(var, topic_post, FUNCTION_ALARMFILE, languages[i], filename, file_paths[i]) == 0)
        {
            ret = 0;
        }
    }
    return ret;
}

int upload_template_request(const mqtt_emms2_var_t* var, cJSON* info)
{
    cJSON* dev_no    = cJSON_GetObjectItem(info, "dev_no");
    cJSON* languages = cJSON_GetObjectItem(info, "lang");
    if (dev_no == NULL || dev_no->valuestring == NULL || dev_no->valuestring[0] == '\0' ||
        languages == NULL || languages->valuestring == NULL || languages->valuestring[0] == '\0')
        return -1;
    return upload_template_by_dev_no(var, dev_no->valuestring, languages->valuestring, TYPE_GET_RESP);
}

int upload_alarm_requset(const mqtt_emms2_var_t* var, cJSON* info)
{
    cJSON* languages = cJSON_GetObjectItem(info, "lang");
    if (languages == NULL || languages->valuestring == NULL || languages->valuestring[0] == '\0')
        return -1;
    return upload_alarminfo_by_language(var, languages->valuestring,TYPE_GET_RESP);
}

int check_and_clear_upload_record(char *mqtt_id, cJSON* config)
{
    if (mqtt_id == NULL || config == NULL) return -1;
    cJSON *new_config = config;
    if (new_config == NULL) return -1;


    char file[256] = {0};
    cJSON *new_host = NULL;
    cJSON *new_port = NULL;
    char *old_config_file = NULL;
    cJSON *old_config = NULL;
    cJSON *old_host = NULL;
    cJSON *old_port = NULL;

    new_host = cJSON_GetObjectItem(new_config, "host");
    new_port = cJSON_GetObjectItem(new_config, "port");

    if (new_host == NULL || new_host->valuestring == NULL || new_host->valuestring[0] == '\0' ||
         new_port == NULL || new_port->valueint == 0)
            goto END;
    if (strcmp(mqtt_id, MQTT_EMMS2_STATION_ID) == 0) 
    {
        old_config_file = read_file_data(MQTT_EMMS2_CONFIG_PATH);
    }
    else if(strcmp(mqtt_id, MQTT_STACTRL_STATION_ID) == 0) {
        old_config_file = read_file_data(MQTT_STACTRL_CONFIG_PATH);
    }
    if (old_config_file == NULL)
        goto END;

    old_config = cJSON_Parse(old_config_file);
    if (old_config == NULL)
        goto END;

    old_host = cJSON_GetObjectItem(old_config, "host");
    old_port = cJSON_GetObjectItem(old_config, "port");

    if (old_host == NULL || old_host->valuestring == NULL || old_port == NULL ||
        strcmp(new_host->valuestring, old_host->valuestring) != 0 ||
        new_port->valueint != old_port->valueint) 
    {
        snprintf(file, sizeof(file), "%s%s.json", SYNC_RECORD_FILE_HEAD, mqtt_id);
        if (access(file, F_OK) == 0) 
        {
            remove(file);
            return 0;
        }
    }

END:
  if (old_config) cJSON_Delete(old_config);
  if (old_config_file) free(old_config_file);
  return -1;
}
