#include "bmser_ems_db_control_db.h"    
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "heartbeat.h"
#include <cJSON.h>


int bmser_write_heartBeat(int attr, uint16_t count)
{
    uint8_t buff[2] = {0};
    buff[0] = (count >> 8) & 0xff;
    buff[1] = count & 0xff;
    EMS_DEV_REG_DATA_S write_par = {.dataType = BMS_DATA};
    write_par.bankId = (attr >> 16) & 0xffff;
    write_par.rackId = attr & 0xffff;
    write_par.startAddr = HEARTBEAT_ADDRESS;
    write_par.regCount = 1;
    write_par.len =  2;
    write_par.data = (uint8_t *)buff;
    return BmserProtocolExt_WriteRegisterDb_No_Waiting_Result(&write_par);
}

int write_devs_heartBeat(heartbeat_t* hb_list)
{
    for (int i = 0; i < hb_list->device_count; i++)
    {
        int ret = bmser_write_heartBeat(hb_list->device[i].no, hb_list->device[i].count++);
        if (ret != 0)
        {
            printf("write heartBeat error\n");
        }
    }
    return 0;
}

int get_device_size(cJSON* dev_class)
{
    int count = 0;
    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) continue;

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

            cJSON* protocol = cJSON_GetObjectItem(dev_item, "protocol");
            if (protocol == NULL) continue;
            if (strcmp(protocol->valuestring, "bmser_bin") != 0) continue;
            count++;
        }
    }
    return count;
}

int get_device_addr(heartbeat_t* hb_list, cJSON* dev_class)
{
    if(hb_list->device != NULL) free(hb_list->device);
    hb_list->device = (device_t *)malloc(sizeof(device_t) * hb_list->device_count);
    if(hb_list->device == NULL) return -1;
    int dev_class_size = cJSON_GetArraySize(dev_class);
    int index = 0;
    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) continue;

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

            cJSON* protocol = cJSON_GetObjectItem(dev_item, "protocol");
            if (protocol == NULL) continue;
            if (strcmp(protocol->valuestring, "bmser_bin") != 0) continue;

            cJSON* dev_no = cJSON_GetObjectItem(dev_item, "no");
            cJSON* dev_addr = cJSON_GetObjectItem(dev_item, "addr");
            if (dev_no == NULL || dev_addr == NULL) continue;
            int sindex = index++;
            if(index > hb_list->device_count) break;
            hb_list->device[sindex].no = atoi(dev_addr->valuestring);
            strncpy(hb_list->device[sindex].dev_no, dev_no->valuestring, sizeof(hb_list->device[sindex].dev_no));
            hb_list->device[sindex].count = 1;
        }
    }
    return 0;
}

int read_device_config(heartbeat_t* hb_list)
{
    int   len  = 0;
    char* buff = NULL;
    int   ret  = -1;
    cJSON* root = NULL;
    int   fd   = open(DEVICE_CONFIG_PATH, O_RDONLY);
    if (fd < 0)
    {
        goto END;
    }
    len  = lseek(fd, 0, SEEK_END);
    if (len <= 0)
    {
        goto END;
    }

    buff = (char *)malloc(len + 1);
    if (buff == NULL)
    {
        goto END;
    }

    lseek(fd, 0, SEEK_SET);
    read(fd, buff, len);
    buff[len] = '\0';

    root = cJSON_Parse(buff);
    if (root == NULL)
    {
        goto END;
    }

    cJSON* dev_class = cJSON_GetObjectItem(root, "dev_class");
    if (dev_class == NULL)
    {
        goto END;
    }

    hb_list->device_count = get_device_size(dev_class);
    if( hb_list->device_count <= 0)
    {
        goto END;
    }

    get_device_addr(hb_list, dev_class);

END:
    if (fd > 0) close(fd);
    if (buff != NULL) free(buff);
    return ret;
}

void check_and_read_file(void)
{
    struct stat file_stat;

    // 获取文件状态信息
    if (stat(DEVICE_CONFIG_PATH, &file_stat) < 0)
    {
        perror("stat");
        return;
    }

    // 检查文件是否已更新
    if (file_stat.st_mtime > heartbeat_list.config_time)
    {
        heartbeat_list.config_time = file_stat.st_mtime; // 更新最后修改时间
        read_device_config(&heartbeat_list);
    }
}
