#include "utils.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include "signal.h"
#include "main.h"
#include "semaphore.h"

#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/statvfs.h>
#include <sys/wait.h> 

#include <sys/sysinfo.h>

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <semaphore.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/stat.h>  
#include <stdbool.h> 
#include <dirent.h> 
#include "../cmdclient.h"
//static pthread_rwlock_t rw_lock = PTHREAD_RWLOCK_INITIALIZER;
static ems_base_variant_t *tags[EMS_TAG_SIZE];
static int tags_size = 0;


int sem_wait_with_time(sem_t *sem,int timeout_s,int timeout_ms) //等待信号量
{	
	struct timeval now;
	struct timespec outtime;
	gettimeofday(&now,NULL);
	outtime.tv_sec = now.tv_sec+timeout_s;
	outtime.tv_nsec = (now.tv_usec+timeout_ms*1000)*1000;
	return sem_timedwait(sem, &outtime);
}

int ems_base_variant_add(const ems_base_variant_t *val)
{
   // pthread_rwlock_wrlock(&rw_lock);
    if(tags_size >= EMS_TAG_SIZE)
    {
        ems_syslog(LOG_ERR, "over the max size:%d",EMS_TAG_SIZE);
       // pthread_rwlock_unlock(&rw_lock);
        return -1;
    }
    tags[tags_size] = calloc(sizeof(ems_base_variant_t),1);
    memcpy(tags[tags_size],val,sizeof(ems_base_variant_t));
    ems_syslog(LOG_NOTICE, "tag[%d] dev:%s var:%s name:%s",tags_size,tags[tags_size]->dev,tags[tags_size]->variant,tags[tags_size]->name);
    tags_size++;
    //pthread_rwlock_unlock(&rw_lock);
    return 0;
}

int ems_base_variant_multi_add(const ems_base_variant_t *val,size_t size)
{
    for(int i = 0;i<size;i++)
    {
        int ret = ems_base_variant_add(&val[i]);
        if(ret != 0) return ret;
    }
    return 0;
}

int ems_base_variant_sing_add(ems_base_variant_t *val)
{
    return ems_base_variant_add(val);
}

int ems_base_variant_get(ems_base_variant_t ***val,int *size)
{
    *val = tags;
    *size = tags_size;
    return 0;
}

void ems_base_variant_free()
{
   // pthread_rwlock_wrlock(&rw_lock);
    for(int i = 0;i<tags_size;i++)
    {
        free(tags[i]);
    }
    tags_size = 0;
   // pthread_rwlock_unlock(&rw_lock);
}


bool check_float_equal(float a,float b) //判断两个浮点值是否相等
{
    if(fabsf(a-b)<0.0001f)
        return true;
    return false;
}

// 当前时间段关键信息
key_info_t key_info = {.index = 0, .last_index = -1, .power = 0, .repower = 0, .soclower = 0, .socup = 0};
double update_plan_cfg(pcs_ctrl_var_t *var)
{
#if 1
    double ret_power = 0;
    int power = 0;
    int repower = 0;
    int socup = 0;
    int soclower = 0;

    // 检查策略SOC阈值是否合理，不合理则上报告警信息
    check_plan_soc_suitable(&g_usercfg_variant);

    int ret = get_current_plan(&g_usercfg_variant, &power, &repower, &socup, &soclower);
    if(ret < 0 ){
        ems_syslog(LOG_NOTICE, "TOU not find");
        power = 0;
    }
    key_info.index = ret;
    key_info.power = power;
    key_info.repower = repower;
    key_info.socup = socup;
    key_info.soclower = soclower;

    float last_power = dev_get_dev_tag_float(DEV_NO_EMS, SET_ACT_POWER);
    if(fabs(last_power - (float)power) > 0.0001)
    {
        dev_set_dev_tag_float(DEV_NO_EMS, SET_ACT_POWER,  power);
    }
    float last_repower = dev_get_dev_tag_float(DEV_NO_EMS, SET_REACTPOWER);
    if(fabs(last_repower - (float)repower) > 0.0001)
    {
        dev_set_dev_tag_float(DEV_NO_EMS, SET_REACTPOWER,  repower);
    }
    ret_power = power;
    //ems_syslog(LOG_NOTICE, "current plan: [power:%d kw] [[mode:%d] [0-idle 1-dischar 2-char]]",power,mode);
    ems_syslog(LOG_NOTICE, "current plan: [power:%d kw]",power);
    ems_syslog(LOG_NOTICE, "current plan: [repower:%d kw] [soc_up: %d] [soc_low: %d]",repower, socup, soclower);
    return ret_power;
#else
    bool state = false;
    int power = 0;
    static int cur_power = 0;
    int filter_t = g_usercfg_variant.ProtectReverseWin;
    if (filter_t < 1)
    {
        filter_t = 1;
    }

    int ret = get_current_plan(&g_usercfg_variant, &power);
    if (ret < 0)
    {
        ems_syslog(LOG_NOTICE, "TOU not find");
        power = 0;
    }
    float last_power = dev_get_dev_tag_float(DEV_NO_EMS, SET_ACT_POWER);
    if (fabs(last_power - (float)power) > 0.0001)
    {
        state = true;
    }
    // ems_syslog(LOG_NOTICE, "current plan: [power:%d kw] [[mode:%d] [0-idle 1-dischar 2-char]]",power,mode);
    ems_syslog(LOG_NOTICE, "current plan: [power:%d kw]", power);

    if ((power > 0) && (state == true)) // 充电且值更新
    {
        double p1 = 0;
        p1_filter_get_min(filter_t, &p1); //
        ems_syslog(LOG_NOTICE, "p1 filter get min:%f, %d", p1, filter_t);
        if (p1 > g_usercfg_variant.Pset) // 没有逆流
        {
            if (cur_power < power)
            {
                p1 = p1 - g_usercfg_variant.Pset;
                if (p1 > 10)
                {
                    cur_power = cur_power + 0.1 * p1;
                }
                else
                {
                    cur_power += 1;
                }
            }

            if (cur_power > power)
            {
                cur_power = power;
            }
        }
        else
        {
            // 到达限定逆流值了，功率值不用再增加，逆流部分交给外部的pid校准回去
        }
    }
    else
    {
        cur_power = power;
    }
    dev_set_dev_tag_float(DEV_NO_EMS, SET_ACT_POWER, cur_power);
    return state;
#endif
}
int check_workstate_by_time(int time,float powernow)
{
    return check_to_plan_time(&g_usercfg_variant,time,powernow);
}

long long get_dir_size(const char* pathname,char* first_file) //获取指定目录大小  //并返回最早的文件名称
{
        long long  size = 0;
        //打开目录
        DIR* dir = opendir(pathname);
        if(dir == NULL)
        {
            perror("open opendir error:");
            return -1;
        }
        //不断的获取目录项
        struct dirent *d = NULL;
        char name_tmp[256] = {0};
        while((d = readdir(dir)))
        {
                //进行具体操作
                //进行路径名的拼接
                char dir_pathname[512] = {0};
                sprintf(dir_pathname,"%s/%s",pathname,d->d_name);
                //判断文件类型
                if(d->d_type == DT_REG)//普通文件
                {
                        //求大小
                        struct stat st;
                        stat(dir_pathname,&st);
                        size += st.st_size;
                        if (strlen(name_tmp) == 0)
                        {
                            strcpy(name_tmp,d->d_name);
                        }
                        if (strcmp(name_tmp,d->d_name)>0)
                        {
                            strcpy(name_tmp,d->d_name);
                        }                        
                }
                //只有一级目录
                // else if(d->d_type == DT_DIR)//目录文件 
                // {
                //         //把 . 和.. 过滤
                //         if(strcmp(d->d_name,".") == 0 || strcmp(d->d_name,"..") == 0)
                //         {
                //                 continue;
                //         }
                //         //把子目录的大小获取
                //         size +=  get_dir_size(dir_pathname);
                // }
        }
        strcpy(first_file,name_tmp);
        //关闭目录
        closedir(dir);
        return size;
}


#define DEBUG 0

struct sysinfo info;

void open_sysinfo(void) {
  int ret = 0;
  ret = sysinfo(&info);
  if (ret != 0) {
    perror("get sys_info failed\n");
    exit(0);
  }
}

bool is_dir(const char* path) {  
    struct stat statbuf;  
    if (stat(path, &statbuf) != 0) {  
        return false;  // 路径不存在  
    }  
    if (S_ISDIR(statbuf.st_mode)) {  
        return true;  // 路径是一个目录  
    } else {  
        return false;  // 路径不是一个目录  
    }  
}

enum buart_rate{
	b9600=0,
	b57600,
	b115200,
};

int Net_AtPortInit(int NetComFd,int iBaud)
{
    int aiNameArray[]  = {b9600, b57600, b115200};
    int aiSpeedArray[] = {B9600,B57600,B115200};
    struct termios tOptions;
    int iCfgSpeed = 0x00;
	unsigned int uiLoop = 0;
    bzero(&tOptions, sizeof(tOptions));

    for(uiLoop = 0; (uiLoop < sizeof(aiSpeedArray) / sizeof(int)); uiLoop++)
    {
        if(iBaud == aiNameArray[uiLoop])
        {
            iCfgSpeed = aiSpeedArray[uiLoop];
        }
    }

    tcgetattr(NetComFd, &tOptions);
    tcflush(NetComFd, TCIOFLUSH);


    cfsetispeed(&tOptions, iCfgSpeed);
    cfsetospeed(&tOptions, iCfgSpeed);

    tcsetattr(NetComFd, TCSANOW, &tOptions);
    tcflush(NetComFd, TCIOFLUSH);


    tcgetattr(NetComFd, &tOptions);
    tcflush(NetComFd, TCIOFLUSH);

 
    tOptions.c_cflag &= ~CSIZE;
    tOptions.c_cflag |= CS8;


    tOptions.c_cflag &= ~CSTOPB;

    tOptions.c_cflag &= ~PARENB; 
    tOptions.c_iflag &= ~INPCK;  
    tOptions.c_cc[VTIME] = 10;
    tOptions.c_cc[VMIN] = 0; 

    cfmakeraw(&tOptions); 

    tOptions.c_cflag &= ~CRTSCTS; 
    tOptions.c_cflag |= (CLOCAL | CREAD); 

    tcflush(NetComFd, TCIFLUSH);
    if((tcsetattr(NetComFd, TCSANOW, &tOptions)) != 0)
    {
        perror("tcsetattr m_iSrlPrtFd!");

        return 0;
    }

    return 0;
}


int init_uart(int baurt,char *uartnme)
{
	int fd;
	int ret;
	int count = 10;
	do{
		fd = open(uartnme,O_RDWR | O_NOCTTY | O_NDELAY);
		if(fd < 0){
			printf("init %s error\n",uartnme);
			sleep(1);
			continue;
		}else{
			break;
		}
	}while(count--);
	if(fd < 0)	return -1;
	fcntl(fd, F_SETFD, FD_CLOEXEC);
	fcntl(fd,F_SETFL,0);
	ret = Net_AtPortInit(fd,baurt);
	if(ret !=0){
		printf("init Net_AtPortInit error\n");
		return -1;
	}
	return fd;
}

int ReplaceUnprint(const char *pcData, int iDataLen, char *pcSingleLineMsg, int iBufSize)
{
    int iCount = 0;
    char tmpBuf[128] ={0};
    memcpy(tmpBuf,pcData,iDataLen);
    for (iCount = 0; iCount < iDataLen; iCount++)
    {
        if ((tmpBuf[iCount] == '\r') || (tmpBuf[iCount] == '\n'))
        {
            tmpBuf[iCount]=' ';
            iCount++;
            break;
        }
    }

    if (0 != iCount)
    {
        if (iBufSize < iCount)
        {
            iCount = iBufSize;
        }
        memcpy(pcSingleLineMsg, tmpBuf, iCount);
    }

    return iCount;
}



int SendAtCmd(int iFd, const char *pcATCmd)
{
	int iRet = 0;
	int tmpBufLen = strlen(pcATCmd);
	char tmpBuf[128];
    if(iFd<=0)
		return 0;
	memset(tmpBuf,'\0',sizeof(tmpBuf));
	ReplaceUnprint(pcATCmd,tmpBufLen,tmpBuf,128);

	if (write(iFd, (unsigned char *)pcATCmd, strlen(pcATCmd)) < 0)
	{
		perror("write error");
		close(iFd);
		iFd = -1;
		return -1;
	}
	return iRet;
}

int Proc_AtMsg_CID(const char *pcMsg)
{
	char cid[21] = {0};
	char *pcid = NULL;
	if((pcid = strstr((char*)pcMsg,"+QCCID:"))!=NULL)
	{
		strncpy(cid,pcid+8,20);
		printf("iccid:%s\n",cid);
		return 0;
	}
	return -1;
}

int g_iccid = -1; //0已经获取到了
void GetICCID()
{
    static int modulefd = -1;
    char RecvBuf[1024] = {0};
    if(modulefd < 0)
    {
        modulefd = init_uart(b115200,"/dev/ttyUSB2");
    }
	SendAtCmd(modulefd, "AT+QCCID\r");

    sleep(1);

    int iReadLen = read(modulefd, RecvBuf, sizeof(RecvBuf));
    if(iReadLen < 0)
    {
        perror("modulefd read error");
        close(modulefd);
        modulefd = -1;
        return;
    }
    g_iccid = Proc_AtMsg_CID(RecvBuf);
}

#if 0
void system_upgrade_ck(void)
{
    if (access(IPK_UPGRADE_FILE, F_OK) == 0)
    {
        ems_syslog(LOG_NOTICE, "System will be upgrading now");
        char exec_cmd[256];
        snprintf(exec_cmd,sizeof(exec_cmd),"/bin/opkg install --force-reinstall %s ;sleep 2; rm %s",IPK_UPGRADE_FILE,IPK_UPGRADE_FILE); 
        ems_syslog(LOG_NOTICE, "sh:%s",exec_cmd);
        system(exec_cmd);
        sleep(5);
    }
}
#endif
static void sig_handler(int sig)
{
    ems_syslog(LOG_NOTICE, "========================================================= sig:%d", sig);
    pcs_ctrl_var_t *var = get_pcs_ctrl_var();
    var->rx_sig = 1;
    if (!var->enable_ems) // 没有使能ems直接退出
    {
        exit(0);
    }
}

// static void child_handler(int signum)
// {
//     pid_t pid = 0;
//     do
//     {
//         pid = waitpid(-1, NULL, WNOHANG);
//     } while (pid > 0);
// }

void sig_init(void)
{
    struct sigaction sig_action = {0};
    sig_action.sa_handler = sig_handler;
    sig_action.sa_flags = SA_RESTART;
    sigemptyset(&sig_action.sa_mask);
    sigaction(SIGINT, &sig_action, NULL);
    // sigaction(SIGTERM, &sig_action, NULL);
    // sigaction(SIGABRT, &sig_action, NULL);
    //
    memset(&sig_action, 0, sizeof(sig_action));
    // sig_action.sa_handler = child_handler;
    // sigaction(SIGCHLD, &sig_action, NULL);//回收僵尸进程
    // 设置信号掩码
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    sigprocmask(SIG_UNBLOCK, &mask, NULL);
}

cJSON* append_json_file(cJSON* test_json, const char* json_file_path, const char* prefix) {
    if (!test_json || !json_file_path) {
        ems_syslog(LOG_ERR, "Invalid input parameters");
        return NULL;
    }

    char* json_file_content = read_file_data(json_file_path);
    if (json_file_content == NULL) {
        ems_syslog(LOG_ERR, "Failed to read file data");
        return NULL;
    }

    cJSON* json = cJSON_Parse(json_file_content);
    free(json_file_content);
    json_file_content = NULL;
    
    if (!json) {
        ems_syslog(LOG_ERR, "Invalid JSON format in: %s", json_file_path);
        return NULL;
    }

    if (!cJSON_IsArray(json)) {
        ems_syslog(LOG_ERR, "File is not JSON array: %s", json_file_path);
        cJSON_Delete(json);
        return NULL;
    }

    if (!cJSON_IsArray(test_json)) {
        ems_syslog(LOG_ERR, "Target JSON is not array");
        cJSON_Delete(json);
        return NULL;
    }

    cJSON* item;
    cJSON_ArrayForEach(item, json) {
        // 为每个item添加前缀
        if (prefix && strlen(prefix) > 0) {
            add_prefix_to_name(item, prefix);
        }

        // 将处理后的item添加到test_json
        cJSON* new_item = cJSON_Duplicate(item, 1);
        if (new_item) {
            cJSON_AddItemToArray(test_json, new_item);
        } else {
            ems_syslog(LOG_ERR, "Failed to duplicate JSON item");
        }
    }

    cJSON_Delete(json);
    return test_json;
}

cJSON* add_prefix_to_name(cJSON *json, const char *prefix) {
    if (!json || !prefix) return json;

    // 如果当前节点是对象，检查是否有"name"字段
    if (cJSON_IsObject(json)) {
        cJSON *name = cJSON_GetObjectItem(json, "name");
        if (name && cJSON_IsString(name)) {
            // 为name字段添加前缀
            char new_name[512];
            snprintf(new_name, sizeof(new_name), "%s%s", prefix, name->valuestring);
            cJSON_SetValuestring(name, new_name);
        }
    }

    // 递归处理子节点
    cJSON *child = json->child;
    while (child) {
        add_prefix_to_name(child, prefix);
        child = child->next;
    }

    return json; // 返回修改后的JSON对象
}


bool automatic_cfg_merged(const char* object_file_path) {
    if (!object_file_path) {
        ems_syslog(LOG_ERR, "automatic_cfg_merged: Invalid output file path");
        return false;
    }

    cJSON *obj_json = NULL;
    char *file_content = read_file_data(BASE_AUTOMATIC_JSON_PATH);
    if (file_content) {
        obj_json = cJSON_Parse(file_content);
        free(file_content);
        if (!obj_json || !cJSON_IsArray(obj_json)) {
            if (obj_json) cJSON_Delete(obj_json);
            obj_json = cJSON_CreateArray();
            ems_syslog(LOG_NOTICE, "automatic_cfg_merged: base file not array, create new array");
        } else {
            ems_syslog(LOG_NOTICE, "automatic_cfg_merged: loaded base array from %s", BASE_AUTOMATIC_JSON_PATH);
        }
    } else {
        obj_json = cJSON_CreateArray();
        ems_syslog(LOG_NOTICE, "automatic_cfg_merged: base file not found, create new array");
    }
    if (!obj_json) {
        ems_syslog(LOG_ERR, "automatic_cfg_merged: Failed to create or load base JSON array");
        return false;
    }

    pcs_ctrl_var_t *var = get_pcs_ctrl_var();
    if (!var || !var->lc_list || var->lc_list_len <= 0) {
        ems_syslog(LOG_ERR, "automatic_cfg_merged: Invalid LC list");
        cJSON_Delete(obj_json);
        return false;
    }

    int lc_list_len = var->lc_list_len;
    lc_it *it_arr = var->lc_list;

    for (int i = 0; i < lc_list_len; i++) {
        if (!it_arr[i].no || strlen(it_arr[i].no) == 0) {
            ems_syslog(LOG_ERR, "automatic_cfg_merged: LC no is empty, skip index %d", i);
            continue;
        }

        char file_path[256];
        snprintf(file_path, sizeof(file_path), "/app/config/lc_devs/%s/automatic_control.json", it_arr[i].no);

        if (access(file_path, F_OK) != 0) {
            ems_syslog(LOG_NOTICE, "automatic_cfg_merged: File not found, skip: %s", file_path);
            continue;
        }

        char prefix[64];
        snprintf(prefix, sizeof(prefix), "%s.", it_arr[i].no);

        cJSON *before = obj_json;
        obj_json = append_json_file(obj_json, file_path, prefix);
        if (obj_json == NULL) {
            ems_syslog(LOG_ERR, "automatic_cfg_merged: Failed to append JSON file: %s, skip", file_path);
            obj_json = before;
            continue;
        }
        ems_syslog(LOG_NOTICE, "automatic_cfg_merged: Merged JSON from file: %s", file_path);
    }

    char *merged_json_str = cJSON_Print(obj_json);
    if (!merged_json_str) {
        ems_syslog(LOG_ERR, "automatic_cfg_merged: Failed to print merged JSON");
        cJSON_Delete(obj_json);
        return false;
    }

    bool ret = true;
    if (write_file_data(object_file_path, merged_json_str, strlen(merged_json_str)) != 0) {
        ems_syslog(LOG_ERR, "automatic_cfg_merged: Failed to write merged JSON to file: %s", object_file_path);
        ret = false;
    } else {
        ems_syslog(LOG_NOTICE, "automatic_cfg_merged: Merged JSON written to file: %s", object_file_path);
    }

    free(merged_json_str);
    cJSON_Delete(obj_json);
    return ret;
}

// 策略DOD保护接口 return 0 无保护 1 禁充保护 2 禁放保护
int logic_dod_protect(key_info_t *key_info, int *chadischapro, double value)
{
    //static int chadischapro = 0; // 0正常  1上限（禁充）  2下限（禁放） 
    int need_protect = 0;
    int en_dod = dev_get_dev_tag_int(DEV_NO_EMS, EN_PROTECT_DOD);

    if(en_dod)
    {
        double socmax = key_info->socup;
        double socmin = key_info->soclower;
        if(value >= socmax)
        {
            *chadischapro = 1;   
        }
        else if (value <= socmin){
            *chadischapro = 2;
        }
        
        if (*chadischapro > 0)
        {
            double socmaxerr = dev_get_dev_tag_float(DEV_NO_EMS, EMS_SOCMAXERR);
            double socminerr = dev_get_dev_tag_float(DEV_NO_EMS, EMS_SOCMINERR);
            if ((*chadischapro == 1) && (value < (socmax - socmaxerr)))
            {
                *chadischapro = 0;
            }
            else if ((*chadischapro == 2) && (value > (socmin + socminerr)))
            {
                *chadischapro = 0;
            }

            if (*chadischapro > 0)
            {
                need_protect = *chadischapro;  // 0 无保护 1 禁充保护 2 禁放保护
            }
            else{
                need_protect = 0;
            }
        } 
        else{
            need_protect = 0;
        } 
    }
/*
    if (need_protect != dev_get_dev_tag_int(DEV_NO_EMS, SOC_LIMIT_ALARM)) // 逻辑DOD保护告警
    {
        dev_set_dev_tag_int(DEV_NO_EMS, SOC_LIMIT_ALARM, need_protect);
    }
*/
    return need_protect;
}
