#include "event_process.h"
#include "bmser_log.h"
#include "bmser_ipc.h"
#include "bmser_cjson.h"
#include "bmser_dev.h"
#include "dtc_export_cfg_parse.h"
#include "cJSON.h"
#include "sqlite_api.h"
#include "bmser_project_para.h"
#include "wave_record_queue.h"
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <stdbool.h>

#include <string.h>

#define CREATE_ALARM_TABLE_SQL               \
"CREATE TABLE IF NOT EXISTS [alarm](                             \
  [id] integer PRIMARY KEY AUTOINCREMENT NOT NULL, \
  [sn] text NOT NULL,                              \
  [station_guid] text NOT NULL DEFAULT '',         \
  [cabin_id] integer NOT NULL DEFAULT 1,\
  [system_type] text NOT NULL DEFAULT '', \
  [device_type] text NOT NULL DEFAULT '', \
  [device_name] text NOT NULL DEFAULT '', \
  [main_id] integer, \
  [sub_id] integer, \
  [event_id] integer, \
  [event_desc] text NOT NULL DEFAULT '', \
  [event_desc_en] text NOT NULL DEFAULT '', \
  [details] text NOT NULL DEFAULT '', \
  [details_en] text NOT NULL DEFAULT '', \
  [status] integer, \
  [level] integer, \
  [settime] integer NOT NULL DEFAULT 0,\
  [clrtime] integer NOT NULL DEFAULT 0,\
  [created_at] DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \
  [comfirmed_at] DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \
  [operate] text NOT NULL DEFAULT '', \
  [fun] text NOT NULL DEFAULT '', \
  [error_no] integer NOT NULL DEFAULT 0, \
  [handler_user] text NOT NULL DEFAULT '', \
  [handler] text NOT NULL DEFAULT '', \
  [handler_time] integer NOT NULL DEFAULT 0, \
  [updated_at] DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP);"

#define INSERT_ALARM_SQL \
"INSERT INTO alarm ( \
  sn, station_guid, cabin_id, system_type, device_type, device_name, main_id,\
  sub_id, event_id, event_desc, event_desc_en, details, details_en, status, level, settime, clrtime, \
  created_at,   comfirmed_at, operate, fun, error_no, handler_user, handler, handler_time, updated_at)\
  VALUES ( \
  ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? \
);"

#define UPDATE_ALARM_SQL \
"update  alarm set clrtime = ?, handler_time = ?, comfirmed_at = ?, updated_at = ? WHERE id = (\
 select id from alarm \
 where main_id = ? AND sub_id = ? AND event_id = ? AND level = ? AND clrtime = 0 ORDER BY id DESC LIMIT 1\
);"

#define CREATE_INDEX_IDX_ALARM_MAIN_SUB_EVENT \
"CREATE INDEX IF NOT EXISTS idx_alarm_main_sub_event ON alarm(main_id, sub_id, event_desc);"

#define CREATE_INDEX_IDX_ALARM_CLRTIME \
"CREATE INDEX IF NOT EXISTS idx_alarm_clrtime ON alarm (clrtime);"

#define CREATE_INDEX_IDX_ALARM_SETTIME \
"CREATE INDEX IF NOT EXISTS idx_alarm_settime ON alarm (settime DESC);"

sqlite3 *g_eventdb;
sqlite3_stmt *g_eventstmt;
sqlite3_stmt *g_handlerstmt;
int g_language = 0;
typedef struct {
	pthread_mutex_t mutex;
	bool message_received;
}event_process_info;

event_process_info g_event_process_info = {
	.mutex = PTHREAD_MUTEX_INITIALIZER,
	.message_received = false,
};

static int rows_callback(void *data, int argc, char **argv, char **azColName){
    int *count = (int*)data;
    *count = atoi(argv[0]);
    return 0;
}

static int eventprocess_space_cleaning()
{
	char sql[512] = {0};
	int rc = 0, counts = 0;
	snprintf(sql,512,"SELECT count(*) FROM alarm");
    //获取存在相同告警
    rc = sqlite3_exec(g_eventdb, sql, rows_callback, &counts, NULL);
    if (rc != SQLITE_OK) {
        dy_syslog(LOG_ERR, "select alarm:%s\n",sqlite3_errmsg(g_eventdb));
        return -1;
    }
	//超过20000条清除时，进行一次清除操作，只保留最新的10000条
	if (counts > 20000){
		snprintf(sql,512,"DELETE FROM alarm WHERE id NOT IN (SELECT id FROM alarm ORDER BY id DESC LIMIT 10000)");
		rc = sqlite3_exec(g_eventdb, sql, NULL, NULL, NULL);
		if (rc != SQLITE_OK) {
			dy_syslog(LOG_ERR, "delete error:%s\n",sqlite3_errmsg(g_eventdb));
			return -1;
		}
		rc = sqlite3_exec(g_eventdb, "vacuum;", NULL, NULL, NULL);
		if (rc != SQLITE_OK) {
			dy_syslog(LOG_ERR, "vacuum error:%s\n",sqlite3_errmsg(g_eventdb));
			return -1;
		}
	}
	
	return 0;
}

static int eventprocess_dataInsert(struct event_table_info * info)
{
	int ret = 0;
	sqlite3_stmt* stmt = g_eventstmt;
	
	int rc = 0, counts = 0;
	char sql[512] = {0};
	//查重处理,已经触发的告警就不要再进行记录了
	snprintf(sql,512,"SELECT count(*) FROM alarm where clrtime == 0 AND main_id = %d AND sub_id = %d AND event_id = %d AND level = %d",
		info->main_id,info->sub_id,info->event_id,info->level);
    //获取存在相同告警
    sqlite3_exec(g_eventdb, sql, rows_callback, &counts, NULL);
    if (counts > 0) {
        dy_syslog(LOG_ERR, "exist same record:%s\n",sqlite3_errmsg(g_eventdb));
        return 1;
    }
	sqlite3_bind_text(stmt, 1, info->sn, -1, SQLITE_TRANSIENT);
	sqlite3_bind_text(stmt, 2, info->station_guid, -1, SQLITE_TRANSIENT);
	sqlite3_bind_int(stmt, 3, info->cabin_id);
	sqlite3_bind_text(stmt, 4, info->system_type, -1, SQLITE_TRANSIENT);
	sqlite3_bind_text(stmt, 5, info->device_type, -1, SQLITE_TRANSIENT);
	sqlite3_bind_text(stmt, 6, info->device_name, -1, SQLITE_TRANSIENT);
	sqlite3_bind_int(stmt, 7, info->main_id);
	sqlite3_bind_int(stmt, 8, info->sub_id);
	sqlite3_bind_int(stmt, 9, info->event_id);
	sqlite3_bind_text(stmt, 10, info->event_name, -1, SQLITE_TRANSIENT);
	sqlite3_bind_text(stmt, 11, info->event_name_en, -1, SQLITE_TRANSIENT);
	sqlite3_bind_text(stmt, 12, info->details, -1, SQLITE_TRANSIENT);
	sqlite3_bind_text(stmt, 13, info->details_en, -1, SQLITE_TRANSIENT);
	sqlite3_bind_int(stmt, 14, info->status);
	sqlite3_bind_int(stmt, 15, info->level);
	sqlite3_bind_int(stmt, 16, info->settime);
	sqlite3_bind_int(stmt, 17, info->clrtime);
	sqlite3_bind_text(stmt, 18, info->created_at, -1, SQLITE_STATIC);
	sqlite3_bind_text(stmt, 19, info->comfirmed_at, -1, SQLITE_STATIC);
	sqlite3_bind_text(stmt, 20, info->operate, -1, SQLITE_TRANSIENT);
	sqlite3_bind_text(stmt, 21, info->fun, -1, SQLITE_TRANSIENT);
	sqlite3_bind_int(stmt, 22, info->error_no); 
	sqlite3_bind_text(stmt, 23, info->handler_user, -1, SQLITE_TRANSIENT);
	sqlite3_bind_text(stmt, 24, info->handler, -1, SQLITE_TRANSIENT);
	sqlite3_bind_int(stmt, 25, info->handler_time);
	sqlite3_bind_text(stmt, 26, info->updated_at, -1, SQLITE_STATIC);
    if (sqlite3_step(stmt) != SQLITE_DONE) {
        ret = -1;
    }
	sqlite3_reset(stmt);

	return ret;
}

static int eventprocess_update_handler_time(struct event_table_info * info)
{
	int ret = 0;
	sqlite3_stmt* stmt = g_handlerstmt;

	sqlite3_bind_int(stmt, 1, info->clrtime);
    sqlite3_bind_int(stmt, 2, info->handler_time);
	sqlite3_bind_text(stmt, 3, info->comfirmed_at, -1, SQLITE_STATIC);
	sqlite3_bind_text(stmt, 4, info->updated_at, -1, SQLITE_STATIC);
	sqlite3_bind_int(stmt, 5, info->main_id);
	sqlite3_bind_int(stmt, 6, info->sub_id);
	sqlite3_bind_int(stmt, 7, info->event_id);
	sqlite3_bind_int(stmt, 8, info->level);

    if (sqlite3_step(stmt) != SQLITE_DONE) {
        ret = -1;
    }
	sqlite3_reset(stmt);

	return ret;
}

static int eventprocess_translation(int event_id, const char *key_name, char *translation, int size)
{
	int i = 0, j = 0;
	char tmp[128] = {0};
	SubDtcInfoList_Stru* infolist = getSubDtcInfoListBySubDID(event_id);
	
	if(infolist == NULL) { return -1; }
	getDtcNameBySubDID(event_id,tmp);
	if(0 == strcmp(key_name,tmp))
	{
		strncpy(translation, tmp, MIN(size - 1, (int)strlen(tmp)));
		translation[size - 1] = '\0';
		return 0;
	}
	
	for(i = 0; i < DTC_VRLIST_MAX_COUNT; i++)
	{
		if(0 == strcmp(infolist->ValueInfoList[i].EnTitle, key_name))
		{
			strncpy(translation, infolist->ValueInfoList[i].ZhTitle, MIN(size - 1, DTC_TEXT_MAX_LENGTH));
			translation[size - 1] = '\0';
			return 0;
		}
		if(0 == strcmp(infolist->ReasonInfoList[i].EnTitle, key_name))
		{
			strncpy(translation, infolist->ReasonInfoList[i].ZhTitle, MIN(size - 1, DTC_TEXT_MAX_LENGTH));
			translation[size - 1] = '\0';
			return 0;
		}
		for(j = 0; j < DTC_MEANLIST_MAX_COUNT; j++)
		{
			if(0 == strcmp(infolist->ValueInfoList[i].MeaningList[j].EnTitle, key_name))
			{
				strncpy(translation, infolist->ValueInfoList[i].MeaningList[j].ZhTitle, MIN(size - 1, DTC_TEXT_MAX_LENGTH));
				translation[size - 1] = '\0';
				return 0;
			}
			if(0 == strcmp(infolist->ReasonInfoList[i].MeaningList[j].EnTitle, key_name))
			{
				strncpy(translation, infolist->ReasonInfoList[i].MeaningList[j].ZhTitle, MIN(size - 1, DTC_TEXT_MAX_LENGTH));
				translation[size - 1] = '\0';
				return 0;
			}
		}
	}

	return -1;
}


/**
 * @brief       尝试从JSON项中获取string。
 * @param[in]   jsonItem - JSON项。
 * @param[in]   key - 要获取的值的键。
 * @param[out]  output - 字符数组，用于存放获取到的字符串。
 * @param[in]   maxLen - 输出数组的最大长度。
 * @return      bool
 * @retval      成功为true，失败为false。
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2024-02-18           JHC        创建初始版本          \n
*/
bool eventprocess_get_json_string_value(void* jsonItem, const char* key, char* output, int maxLen) 
{
    JsonValue result;
    json_value_get_by_json(jsonItem, key, &result);
    
    // 检查返回的类型是否为期望的字符串类型。
    if (result.type == JSON_VALUE_STRING) {
        // 使用strncpy确保不会超出数组界限，并保留一个字节用于末尾的null字符。
        strncpy(output, result.stringVal, maxLen - 1);
        // 确保字符串以null字符结尾。
        output[maxLen - 1] = '\0';
        return true;
    }
    
    // 如果获取失败或类型不匹配，返回false。
    return false;
}

/**
 * @brief       尝试从JSON项中获取int。
 * @param[in]   jsonItem - JSON项。
 * @param[in]   key - 要获取的值的键。
 * @param[out]  output - 数值指针，用于存放获取到的数值。
 * @param[in]   maxLen - 输出数组的最大长度。
 * @return      bool
 * @retval      成功为true，失败为false。
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2024-02-18           JHC        创建初始版本          \n
*/
bool eventprocess_get_json_int_value(void* jsonItem, const char* key, int* output) 
{
    JsonValue result;
    json_value_get_by_json(jsonItem, key, &result);
    
    // 检查返回的类型是否为期望的字符串类型。
    if (result.type == JSON_VALUE_NUMBER) {
		*output = result.int64Val;
        return true;
    }
    
    // 如果获取失败或类型不匹配，返回false。
    return false;
}

typedef enum
{
	DTC_FORMAT_TYPE_INT,
	DTC_FORMAT_TYPE_FLOAT,
	DTC_FORMAT_TYPE_STRING,
	DTC_FORMAT_TYPE_BOOL,
	DTC_FORMAT_TYPE_UNKNOWN
}DTC_FORMAT_TYPE;
static DTC_FORMAT_TYPE check_dtc_info_value_format(char *format, int len)
{
	if(strstr(format, "0.0")){
		return DTC_FORMAT_TYPE_FLOAT;
	}
	else if(strstr(format, "0") == 0){
		return DTC_FORMAT_TYPE_INT;
	}
	else{
		return DTC_FORMAT_TYPE_INT;
	}
}

static int pack_dtc_value_to_string(char *format, int len, double value_double, char *output)
{
	if(DTC_FORMAT_TYPE_FLOAT == check_dtc_info_value_format(format,len)){
		snprintf(output,DETAIL_MAX_LEN, "%.1f", value_double);
	}
	else{
		snprintf(output,DETAIL_MAX_LEN, "%d", (int)value_double);
	}
	return 0;
}

static int eventprocess_details(void* jsonItem, struct event_table_info *info)
{
	int arrayLength = 0, i = 0, value = 0, reason = 0;
	char jsonpath1[128] = {0}, jsonpath2[128] = {0}, jsonpath3[128] = {0}, jsonpath4[128] = {0}, jsonpath5[128] = {0};
	SubDtcInfoList_Stru* sub_dtc_info = getSubDtcInfoListBySubDID(info->event_id);
	if(info == NULL || sub_dtc_info == NULL){
		return -1;
	}

	arrayLength = json_get_array_length_by_json(jsonItem,"issueDetails");

	//先填充对内故障名称
	strncat(info->details,sub_dtc_info->subDtcName,strlen(sub_dtc_info->subDtcName));
	strncat(info->details_en,sub_dtc_info->subDtcName_en,strlen(sub_dtc_info->subDtcName_en));
	strncat(info->details_en,";",2);
	strncat(info->details,";",2);
	if(arrayLength > 0){
		for(i=0; i<arrayLength; i++ ){
			char value_tmp[16] = {0}, reason_tmp[16] = {0};
			char position_str[32] = {0};
			//主要针对电池 温度这些采集点的位置定位
			int pack_id = 0, single_id = 0;
			snprintf(jsonpath1, sizeof(jsonpath1), "issueDetails[%d].key", i);
			snprintf(jsonpath2, sizeof(jsonpath2), "issueDetails[%d].value", i);
			snprintf(jsonpath3, sizeof(jsonpath3), "issueDetails[%d].reason", i);
			snprintf(jsonpath4, sizeof(jsonpath4), "issueDetails[%d].packId", i);
			snprintf(jsonpath5, sizeof(jsonpath5), "issueDetails[%d].singleId", i);
			
			/*如果存在采集点定位,则补充到详细信息字符串*/
			if(eventprocess_get_json_int_value(jsonItem, jsonpath4, &pack_id) && 
				eventprocess_get_json_int_value(jsonItem, jsonpath5, &single_id)){
			    snprintf(position_str, sizeof(position_str), "%d-%d;", pack_id,single_id);
				strncat(info->details_en,position_str,strlen(position_str));
				strncat(info->details,position_str,strlen(position_str));
			}
			/*中英文字段都需要解析记录,先做故障值的解析*/
			/*例:tile:1,reason:1;*/
			if(strcmp(sub_dtc_info->ValueInfoList[i].EnTitle, "NULL") != 0 && 
				strcmp(sub_dtc_info->ValueInfoList[i].ZhTitle ,"NULL") != 0 && 
				sub_dtc_info->value_info_valid_length > 0 && 
				i < sub_dtc_info->value_info_valid_length)
			{
				eventprocess_get_json_int_value(jsonItem, jsonpath2, &value);
				snprintf(value_tmp,DETAIL_MAX_LEN, "%d", value);
				strncat(info->details_en,sub_dtc_info->ValueInfoList[i].EnTitle,strlen(sub_dtc_info->ValueInfoList[i].EnTitle));
				strncat(info->details,sub_dtc_info->ValueInfoList[i].ZhTitle,strlen(sub_dtc_info->ValueInfoList[i].ZhTitle));
				strncat(info->details_en,":",2);
				strncat(info->details,":",2);
				if(sub_dtc_info->ValueInfoList[i].DataType == 0){
					if(sub_dtc_info->ValueInfoList[i].HexFlag) {
						/*hex格式暂不做数值转换, 忽略单位*/
						snprintf(value_tmp, DETAIL_MAX_LEN, "0x%x", value);
						strncat(info->details_en,value_tmp,strlen(value_tmp));
						strncat(info->details,value_tmp,strlen(value_tmp));
					} else {
						double value_double = 0;
						value_double = (double)value * sub_dtc_info->ValueInfoList[i].Factor + sub_dtc_info->ValueInfoList[i].Offset;
						pack_dtc_value_to_string(sub_dtc_info->ValueInfoList[i].ValueFormat,DTC_FORMAT_MAX_LENGTH,value_double,value_tmp);
						strncat(info->details_en,value_tmp,strlen(value_tmp));
						strncat(info->details,value_tmp,strlen(value_tmp));
						strncat(info->details_en,sub_dtc_info->ValueInfoList[i].Unit,strlen(sub_dtc_info->ValueInfoList[i].Unit));
						strncat(info->details,sub_dtc_info->ValueInfoList[i].Unit,strlen(sub_dtc_info->ValueInfoList[i].Unit));
					}
				}
				else if(sub_dtc_info->ValueInfoList[i].DataType == 1 && 
						value < DTC_MEANLIST_MAX_COUNT && value >= 0){
					int list_index = value;
					strncat(info->details_en,
							sub_dtc_info->ValueInfoList[i].MeaningList[list_index].EnTitle,
							strlen(sub_dtc_info->ValueInfoList[i].MeaningList[list_index].EnTitle));
					strncat(info->details,
							sub_dtc_info->ValueInfoList[i].MeaningList[list_index].ZhTitle,
							strlen(sub_dtc_info->ValueInfoList[i].MeaningList[list_index].ZhTitle));
				}
				else if(sub_dtc_info->ValueInfoList[i].DataType == 2){
					for(uint32_t j = 0; j < DTC_MEANLIST_MAX_COUNT; j++)
					{
						if(value & (1<<j)){
							strncat(info->details_en,
									sub_dtc_info->ValueInfoList[i].MeaningList[j].EnTitle,
									strlen(sub_dtc_info->ValueInfoList[i].MeaningList[j].EnTitle));
							strncat(info->details,
									sub_dtc_info->ValueInfoList[i].MeaningList[j].ZhTitle,
									strlen(sub_dtc_info->ValueInfoList[i].MeaningList[j].ZhTitle));	
							strncat(info->details_en,"|",2);
							strncat(info->details,"|",2);
						}
					}
				}
				strncat(info->details_en,";",2);
				strncat(info->details,";",2);
			}
			/*再解析reason字段*/
			if(strcmp(sub_dtc_info->ReasonInfoList[i].EnTitle, "NULL") != 0 && 
				strcmp(sub_dtc_info->ReasonInfoList[i].ZhTitle, "NULL") != 0 &&
				sub_dtc_info->reason_info_valid_length > 0 && 
				i < sub_dtc_info->reason_info_valid_length)
			{
				eventprocess_get_json_int_value(jsonItem, jsonpath3, &value);
				strncat(info->details_en,sub_dtc_info->ReasonInfoList[i].EnTitle,strlen(sub_dtc_info->ReasonInfoList[i].EnTitle));
				strncat(info->details,sub_dtc_info->ReasonInfoList[i].ZhTitle,strlen(sub_dtc_info->ReasonInfoList[i].ZhTitle));
				strncat(info->details_en,":",2);
				strncat(info->details,":",2);
				/*根据reason类型做不同的处理,0：数值类型，1：枚举类型，2：bit位告警类型*/
				if(sub_dtc_info->ReasonInfoList[i].DataType == 0){
					if(sub_dtc_info->ReasonInfoList[i].HexFlag) {
						/*hex格式暂不做数值转换, 忽略单位*/
						snprintf(reason_tmp, DETAIL_MAX_LEN, "0x%x", value);
						strncat(info->details_en,reason_tmp,strlen(reason_tmp));
						strncat(info->details,reason_tmp,strlen(reason_tmp));
					} else {
						double value_double = 0;
						value_double = (double)value * sub_dtc_info->ReasonInfoList[i].Factor + sub_dtc_info->ReasonInfoList[i].Offset;
						pack_dtc_value_to_string(sub_dtc_info->ReasonInfoList[i].ValueFormat,DTC_FORMAT_MAX_LENGTH,value_double,reason_tmp);
						strncat(info->details_en,reason_tmp,strlen(reason_tmp));
						strncat(info->details,reason_tmp,strlen(reason_tmp));
						strncat(info->details_en,sub_dtc_info->ReasonInfoList[i].Unit,strlen(sub_dtc_info->ReasonInfoList[i].Unit));
						strncat(info->details,sub_dtc_info->ReasonInfoList[i].Unit,strlen(sub_dtc_info->ReasonInfoList[i].Unit));
					}
				}
				else if(sub_dtc_info->ReasonInfoList[i].DataType == 1 && 
						value < DTC_MEANLIST_MAX_COUNT && value >= 0){
					int list_index = value;
					strncat(info->details_en,
							sub_dtc_info->ReasonInfoList[i].MeaningList[list_index].EnTitle,
							strlen(sub_dtc_info->ReasonInfoList[i].MeaningList[list_index].EnTitle));
					strncat(info->details,
							sub_dtc_info->ReasonInfoList[i].MeaningList[list_index].ZhTitle,
							strlen(sub_dtc_info->ReasonInfoList[i].MeaningList[list_index].ZhTitle));
				}
				else if(sub_dtc_info->ReasonInfoList[i].DataType == 2){
					for(uint32_t j = 0; j < DTC_MEANLIST_MAX_COUNT; j++)
					{
						if(value & (1<<j)){
							strncat(info->details_en,
									sub_dtc_info->ReasonInfoList[i].MeaningList[j].EnTitle,
									strlen(sub_dtc_info->ReasonInfoList[i].MeaningList[j].EnTitle));
							strncat(info->details,
									sub_dtc_info->ReasonInfoList[i].MeaningList[j].ZhTitle,
									strlen(sub_dtc_info->ReasonInfoList[i].MeaningList[j].ZhTitle));	
							strncat(info->details_en,"|",2);
							strncat(info->details,"|",2);
						}
					}
				}
				strncat(info->details_en,";",2);
				strncat(info->details,";",2);
			}
		}
	}

	
	
	return 0;
}

static int eventprocess_oprate(void* jsonItem, struct event_table_info *info)
{
	int arrayLength = 0, i = 0;
	char jsonpath1[128] = {0}, jsonpath2[128] = {0}, jsonpath3[128] = {0};
	char str[128] = {0};
	if(info == NULL){
		return -1;
	}
	arrayLength = json_get_array_length_by_json(jsonItem,"extra");
	if(arrayLength > 0){
		int addr= 0, value = 0;
		memset(info->operate,0,sizeof(info->operate));
		for(i=0; i<arrayLength; i++ ){
			//操作信息拼接
			snprintf(jsonpath1, sizeof(jsonpath1), "extra[%d].addr", i);
			snprintf(jsonpath2, sizeof(jsonpath2), "extra[%d].value", i);
			snprintf(jsonpath3, sizeof(jsonpath3), "extra[%d].operate", i);
			if(eventprocess_get_json_int_value(jsonItem,jsonpath1,&addr) &&\
				eventprocess_get_json_int_value(jsonItem,jsonpath2,&value) &&\
				eventprocess_get_json_string_value(jsonItem,jsonpath3,str,sizeof(str))){
				char tmpstr[128] = {0};
				snprintf(tmpstr,sizeof(tmpstr),"%s,%d,%d;",str,value,addr);
				strncat(info->operate,tmpstr,strlen(tmpstr));
			}
		}
	}

	return 0;
}


// 获取当天的开始和结束时间戳
static void get_day_start_end_timestamp(time_t *start, time_t *end) {
    time_t now = time(NULL);
    struct tm *tm_start = localtime(&now);
    tm_start->tm_hour = 0;
    tm_start->tm_min = 0;
    tm_start->tm_sec = 0;
    *start = mktime(tm_start);

    struct tm *tm_end = localtime(&now);
    tm_end->tm_hour = 23;
    tm_end->tm_min = 59;
    tm_end->tm_sec = 59 ;
	*end = mktime(tm_end);
}

// 检查文件是否存在，并创建CSV文件（包含BOM和标题）
static bool ensure_csv_file(const char *filepath) {
    FILE *file;
    if ((file = fopen(filepath, "r"))) {
        // 文件已存在，不需要进一步操作
        fclose(file);
		return true;
    } else {
        // 文件不存在，创建文件并添加UTF-8 BOM
        file = fopen(filepath, "w");
        if (file != NULL) {
            fprintf(file, "\xEF\xBB\xBF"); // 写入UTF-8 BOM
			fprintf(file,"Trigger time,Recovery time,Alarm CN,Alarm EN,Main ID,Sub ID,Alarm level,Extra\n");
            fclose(file);
        }
		return false;
    }
}

// 使用system命令调用sqlite3命令行工具导出数据
static void export_data_within_time_range(const char *db_path, const char *csv_file_path, time_t start, time_t end) {
    char command[2048];
    snprintf(command, sizeof(command),
             "sqlite3 -csv %s \"SELECT strftime('%%Y%%m%%d %%H:%%M:%%S', settime, 'unixepoch', 'localtime'), "
             "CASE WHEN clrtime = 0 THEN '' ELSE strftime('%%Y%%m%%d %%H:%%M:%%S', clrtime, 'unixepoch', 'localtime') END, "
             "event_desc, event_desc_en, alarm.main_id, alarm.sub_id, "
             "CASE WHEN alarm.level = 3 THEN '1' WHEN alarm.level = 1 THEN '3' ELSE alarm.level END, details FROM alarm "
             "WHERE (( alarm.settime >= %ld AND alarm.settime <= %ld ) "
             "OR alarm.clrtime = 0 ) "
			 "GROUP BY alarm.settime, alarm.sub_id, alarm.level, alarm.event_desc;\" >> %s",
             db_path, start, end, csv_file_path);

	//printf("1 export sql,end=%ld:%s\r\n",end,command);
    system(command);
}

// 使用system命令调用sqlite3命令行工具导出基于特定时间点的数据
static void export_data_at_settime_timestamp(const char *db_path, const char *csv_file_path, time_t export_timestamp) {
    char command[2048];
    snprintf(command, sizeof(command),
             "sqlite3 -csv %s \"SELECT strftime('%%Y%%m%%d %%H:%%M:%%S', settime, 'unixepoch', 'localtime'), "
             "CASE WHEN clrtime = 0 THEN '' ELSE strftime('%%Y%%m%%d %%H:%%M:%%S', clrtime, 'unixepoch', 'localtime') END, "
             "event_desc, event_desc_en, alarm.main_id, alarm.sub_id, "
			 "CASE WHEN alarm.level = 3 THEN '1' WHEN alarm.level = 1 THEN '3' ELSE alarm.level END, details FROM alarm "
             "WHERE alarm.settime = %ld "
             "GROUP BY alarm.settime, alarm.sub_id, alarm.level, alarm.event_desc;\" >> %s",
             db_path, export_timestamp, csv_file_path);
	//printf("2 export sql:%s\r\n",command);
    system(command);
}

// 使用system命令调用sqlite3命令行工具导出基于特定时间点的数据
static void export_data_at_clrtime_timestamp(const char *db_path, const char *csv_file_path, time_t export_timestamp) {
    char command[2048];
    snprintf(command, sizeof(command),
             "sqlite3 -csv %s \"SELECT strftime('%%Y%%m%%d %%H:%%M:%%S', settime, 'unixepoch', 'localtime'), "
             "CASE WHEN clrtime = 0 THEN '' ELSE strftime('%%Y%%m%%d %%H:%%M:%%S', clrtime, 'unixepoch', 'localtime') END, "
             "event_desc, event_desc_en, alarm.main_id, alarm.sub_id, "
             "CASE WHEN alarm.level = 3 THEN '1' WHEN alarm.level = 1 THEN '3' ELSE alarm.level END, details FROM alarm "
             "WHERE alarm.clrtime = %ld "
             "GROUP BY alarm.settime, alarm.sub_id, alarm.level, alarm.event_desc;\" >> %s",
             db_path, export_timestamp, csv_file_path);
	//printf("3 export sql:%s\r\n",command);	
    system(command);
}

static void get_alarm_csv_file_path(char *csv_file_path ,int len)
{
	int containerNumber = bmser_jsonGetContainerNum();
	struct tm *tm;
	time_t start, end;
	sqlResult_t result = {0};

	get_day_start_end_timestamp(&start,&end);
    tm = localtime(&start);
    snprintf(csv_file_path, len, "/bmsLog/tar/bak/%d_bank0alarmInfoDB_%d-%02d-%02d.csv",containerNumber,tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
}

static int32_t eventprocess_export_alarm_csv()
{
	time_t start, end;
	char csv_file_path[256] = {0}, cmd[512] = {0};
	get_day_start_end_timestamp(&start,&end);
	get_alarm_csv_file_path(csv_file_path,256);
	snprintf(cmd,512,"rm -rf %s",csv_file_path);
	system(cmd);
	ensure_csv_file(csv_file_path);
	export_data_within_time_range(EVENT_DB_FILE_PATH,csv_file_path,start,end);

	return 0;
}

int32_t eventprocess_set_language(struct ipc_message *m)
{
    if (NULL == m) {
        return -1;
    }
    int32_t language = 0;
    void *jsonItem = get_jsonItem_by_msgContent((char *)m->p.buf);
	if(jsonItem == NULL){ 
		return -1; 
	}
    if(eventprocess_get_json_int_value(jsonItem,"language",&language))
	{
		g_language = language;
	}
	free_jsonItem(jsonItem);
	return 0;
}

void update_last_message_time() {
    pthread_mutex_lock(&g_event_process_info.mutex);
    g_event_process_info.message_received = true;         // 标记接收到消息
    pthread_mutex_unlock(&g_event_process_info.mutex);
}

/**
 * @brief       告警事件消息处理
 * @param[in]   struct ipc_message *msg
 * @return      int
 * @retval      0:正常  !0:错误
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2024-02-18           JHC        创建初始版本          \n
 * 2025-01-02           JHC        新增字段“eventName_zh”适配 \n
*/
int eventprocess_messaging(struct ipc_message *msg)
{
	if(msg == NULL){ 
		return -1; 
	}
	struct event_table_info info = {0};
	JsonValue result1,result2;
	void *jsonItem = get_jsonItem_by_msgContent((char *)msg->p.buf);
	char export_file_path[256] = {0};
	if(jsonItem == NULL){ 
		return -1; 
	}
	/*--------------------------------------necessary----------------------------------------*/
	bmser_dev_get_bankid_from_topic(msg->t.name,(uint16_t*)&info.main_id,(uint16_t*)&info.sub_id);
	bmser_dev_get_board_sn_ex(info.sn,SN_MAX_LEN);
	get_alarm_csv_file_path(export_file_path,256);
	info.cabin_id = bmser_jsonGetContainerNum();
	
	int unix_time = 0;
	if(eventprocess_get_json_int_value(jsonItem,"unixTime",&unix_time) &&\
	eventprocess_get_json_int_value(jsonItem,"status",&info.status)){
		time_t unix_time_convertes = unix_time;
		struct tm *tm = localtime((time_t*)&unix_time_convertes);
		if(info.status == 1){
			info.settime = unix_time;
			info.clrtime = 0;
			info.handler_time = 0;
			strftime(info.created_at, sizeof(info.created_at), "%Y-%m-%d %H:%M:%S", tm);
			strftime(info.updated_at, sizeof(info.updated_at), "%Y-%m-%d %H:%M:%S", tm);
			strftime(info.comfirmed_at, sizeof(info.comfirmed_at), "%Y-%m-%d %H:%M:%S", tm);
		}
		else{
			info.handler_time = unix_time;
			info.clrtime = unix_time;
			info.settime = 0;
			strftime(info.comfirmed_at, sizeof(info.comfirmed_at), "%Y-%m-%d %H:%M:%S", tm);
			strftime(info.updated_at, sizeof(info.updated_at), "%Y-%m-%d %H:%M:%S", tm);
		}
	}else{ goto err;}
	
	if(!eventprocess_get_json_int_value(jsonItem,"eventID",&info.event_id)){
		goto err;
	}
	if(!eventprocess_get_json_int_value(jsonItem,"eventLevel",&info.level)){
		goto err;
	}
	//新增字段“eventName_zh”适配
	if( 0 != getDtcNameBySubDID(info.event_id,info.event_name)){
		eventprocess_get_json_string_value(jsonItem,"eventName_zh", info.event_name, sizeof(info.event_name));
	}
	if( 0 != getDtcNameEnBySubDID(info.event_id,info.event_name_en)){
		eventprocess_get_json_string_value(jsonItem,"eventName", info.event_name_en, sizeof(info.event_name_en));
	}

	/*--------------------------------------optional----------------------------------------*/
	eventprocess_get_json_string_value(jsonItem,"systemType",info.system_type,sizeof(info.system_type));
	eventprocess_get_json_string_value(jsonItem,"deviceType",info.device_type,sizeof(info.device_type));
	eventprocess_get_json_string_value(jsonItem,"deviceName",info.device_name,sizeof(info.device_name));

	eventprocess_details(jsonItem,&info);
	eventprocess_oprate(jsonItem,&info);

	wave_record_get_alarm_info_call_back(&info);
	//插入到数据库
	ensure_csv_file(export_file_path);
	if(info.clrtime != 0){
		//如果是报警恢复的则更新到对应的告警行
		if( 0 == eventprocess_update_handler_time(&info))
		{
			//export_data_at_clrtime_timestamp(EVENT_DB_FILE_PATH,export_file_path,(time_t)unix_time);
			update_last_message_time();
		}
	}
	else{
		//告警插入前做一次空间清理
		eventprocess_space_cleaning();
		if(0 == eventprocess_dataInsert(&info))
		{
			//export_data_at_settime_timestamp(EVENT_DB_FILE_PATH,export_file_path,(time_t)unix_time);
			update_last_message_time();
		}
	}

	free_jsonItem(jsonItem);
	return 0;
err:
	free_jsonItem(jsonItem);
	return -1;
}

static int clean_unrecovered_alarm()
{
	int rc = 0;
    rc = sqlite3_exec(g_eventdb, "delete from alarm where clrtime = 0;", NULL, NULL, NULL);
    if (rc != SQLITE_OK) {
        dy_syslog(LOG_ERR, "delete from alarm:%s\n",sqlite3_errmsg(g_eventdb));
        return -1;
    }
	rc = sqlite3_exec(g_eventdb, "vacuum;", NULL, NULL, NULL);
    if (rc != SQLITE_OK) {
        dy_syslog(LOG_ERR, "vacuum error:%s\n",sqlite3_errmsg(g_eventdb));
        return -1;
    }

	return 0;
}

void *export_alarm_csv_thread(void *arg) {
    while (1) {
        
        // 检查是否需要导出
        time_t current_time = time(NULL);
        if (g_event_process_info.message_received) {  
            eventprocess_export_alarm_csv();  // 执行导出操作
        }
        pthread_mutex_lock(&g_event_process_info.mutex);
        g_event_process_info.message_received = false;  // 重置标志
        pthread_mutex_unlock(&g_event_process_info.mutex);

		sleep(1);
    }
    return NULL;
}

/**
 * @brief       事件处理初始化
 * @return      int
 * @retval      0:正常  !0:错误
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2024-02-18           JHC        创建初始版本          \n
*/
int eventprocess_init()
{
    int ret = 0;
	sqlResult_t result = {0};

    ret = sqlite3_open_v2(EVENT_DB_FILE_PATH, &g_eventdb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
    if (ret != SQLITE_OK) {
        dy_syslog(LOG_ERR, "Cannot open or create database:%s\n",sqlite3_errmsg(g_eventdb));
        goto err;
    }
	ret = sqlite3_exec(g_eventdb, "PRAGMA journal_mode=WAL;", 0, 0, 0);
    if (ret != SQLITE_OK) {
        dy_syslog(LOG_ERR, "Failed to create table:%s\n",sqlite3_errmsg(g_eventdb));
		goto err;
    }
    ret = sqlite3_exec(g_eventdb, CREATE_ALARM_TABLE_SQL, 0, 0, NULL);
    if (ret != SQLITE_OK) {
        dy_syslog(LOG_ERR, "Failed to create table:%s\n",sqlite3_errmsg(g_eventdb));
		goto err;
    }
	ret = sqlite3_exec(g_eventdb, CREATE_INDEX_IDX_ALARM_MAIN_SUB_EVENT, 0, 0, NULL);
	if (ret != SQLITE_OK) {
        dy_syslog(LOG_ERR, "Failed to create index:%s\n",sqlite3_errmsg(g_eventdb));
		goto err;
    }
	ret = sqlite3_exec(g_eventdb, CREATE_INDEX_IDX_ALARM_CLRTIME, 0, 0, NULL);
	if (ret != SQLITE_OK) {
        dy_syslog(LOG_ERR, "Failed to create index:%s\n",sqlite3_errmsg(g_eventdb));
		goto err;
    }
	ret = sqlite3_exec(g_eventdb, CREATE_INDEX_IDX_ALARM_SETTIME, 0, 0, NULL);
	if (ret != SQLITE_OK) {
        dy_syslog(LOG_ERR, "Failed to create index:%s\n",sqlite3_errmsg(g_eventdb));
		goto err;
    }

	ret = sqlite3_prepare_v2(g_eventdb, INSERT_ALARM_SQL, -1, &g_eventstmt, NULL);
    if (ret != SQLITE_OK) {
        dy_syslog(LOG_ERR, "Failed to prepare statement:%s\n",sqlite3_errmsg(g_eventdb));
        goto err;
    }
	ret = sqlite3_prepare_v2(g_eventdb, UPDATE_ALARM_SQL, -1, &g_handlerstmt, NULL);
    if (ret != SQLITE_OK) {
        dy_syslog(LOG_ERR, "Failed to prepare statement:%s\n",sqlite3_errmsg(g_eventdb));
        goto err;
    }

	ret = sqliteApi_query(SYSTEM_CONFIG_TABLE,SYSTEM_CONFIG_LANGUAGE_KEY,1,INTEGER,&result);
	if(ret == SQLITE_OK){
		g_language = result.integer;
	}
	//每次上电清理下之前未恢复的告警，防止变成脏数据
	clean_unrecovered_alarm();
	//初始化时,检查下alarm文件是否存在,不存在就进行一次文件创建
	time_t start, end;
	char csv_file_path[256] = {0};
	get_day_start_end_timestamp(&start,&end);
	get_alarm_csv_file_path(csv_file_path,256);
	if(!ensure_csv_file(csv_file_path)){
		export_data_within_time_range(EVENT_DB_FILE_PATH,csv_file_path,start,end);
	}
	//初始化完成后进行一次DB3空间清理
	ret = eventprocess_space_cleaning();

    pthread_t thread_id;
    pthread_create(&thread_id, NULL, export_alarm_csv_thread, NULL);
    pthread_detach(thread_id);  // 线程分离，自动回收资源

	return ret;
err:
	if(g_eventstmt){
		sqlite3_finalize(g_eventstmt);
		g_eventstmt = NULL;
	}
	if(g_handlerstmt){
		sqlite3_finalize(g_handlerstmt);
		g_handlerstmt = NULL;
	}
	if(g_eventdb){
		sqlite3_close(g_eventdb);
		g_eventdb = NULL;
	}
	return -1;
}

/**
 * @brief       反初始化
 * @return      void
 * @retval      none
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2024-02-18           JHC        创建初始版本          \n
*/
void eventprocess_deinit()
{
	if(g_eventstmt){
		sqlite3_finalize(g_eventstmt);
		g_eventstmt = NULL;
	}
	if(g_handlerstmt){
		sqlite3_finalize(g_handlerstmt);
		g_handlerstmt = NULL;
	}
	if(g_eventdb){
		sqlite3_close(g_eventdb);
		g_eventdb = NULL;
	}	
}