#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include "define.h"
#include "jsonct.h"
#include "deviceLayer.h"
#include "emsctrlProc.h"
#include "../common.h"
#include "main.h"
#include "../adapter/pe_adapter.h"
#include <math.h>
#include <time.h>
#include "ems_ua.h"
#include "lc_discovery.h"
#include "../proto_forward.h"
#include "automatic.h"
#include "pub_fun.h"
#include "log_module.h"
#include "../multilanguage.h"
#include "microgridtopology.h"
#include <semaphore.h>
#include "vlc_cfg.h"

const char *vlc_def_cfg = "[\
{\"type\":1,\"name\":\"PowerLimit\",\"double_value\":100},\
{\"type\":1,\"name\":\"Installedcab_coeff\",\"double_value\":100}\
]";
static void vlc_cfg_cb(char *nod, tag_value *data_value, void *par)
{
    // 只更新时间，没有同步值，需要写入文件的时候再去读(因为配置的点位肯定不是频繁写入)
    vlc_cfg_it_list *vlc_cfg_list = (vlc_cfg_it_list *)par;
    vlc_cfg_list->update_time = time(NULL);
}
int vlc_cfg_it_list_register_cb(vlc_cfg_it_list *vlc_cfg_list)
{
    if (vlc_cfg_list == NULL)
    {
        return -1;
    }
    pcs_ctrl_var_t *var = get_pcs_ctrl_var();
    char tag_name[128] = {0};
    for (int i = 0; i < vlc_cfg_list->it_sum; i++)
    {
        snprintf(tag_name, sizeof(tag_name), "%s.%s", vlc_cfg_list->lc_no, vlc_cfg_list->it[i].name);
        if (0 != collector_variant_monitor_add_one_with_par(var, tag_name, vlc_cfg_cb, vlc_cfg_list, 1))
        {
            ems_syslog(LOG_ERR, "vlc_cfg add monitor fail:%s", tag_name);
        }
        else
        {
            ems_syslog(LOG_NOTICE, "vlc_cfg add monitor success:%s", tag_name);
        }
    }
    return 0;
}
int vlc_cfg_it_list_sync_to_tag(vlc_cfg_it_list *vlc_cfg_list)
{
    if (!vlc_cfg_list)
    {
        return -1;
    }
    int it_sum = vlc_cfg_list->it_sum;
    vlc_cfg_it *it = NULL;
    for (int i = 0; i < it_sum; i++)
    {
        it = &(vlc_cfg_list->it[i]);
        if (it->type == 0)
        {
            dev_set_dev_tag_int(vlc_cfg_list->lc_no, it->name, it->int_value);
        }
        else if (it->type == 1)
        {
            dev_set_dev_tag_float(vlc_cfg_list->lc_no, it->name, it->double_value);
        }
        else
        {
            ems_syslog(LOG_ERR, "vlc_cfg_it_list_sync_to_tag[%s]: type error", it->name);
        }
    }
    return 0;
}

char *merge_json_cfg_with_default(const char *source_cfg_data, const char *def_cfg_data) {
    if (!def_cfg_data) return NULL;

    cJSON *src_arr = source_cfg_data ? cJSON_Parse(source_cfg_data) : NULL;
    cJSON *def_arr = cJSON_Parse(def_cfg_data);
    if (!def_arr) {
        if (src_arr) cJSON_Delete(src_arr);
        return NULL;
    }

    if (!src_arr) src_arr = cJSON_CreateArray();

    int def_sum = cJSON_GetArraySize(def_arr);
    int src_sum = cJSON_GetArraySize(src_arr);

    for (int i = 0; i < def_sum; i++) {
        cJSON *def_item = cJSON_GetArrayItem(def_arr, i);
        cJSON *def_name = cJSON_GetObjectItemCaseSensitive(def_item, "name");
        if (!def_name || !cJSON_IsString(def_name)) continue;

        int found = 0;
        for (int j = 0; j < src_sum; j++) {
            cJSON *src_item = cJSON_GetArrayItem(src_arr, j);
            cJSON *src_name = cJSON_GetObjectItemCaseSensitive(src_item, "name");
            if (src_name && cJSON_IsString(src_name) &&
                strcmp(def_name->valuestring, src_name->valuestring) == 0) {
                found = 1;
                break;
            }
        }
        if (!found) {
            cJSON_AddItemToArray(src_arr, cJSON_Duplicate(def_item, 1));
        }
    }

    char *result = cJSON_PrintUnformatted(src_arr);
    cJSON_Delete(src_arr);
    cJSON_Delete(def_arr);
    return result;
}

vlc_cfg_it_list *new_vlc_cfg_it_list(const char *cfg_file, const char *lc_no)
{
    char *data = read_file_data(cfg_file);
    char *merged_data = merge_json_cfg_with_default(data, vlc_def_cfg);
    if (data) free(data);
    if (!merged_data) return NULL;

    cJSON *cfg_arr = cJSON_Parse(merged_data);
    free(merged_data);
    if (cfg_arr == NULL)
    {
        return NULL;
    }
    //
    int cfg_sum = cJSON_GetArraySize(cfg_arr);
    vlc_cfg_it_list *vlc_cfg_list = (vlc_cfg_it_list *)malloc(sizeof(vlc_cfg_it_list));
    if (vlc_cfg_list != NULL)
    {
        vlc_cfg_list->it = (vlc_cfg_it *)malloc(sizeof(vlc_cfg_it) * cfg_sum);
        if (vlc_cfg_list->it != NULL)
        {
            memset(vlc_cfg_list->it, 0, sizeof(vlc_cfg_it) * cfg_sum);
            vlc_cfg_list->it_sum = cfg_sum;
        }
        else
        {
            free(vlc_cfg_list);
            return NULL;
        }
    }
    //
    vlc_cfg_list->update_time = 0;
    snprintf(vlc_cfg_list->cfg_file, sizeof(vlc_cfg_list->cfg_file), "%s", cfg_file);
    snprintf(vlc_cfg_list->lc_no, sizeof(vlc_cfg_list->lc_no), "%s", lc_no);
    //
    cJSON *it = NULL;
    for (int i = 0; i < cfg_sum; i++)
    {
        it = cJSON_GetArrayItem(cfg_arr, i);
        cJSON *type = cJSON_GetObjectItemCaseSensitive(it, "type");
        cJSON *name = cJSON_GetObjectItemCaseSensitive(it, "name");
        if ((type != NULL) && (name != NULL))
        {
            vlc_cfg_list->it[i].type = type->valueint;
            snprintf(vlc_cfg_list->it[i].name, sizeof(vlc_cfg_list->it[i].name), "%s", name->valuestring);
            if (type->valueint == 0)
            {
                cJSON *v = cJSON_GetObjectItemCaseSensitive(it, "int_value");
                if (v != NULL)
                {
                    vlc_cfg_list->it[i].int_value = v->valueint;
                }
            }
            else if (type->valueint == 1)
            {
                cJSON *v = cJSON_GetObjectItemCaseSensitive(it, "double_value");
                if (v != NULL)
                {
                    vlc_cfg_list->it[i].double_value = v->valuedouble;
                }
            }
        }
        else
        {
            vlc_cfg_list->it[i].type = -1; // 设置为无效类型
            ems_syslog(LOG_ERR, "vlc_cfg_it_list_init: cfg_arr item error");
        }
    }
    // vlc_cfg_it_list_register_cb在vlc_cfg_it_list_sync_to_tag前面为了同步数据的时候不调用回调
    vlc_cfg_it_list_register_cb(vlc_cfg_list);
    vlc_cfg_it_list_sync_to_tag(vlc_cfg_list);
    cJSON_Delete(cfg_arr);
    return vlc_cfg_list;
}

time_t vlc_cfg_it_list_get_update_time(vlc_cfg_it_list *vlc_cfg_list)
{
    if (vlc_cfg_list == NULL)
    {
        return 0;
    }
    return vlc_cfg_list->update_time;
}

int vlc_cfg_it_list_sync_to_file(vlc_cfg_it_list *vlc_cfg_list)
{
    if (vlc_cfg_list == NULL)
    {
        return -1;
    }
    int it_sum = vlc_cfg_list->it_sum;
    vlc_cfg_it *it = NULL;
    cJSON *cfg_arr = cJSON_CreateArray();
    for (int i = 0; i < it_sum; i++)
    {
        cJSON *obj = cJSON_CreateObject();
        it = &(vlc_cfg_list->it[i]);
        cJSON_AddItemToObject(obj, "type", cJSON_CreateNumber(it->type));
        cJSON_AddItemToObject(obj, "name", cJSON_CreateString(it->name));
        if (it->type == 0)
        {
            it->int_value = dev_get_dev_tag_int(vlc_cfg_list->lc_no, it->name);
            cJSON_AddItemToObject(obj, "int_value", cJSON_CreateNumber(it->int_value));
        }
        else if (it->type == 1)
        {
            it->double_value = dev_get_dev_tag_float(vlc_cfg_list->lc_no, it->name);
            cJSON_AddItemToObject(obj, "double_value", cJSON_CreateNumber(it->double_value));
        }
        else
        {
            ems_syslog(LOG_ERR, "vlc_cfg_it_list_sync_to_file[%s]: type error", it->name);
        }
        cJSON_AddItemToArray(cfg_arr, obj);
    }
    vlc_cfg_list->update_time = 0;
    char *json = cJSON_Print(cfg_arr);
    int ret = write_file_data(vlc_cfg_list->cfg_file, json, strlen(json));
    free(json);
    cJSON_Delete(cfg_arr);
    return ret;
}
