#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <cJSON.h>
#include "configuration_adaptation.h"
#include "../common.h"
#include "define.h"

const board_port_list_t g_board_port_table[] = {
    {"WLOSANY_RK3568",8, 1, 2, 2, 16, 8},
    {"WLOSANY_LC100",8, 1, 1, 2, 16, 8},
};

typedef cJSON *(*create_default_port_attr_func)(int index);

static cJSON *create_default_uart_attr(int index)
{
    cJSON *item = cJSON_CreateObject();
    char name[32];
    snprintf(name, sizeof(name), "RS485_%d", index+1);
    cJSON_AddStringToObject(item, "name", name);
    cJSON_AddNumberToObject(item, "baud", DEFAULT_UART_BAUD);
    cJSON_AddNumberToObject(item, "data_bit", DEFAULT_UART_DATABIT);
    cJSON_AddNumberToObject(item, "stop_bit", DEFAULT_UART_STOPBIT);
    cJSON_AddStringToObject(item, "parity", DEFAULT_UART_PARITY);
    return item;
}

static cJSON *create_default_lan_attr(int index)
{
    cJSON *item = cJSON_CreateObject();
    cJSON_AddStringToObject(item, "name", "lan");
    cJSON_AddStringToObject(item, "type", DEFAULT_LAN_TYPE);
    cJSON_AddStringToObject(item, "ip", DEFAULT_LAN_IP);
    cJSON_AddStringToObject(item, "mask", DEFAULT_LAN_MASK);
    return item;
}

static cJSON *create_default_wan_attr(int index)
{
    cJSON *item = cJSON_CreateObject();
    char name[16];

    snprintf(name, sizeof(name), "wan%d", index+1);
    cJSON_AddStringToObject(item, "name", name);
    cJSON_AddStringToObject(item, "ip", DEFAULT_WAN_IP);
    cJSON_AddStringToObject(item, "gateway", DEFAULT_WAN_GATEWAY);
    cJSON_AddStringToObject(item, "mask", DEFAULT_WAN_MASK);
    cJSON_AddStringToObject(item, "metric", DEFAULT_WAN_METRIC);
    cJSON_AddStringToObject(item, "type", DEFAULT_WAN_TYPE);
    return item;
}

static cJSON *create_default_can_attr(int index)
{
    cJSON *item = cJSON_CreateObject();
    char name[16];
    snprintf(name, sizeof(name), "CAN%d", index+1);
    cJSON_AddStringToObject(item, "name", name);
    cJSON_AddNumberToObject(item, "baud", DEFAULT_CAN_BAUD);

    cJSON *filters = cJSON_CreateArray();

    cJSON *filter1 = cJSON_CreateObject();
    cJSON_AddStringToObject(filter1, "id", "0x00000001");
    cJSON_AddStringToObject(filter1, "mask", "0xffffffff");
    cJSON_AddItemToArray(filters, filter1);

    cJSON *filter2 = cJSON_CreateObject();
    cJSON_AddStringToObject(filter2, "id", "0x00000200");
    cJSON_AddStringToObject(filter2, "mask", "0xffffff00");
    cJSON_AddItemToArray(filters, filter2);

    cJSON_AddItemToObject(item, "filter", filters);
    return item;
}

static cJSON *create_default_di_attr(int index)
{
    cJSON *item = cJSON_CreateObject();
    char name[16];
    snprintf(name, sizeof(name), "DI%d", index+1);
    cJSON_AddStringToObject(item, "name", name);
    cJSON_AddStringToObject(item, "disp_name", name);
    cJSON_AddNumberToObject(item, "ncno", DEFAULT_DI_NCNO);
    return item;
}

static cJSON *create_default_do_attr(int index)
{
    cJSON *item = cJSON_CreateObject();
    char name[16];
    snprintf(name, sizeof(name), "DO%d", index+1);
    cJSON_AddStringToObject(item, "name", name);
    cJSON_AddStringToObject(item, "disp_name", name);
    return item;
}

int update_single_port_config(cJSON *port_json, int port_num,int file_port_count,char *port_type,create_default_port_attr_func create_default_port_attr)
{
    if(port_json == NULL)
        return -1;
    
    if(file_port_count < port_num)
    {
        for(int i = file_port_count; i < port_num; i++)
        {
            cJSON *new_port = create_default_port_attr(i);
            cJSON_AddItemToArray(port_json, new_port);
        }
    }
    else if(port_num < file_port_count)
    {
        for(int i = file_port_count - 1; i >= port_num; i--)
        {
            cJSON_DeleteItemFromArray(port_json, i);
        }    
    }

    //
    if(strcmp(port_type,"wan") == 0 && cJSON_GetArraySize(port_json) == 1)
    {
        cJSON *wan_obj = cJSON_GetArrayItem(port_json, 0);
        if (wan_obj) {
            cJSON *name_item = cJSON_GetObjectItem(wan_obj, "name");
            if (name_item) {
                cJSON_SetValuestring(name_item, "wan");
            }
        }
    }else if(strcmp(port_type,"wan") == 0 && cJSON_GetArraySize(port_json) != 1){
        cJSON *wan_obj = cJSON_GetArrayItem(port_json, 0);
        if (wan_obj) {
            cJSON *name_item = cJSON_GetObjectItem(wan_obj, "name");
            if (name_item) {
                cJSON_SetValuestring(name_item, "wan1");
            }
        }
    }
    return 0;
}

typedef struct {
    const char *type;
    int expected_count;
    cJSON *json;
    create_default_port_attr_func create_default_port_attr;
} port_cfg_t;

void update_board_port_config(board_port_list_t *port_info, char *port_config_file)
{
    char *port_config_str = read_file_data(port_config_file);
    if(port_config_str == NULL)
    {
        ems_syslog(LOG_ERR, "读取端口配置文件失败:%s", port_config_file);
        return;
    }
    cJSON *port_config_json = cJSON_Parse(port_config_str);
    free(port_config_str);
    if(port_config_json == NULL)
    {
        ems_syslog(LOG_ERR, "解析端口配置文件失败:%s", port_config_file);
        return;
    }

    cJSON *dev_cfg = cJSON_GetObjectItem(port_config_json, "dev_cfg");
    if (!dev_cfg) {
        ems_syslog(LOG_ERR, "配置文件缺少dev_cfg节点:%s", port_config_file);
        cJSON_Delete(port_config_json);
        return;
    }
    
    //
    port_cfg_t port_cfgs[] = {
        {"uart", port_info->uart_num, cJSON_GetObjectItem(dev_cfg, "uart"), create_default_uart_attr},
        {"lan",  port_info->lan_num,  cJSON_GetObjectItem(dev_cfg, "lan"), create_default_lan_attr},
        {"wan",  port_info->wan_num,  cJSON_GetObjectItem(dev_cfg, "wan"), create_default_wan_attr},
        {"can",  port_info->can_num,  cJSON_GetObjectItem(dev_cfg, "can"), create_default_can_attr},
        {"di",   port_info->di_num,   cJSON_GetObjectItem(dev_cfg, "di"), create_default_di_attr},
        {"do",   port_info->do_num,   cJSON_GetObjectItem(dev_cfg, "do"), create_default_do_attr},
    };

    for (int i = 0; i < sizeof(port_cfgs)/sizeof(port_cfg_t); i++) {
        cJSON *attr_array = NULL;
        if (port_cfgs[i].json) {
            attr_array = cJSON_GetObjectItem(port_cfgs[i].json, "attr");
        }
        int count = attr_array ? cJSON_GetArraySize(attr_array) : 0;
        if (count != port_cfgs[i].expected_count) {
            update_single_port_config(attr_array, port_cfgs[i].expected_count, count, (char *)port_cfgs[i].type, port_cfgs[i].create_default_port_attr);
        }
    }
    //

    char *new_json_str = cJSON_Print(port_config_json);
    if (new_json_str) {
        write_file_data(port_config_file, new_json_str, strlen(new_json_str));
        free(new_json_str);
    }
    cJSON_Delete(port_config_json);
}



int update_board_config(void)
{
    board_info_t board_info;
    board_port_list_t *port_info = NULL;

    memset(&board_info, 0, sizeof(board_info));
    snprintf(board_info.board_name, sizeof(board_info.board_name), "%s", get_board_name());
    board_info.port_config_check = update_board_port_config;

    for(int i = 0; i < sizeof(g_board_port_table)/sizeof(board_port_list_t); i++)
    {
        if(strcmp(board_info.board_name, g_board_port_table[i].board_name) == 0)
        {
            port_info = (board_port_list_t *)&g_board_port_table[i];
            break;
        }
    }

    if(port_info != NULL)
    {
        board_info.port_config_check(port_info, DEV_PORT_CFG_FILE);
    }

    return 0;
}
