#include "alarm_control.h"
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syslog.h>
#include <time.h>
#include "alarm_database.h"
#include "alarm_define.h"
#include "hash_intptr.h"
#include "alarm_init.h"
#include "mqtt_emms2.h"
#include "../proto_forward.h"
#include "collector-api.h"
#include "../business_log/business_log.h"

// 全局变量

alarm_control_t alarm_control;
// define
static int           get_forbidden_alarm_code_from_file(void);
static inline int    find_forbidden_alarm_code_from_list(int alarm_code);
static alarm_real_t* find_and_del_alarm_real_from_queue(int alarm_code, int reason_code, tag_t* tag);
static alarm_real_t* find_alarm_real_from_queue(int alarm_code, int reason_code, tag_t* tag);
static inline int    add_forbidden_alarm_code_to_list(long alarm_code);
static char*         get_additional_param_string(alarm_info_t* alarm_info);
//
static int init_alarm_cache_queue(alarm_control_t* alarm_control)
{
    // 当前告警队列
    INIT_LIST_HEAD(&alarm_control->alarm_real_list);
    pthread_mutex_init(&alarm_control->alarm_real_list_mutex, NULL);
    alarm_control->alarm_real_list_max_size = 1000;
    alarm_control->alarm_real_list_size     = 0;
    // 屏蔽告警列表
    INIT_LIST_HEAD(&alarm_control->alarm_forbidden_list);
    pthread_mutex_init(&alarm_control->alarm_forbidden_list_mutex, NULL);
    alarm_control->alarm_forbidden_list_max_size = 1000;
    alarm_control->alarm_forbidden_list_size     = 0;
    return 0;
}

// 初始化告警控制模块
int alarm_control_init(alarm_control_t* alarm_control)
{
    // 初始化告警队列
    alarm_control->need_report = false;
    int ret                    = init_alarm_cache_queue(alarm_control);
    if (ret != 0)
    {
        BUSINESS_LOG(BLOG_ERR, ALARM_ID_0001, NULL, "初始化实时告警队列失败");
        return -1;
    }

    // 初始化数据库连接
    ret = init_alarm_db(&alarm_control->db);
    if (ret != 0)
    {
        BUSINESS_LOG(BLOG_ERR, ALARM_ID_0001, NULL, "初始化告警数据库失败");
        alarm_control->db = NULL;
    }

    // 初始化告警信息哈希表
    init_alarm_info(alarm_control);
    // 读取数据库中未恢复的告警
    get_all_real_alarm_from_db();
    // 从配置文件中读取告警屏蔽列表
    get_forbidden_alarm_code_from_file();

    return 0;
}

void set_alarm_need_report(bool status)
{
    alarm_control.need_report = status;
    ems_syslog(LOG_WARNING, "set alarm need report to %d", status);
}

static int free_alarm_tag_hash(struct hash_intptr* hash_p, int unknow, void* param)
{
    destory_alarm_tag((alarm_tag_t*)hash_p->hh_ptr);
    return 0;
}

static int free_alarm_condition_hash(struct hash_intptr* hash_p, int unknow, void* param)
{
    free((cond_chenge_t*)hash_p->hh_ptr);
    return 0;
}

static int destory_alarm_info_hash_iter(struct hash_intptr* hash_p, int unknow, void* param)
{
    destory_alarm_info((alarm_info_t*)hash_p->hh_ptr);
    return 0;
}

int alarm_control_destory(alarm_control_t* alarm_control)
{
    alarm_real_t*   alarm_real      = NULL;
    alarm_forbd_t*  alarm_forbidden = NULL;

    // 清空当前告警队列
    list_for_each_entry(alarm_real, &alarm_control->alarm_real_list, list)
    {
        list_del(&alarm_real->list);
        free(alarm_real);
    }
    // 清空屏蔽告警列表
    list_for_each_entry(alarm_forbidden, &alarm_control->alarm_forbidden_list, list)
    {
        list_del(&alarm_forbidden->list);
        free(alarm_forbidden);
    }

    if (alarm_control->db != NULL)
    {
        close_alarm_db(&alarm_control->db);
        alarm_control->db = NULL;
    }

    if (alarm_control->alarm_tag_hash != NULL)
    {
        hash_intptr_iter(&alarm_control->alarm_tag_hash, free_alarm_tag_hash, NULL);
        hash_intptr_removeall(&alarm_control->alarm_tag_hash);
        alarm_control->alarm_tag_hash = NULL;
    }

    if (alarm_control->alarm_info_hash != NULL)
    {
        hash_intptr_iter(&alarm_control->alarm_info_hash, destory_alarm_info_hash_iter, NULL);
        hash_intptr_removeall(&alarm_control->alarm_info_hash);
        alarm_control->alarm_info_hash = NULL;
    }

    if (alarm_control->alarm_cond_ce_hash != NULL)
    {
        hash_intptr_iter(&alarm_control->alarm_cond_ce_hash, free_alarm_condition_hash, NULL);
        hash_intptr_removeall(&alarm_control->alarm_cond_ce_hash);
        alarm_control->alarm_cond_ce_hash = NULL;
    }

    if (alarm_control->alarm_code_hash != NULL)
    {
        hash_intptr_removeall(&alarm_control->alarm_code_hash);
    }

    return 0;
}

// 业务
static alarm_real_t* create_alarm_real_node(alarm_tag_t* alarm_tag, alarm_info_t* alarm)
{
    if (alarm == NULL)
    {
        return NULL;
    }
    alarm_real_t* alarm_real = (alarm_real_t*)malloc(sizeof(alarm_real_t));
    if (alarm_real == NULL)
    {
        ems_syslog(LOG_ERR, "malloc alarm report struct failed");
        return NULL;
    }
    alarm_real->alarm      = alarm;
    alarm_real->entity     = strdup(((device_t*)(alarm_tag->tag->dev_ptr))->no);
    alarm_real->tagname    = strdup(alarm_tag->tag->dev_tag_name);
    alarm_real->additional = get_additional_param_string(alarm);
    alarm_real->status     = ALARM_RAISE;
    alarm_real->raise      = get_time_stamp_ms();
    alarm_real->recovery   = 0;
    return alarm_real;
}

alarm_report_t* create_alarm_report_node(alarm_real_t* alarm_real)
{
    alarm_report_t* alarm_report = malloc(sizeof(alarm_report_t));
    memcpy(alarm_report, alarm_real, sizeof(alarm_real_t));
    if (alarm_real->entity != NULL)
    {
        alarm_report->entity = strdup(alarm_real->entity);
    }
    if (alarm_real->tagname != NULL)
    {
        alarm_report->tagname = strdup(alarm_real->tagname);
    }
    if (alarm_real->additional != NULL)
    {
        alarm_report->additional = strdup(alarm_real->additional);
    }
    return alarm_report;
}

bool checkout_condition(alarm_condition_t* cond)
{
    bool result = true;
    if (cond->tag == NULL)
    {
        return false;
    }
    switch (cond->condition)
    {
        case CONDITION_GT: // 0大于 1大于等于 2等于 3小于 4小于等于
        {
            if (cond->tag->data_type == TYPE_TAG_INT && cond->tag->read_cache.to_int <= cond->value)
            {
                result = false;
            }
            else if (cond->tag->data_type == TYPE_TAG_FLOAT && cond->tag->read_cache.to_float <= cond->value)
            {
                result = false;
            }
            break;
        }
        case CONDITION_GE:
        {
            if (cond->tag->data_type == TYPE_TAG_INT && cond->tag->read_cache.to_int < cond->value)
            {
                result = false;
            }
            else if (cond->tag->data_type == TYPE_TAG_FLOAT && cond->tag->read_cache.to_float < cond->value)
            {
                result = false;
            }
            break;
        }
        case CONDITION_EQ:
        {
            if (cond->tag->data_type == TYPE_TAG_INT && cond->tag->read_cache.to_int != cond->value)
            {
                result = false;
            }
            else if (cond->tag->data_type == TYPE_TAG_FLOAT && cond->tag->read_cache.to_float != cond->value)
            {
                result = false;
            }
            break;
        }
        case CONDITION_LT:
        {
            if (cond->tag->data_type == TYPE_TAG_INT && cond->tag->read_cache.to_int >= cond->value)
            {
                result = false;
            }
            else if (cond->tag->data_type == TYPE_TAG_FLOAT && cond->tag->read_cache.to_float >= cond->value)
            {
                result = false;
            }
            break;
        }
        case CONDITION_LE:
        {
            if (cond->tag->data_type == TYPE_TAG_INT && cond->tag->read_cache.to_int > cond->value)
            {
                result = false;
            }
            else if (cond->tag->data_type == TYPE_TAG_FLOAT && cond->tag->read_cache.to_float > cond->value)
            {
                result = false;
            }
            break;
        }
        case CONDITION_ERROR:
        case CONDITION_MAX:
        default:
        {
            result = false;
            break;
        }
    }
    return result;
}

// 表达式处理
bool is_alarm(alarm_info_t* alarm_info, tag_t* alarm)
{
    // 判断告警是否有效
    if (alarm_info->alarm_code == find_forbidden_alarm_code_from_list(alarm_info->alarm_code))
    {
        // ems_syslog(LOG_DEBUG, "alarm event active but is invalid, tag,: %s", alarm->dev_tag_name);
        return false;
    }

    bool result = true;

    for (int i = 0; i < alarm_info->condition_num && result; i++)
    {
        alarm_condition_t* cond = alarm_info->condition[i];
        if (cond->tag == NULL)
        {
            continue;
        }
        result = checkout_condition(cond);
    }
    return result;
}

/**/
alarm_info_t* get_alarm_info_by_code(int alarmCode, int reasonCode)
{
    alarm_info_t* info    = NULL;
    char          key[32] = {0};
    snprintf(key, sizeof(key), "%d.%d", alarmCode, reasonCode);
    hash_intptr_findptr(alarm_control.alarm_code_hash, key, strlen(key), (void**)&info);
    return info;
}

int get_alarm_cnt(){
    return alarm_control.alarm_real_list_size;
}

static void deal_alarm_event(alarm_tag_t* alarm_tag)
{
    if (alarm_tag == NULL) return;
    tag_t * tag = alarm_tag->tag;
    for (int i = 0; i < alarm_tag->alarm_info_num; i++)
    {
        alarm_info_t* info = alarm_tag->alarm_info[i];
        if (is_alarm(info, tag))
        {
            // 告警
            alarm_real_t* real = find_alarm_real_from_queue(info->alarm_code, info->reason_code, alarm_tag->tag);
            if (real != NULL)
            {
                // ems_syslog(LOG_DEBUG, "alarm event active but is already in real list, tag: %s", tag->dev_tag_name);
                continue;
            }
            // 激活告警
            BUSINESS_LOG(BLOG_WARNING, ALARM_ID_0005, tag->dev_tag_name, "告警激活, tag: %s, key: %d,%d", tag->dev_tag_name, info->alarm_code, info->reason_code);
            real = create_alarm_real_node(alarm_tag, info);
            if (real != NULL)
            {
                if (push_alarm_real_to_queue(real) != 0)
                {
                    ems_syslog(LOG_ERR, "push alarm real to list failed");
                    destory_alarm_real(real);
                }
                else
                {
#ifdef EN_ACCIDENT
                    alarm_event_t* alarm_event_real = create_alarm_event_node(real);
                    if (alarm_event_real != NULL && push_alarm_event_to_queue(alarm_event_real) != 0)
                    {
                        ems_syslog(LOG_ERR, "[zxf]push alarm event list failed");
                        free(alarm_event_real);
                    }
#endif
                }
            }
            mqtt_add_alarm_report_s(real);

            alarm_db_t db_alarm    = {};
            db_alarm.alarm_code    = real->alarm->alarm_code;
            db_alarm.reason_code   = real->alarm->reason_code;
            db_alarm.entity        = real->entity;
            db_alarm.dev_tag_name  = real->tagname;
            db_alarm.addition      = real->additional;
            db_alarm.raise_time    = real->raise;
            db_alarm.recovery_time = real->recovery;
            db_alarm.status        = real->status;
            flush_alarm_db_to_database(&db_alarm);
        }
        else
        {
            // 恢复
            alarm_real_t* real = find_and_del_alarm_real_from_queue(info->alarm_code, info->reason_code, alarm_tag->tag);
            if (real != NULL)
            {
                BUSINESS_LOG(BLOG_WARNING, ALARM_ID_0005, tag->dev_tag_name, "告警恢复, tag: %s, key: %d,%d", tag->dev_tag_name, info->alarm_code, info->reason_code);
                real->recovery = get_time_stamp_ms();
                real->status   = ALARM_RECOVERY;
                mqtt_add_alarm_report_s(real);
                recovery_alarm_to_db(real);
                destory_alarm_real(real);
            }
        }
    }
}

static int traverse_alarm_tag_hash(struct hash_intptr* hash_p, int unknow, void* param)
{
    deal_alarm_event((alarm_tag_t*)hash_p->hh_ptr);
    return 0;
}

// 告警处理线程
static void* alarm_control_thread(void* arg)
{
    sleep(20);
    while (true)
    {
        sleep(1);
        hash_intptr_iter(&alarm_control.alarm_tag_hash, traverse_alarm_tag_hash, NULL);

        if (time(NULL) % 86400 == 0)
        {
            delete_staledated_alarm(10000); // sqlite数据库每天检测一次 保留10000条数据
        }
    }
    return NULL;
}
//  入口
int init_alarm_control_task()
{
    // 初始化告警控制模块
    int ret = alarm_control_init(&alarm_control);
    if (ret != 0)
    {
        alarm_control_destory(&alarm_control);
        ems_syslog(LOG_ERR, "alarm control init failed");
        return ret;
    }
    else
    {
        BUSINESS_LOG(BLOG_ERR, ALARM_ID_0001, NULL, "初始化实时告警模块成功");
    }

    pthread_t tid;
    if (pthread_create(&tid, NULL, alarm_control_thread, NULL) != 0)
    {
        alarm_control_destory(&alarm_control);
        BUSINESS_LOG(BLOG_ERR, ALARM_ID_0002, NULL, "启动实时告警模块失败");
        return -1;
    }
    else
    {
        BUSINESS_LOG(BLOG_ERR, ALARM_ID_0002, NULL, "启动实时告警模块成功");
        pthread_setname_np(tid, "alarm_task");
    }
    return 0;
}

// 打印告警信息
int get_alarm_string(struct lnxall_buff* lbuf, int type)
{
    char        data_tmp[1024] = {0};
    const char* head          = "\"messages\":[";
    int         head_len      = strlen(head);
    lbuff_append(lbuf, head, head_len);

    // node_t* h = alarm_control.alarm_real_list->head;
    alarm_real_t* real = NULL;
    int append_len = 0;
    list_for_each_entry(real, &alarm_control.alarm_real_list, list)
    {
        alarm_info_t* alarm_info = real->alarm;
        if (alarm_info == NULL)
        {
            continue;
        }
        if (head_len + 1 < lbuf->curlen)
        {
            lbuff_append(lbuf, ",", 1);
        }
        append_len = snprintf(data_tmp, sizeof(data_tmp), "{\"alarmCode\":%d,", alarm_info->alarm_code);
        lbuff_append(lbuf, data_tmp, append_len);
        append_len = snprintf(data_tmp, sizeof(data_tmp), "\"reasonCode\":%d,", alarm_info->reason_code);
        lbuff_append(lbuf, data_tmp, append_len);
        append_len = snprintf(data_tmp, sizeof(data_tmp), "\"severity\":%d,", alarm_info->severity);
        lbuff_append(lbuf, data_tmp, append_len);
        append_len = snprintf(data_tmp, sizeof(data_tmp), "\"entityInstance\":\"%s\",", real->entity);
        lbuff_append(lbuf, data_tmp, append_len);
        append_len = snprintf(data_tmp, sizeof(data_tmp), "\"additionalParam\":\"%s\",", real->additional == NULL ? "" : real->additional);
        lbuff_append(lbuf, data_tmp, append_len);
        append_len = snprintf(data_tmp, sizeof(data_tmp), "\"raiseTime\":%"PRIu64"}", real->raise / 1000);
        lbuff_append(lbuf, data_tmp, append_len);
    }
    lbuff_append(lbuf, "]", 1);
    return lbuf->curlen;
}

/* 屏蔽 告警Id */
static int find_forbidden_alarm_code_from_list(int alarm_code)
{
    alarm_forbd_t* code = 0;
    list_for_each_entry(code, &alarm_control.alarm_forbidden_list, list)
    {
        if (code->alarm_code == alarm_code)
        {
            return alarm_code;
        }
    }
    return 0;
}
// 从配置文件中读取屏蔽的告警
static int get_forbidden_alarm_code_from_file(void)
{
    char*  file = NULL;
    cJSON* json = NULL;
    file        = read_file_data(ALARM_DISABLE_LIST_FILE);
    if (file == NULL) goto ERR0;

    json = cJSON_Parse(file);
    if (json == NULL) goto ERR0;

    cJSON* item = cJSON_GetObjectItem(json, "forbidden");
    if (item == NULL) goto ERR0;

    int size = cJSON_GetArraySize(item);
    for (int i = 0; i < size; i++)
    {
        cJSON* code = cJSON_GetArrayItem(item, i);
        if (code == NULL)
        {
            continue;
        }
        int alarm_code = code->valueint;
        if (alarm_code != 0)
            add_forbidden_alarm_code_to_list(alarm_code);
    }

ERR0:
    if (file != NULL)
    {
        free(file);
    }
    if (json != NULL)
    {
        cJSON_free(json);
    }
    return 0;
}

// 刷新屏蔽的告警(不管是文件还是云端下发,都是全量刷新)
static inline int add_forbidden_alarm_code_to_list(long alarm_code)
{
    alarm_forbd_t* alarm = (alarm_forbd_t*)malloc(sizeof(alarm_forbd_t));
    if (alarm == NULL) return -1;
    alarm->alarm_code = alarm_code;
    alarm->list.next  = NULL;
    alarm->list.prev  = NULL;
    list_add_tail(&alarm->list, &alarm_control.alarm_forbidden_list);
    return 0;
}

int add_forbidden_alarm_code(int* alarm_code, int size)
{
    alarm_forbd_t* code = 0;
    cJSON*         item = cJSON_CreateArray();

    pthread_mutex_lock(&alarm_control.alarm_forbidden_list_mutex);
    list_for_each_entry(code, &alarm_control.alarm_forbidden_list, list)
    {
        list_del(&code->list);
        free(code);
    }
    for (int i = 0; i < size; i++)
    {
        add_forbidden_alarm_code_to_list(alarm_code[i]);
        cJSON_AddItemToArray(item, cJSON_CreateNumber(alarm_code[i]));
    }
    pthread_mutex_unlock(&alarm_control.alarm_forbidden_list_mutex);

    cJSON* json = cJSON_CreateObject();
    cJSON_AddItemToObject(json, "forbidden", item);
    char* file = cJSON_Print(json);
    if (file != NULL)
    {
        write_file_data(ALARM_DISABLE_LIST_FILE, file, strlen(file));
        free(file);
    }
    else
    {
        ems_syslog(LOG_ERR, "add_forbidden_alarm_code: cJSON_Print failed");
    }
    cJSON_free(json);
    return 0;
}


// alarm_real_list
int push_alarm_real_to_queue(alarm_real_t* real)
{
    int ret = -1;
    pthread_mutex_lock(&alarm_control.alarm_real_list_mutex);
    if (alarm_control.alarm_real_list_size < alarm_control.alarm_real_list_max_size)
    {
        list_add_tail(&real->list, &alarm_control.alarm_real_list);
        alarm_control.alarm_real_list_size++;
        ret = 0;
    }
    pthread_mutex_unlock(&alarm_control.alarm_real_list_mutex);
    return ret;
}

// 找到并删除当前告警,只删除队列节点,返回告警结构体指针(内容)
static alarm_real_t* find_and_del_alarm_real_from_queue(int alarm_code, int reason_code, tag_t* tag)
{
    alarm_real_t* alarm = NULL;
    pthread_mutex_lock(&alarm_control.alarm_real_list_mutex);
    if (!list_empty(&alarm_control.alarm_real_list))
    {
        alarm_real_t* pos = NULL;
        list_for_each_entry(pos, &alarm_control.alarm_real_list, list)
        {
            if (pos->alarm->alarm_code == alarm_code && pos->alarm->reason_code == reason_code && strcmp(pos->entity, ((device_t*)tag->dev_ptr)->no) == 0)
            {
                list_del(&pos->list);
                alarm = pos;
                alarm_control.alarm_real_list_size--;
                break;
            }
        }
    }
    pthread_mutex_unlock(&alarm_control.alarm_real_list_mutex);
    return alarm;
}

static alarm_real_t* find_alarm_real_from_queue(int alarm_code, int reason_code, tag_t* tag)
{
    alarm_real_t* alarm = NULL;
    pthread_mutex_lock(&alarm_control.alarm_real_list_mutex);
    if (!list_empty(&alarm_control.alarm_real_list))
    {
        alarm_real_t* pos = NULL;
        list_for_each_entry(pos, &alarm_control.alarm_real_list, list)
        {
            if (pos->alarm->alarm_code == alarm_code && pos->alarm->reason_code == reason_code && strcmp(pos->entity, ((device_t*)tag->dev_ptr)->no) == 0)
            {
                alarm = pos;
                break;
            }
        }
    }
    pthread_mutex_unlock(&alarm_control.alarm_real_list_mutex);
    return alarm;
}
//

typedef char* (*get_info_func_t)(int alarm_code, int reason_code);

typedef struct {
    int alarm_code;
    int reason_code;
    get_info_func_t get_info_func;
} alarm_info_map_t;

static char* get_abnormal_domain(int alarm_code, int reason_code) {
    pcs_ctrl_var_t *ctrl_var = get_pcs_ctrl_var();
    if (!ctrl_var || !ctrl_var->domain_list.list || ctrl_var->domain_list.count <= 0) {
        return NULL;
    }
    char buffer[2048] = {0};
    int offset = 0;
    for (int i = 0; i < ctrl_var->domain_list.count; ++i) {
        domain_info_t *domain = &ctrl_var->domain_list.list[i];
        if (domain->status == 1) {
            if (offset > 0) {
                buffer[offset++] = '/';
            }
            int n = snprintf(buffer + offset, sizeof(buffer) - offset, "%s:%u", domain->domain, domain->port);
            if (n < 0 || n >= (int)(sizeof(buffer) - offset)) {
                break;
            }
            offset += n;
        }
    }
    if (offset == 0) {
        return NULL;
    }
    return strdup(buffer);
}

static alarm_info_map_t alarm_info_map_table[] = {
    {20004, 21, get_abnormal_domain},
};

#define ALARM_INFO_MAP_TABLE_SIZE (sizeof(alarm_info_map_table)/sizeof(alarm_info_map_table[0]))

char *get_information_from_tag_info_map(int alarm_code, int reason_code)
{
    for (size_t i = 0; i < ALARM_INFO_MAP_TABLE_SIZE; i++) {
        if (alarm_info_map_table[i].alarm_code == alarm_code &&
            alarm_info_map_table[i].reason_code == reason_code &&
            alarm_info_map_table[i].get_info_func != NULL) {
            return alarm_info_map_table[i].get_info_func(alarm_code, reason_code);
        }
    }
    return NULL;
}

// MQTT UI 获取信息
static char* get_additional_param_string(alarm_info_t* alarm_info)
{
    if (alarm_info == NULL || alarm_info->additional_para == NULL)
    {
        return NULL;
    }

    char tmp_char[DEV_NAME_LEN + TAG_NAME_LEN + 10] = {0};
    char distChar[2048]                             = {0};
    int  index                                      = 0;
    for (size_t i = 0; i < alarm_info->additional_para->num; i++)
    {
        uint8_t spilit  = alarm_info->additional_para->spilit[i];
        uint8_t addtype = alarm_info->additional_para->addtype[i];

        if (alarm_info->additional_para->tags[i] != NULL)
        {
            char spilitCode = ',';
            if (spilit == 1)
            {
                spilitCode = ';';
            }
            if (addtype == 1)
            {
                tag_t* tag = alarm_info->additional_para->tags[i];
                sprintf(tmp_char, "%s.%s%c", ((device_t*)tag->dev_ptr)->disp_name, tag->disp_name, spilitCode);
            }
            else if (addtype == 2)
            {
                sprintf(tmp_char, "%s%c", (char*)alarm_info->additional_para->tags[i], spilitCode);
            }
            else
            {
                tag_t* tag = alarm_info->additional_para->tags[i];

                if (tag->data_type == TYPE_TAG_INT)
                {
                    sprintf(tmp_char, "%ld%c", tag->read_cache.to_int, spilitCode);
                }
                else
                {
                    snprintf(tmp_char, sizeof(tmp_char), "%.2f%c", tag->read_cache.to_float, spilitCode);
                }
            }
            index += snprintf(distChar + index, sizeof(distChar) - index, "%s", tmp_char);
        }
        else
        {
            index += snprintf(distChar + index, sizeof(distChar) - index, "(null),");
        }
    }
    if(alarm_info->additional_para->num == 0)
    {
        char *addition_info = get_information_from_tag_info_map(alarm_info->alarm_code, alarm_info->reason_code);
        if(addition_info != NULL) {
            index += snprintf(distChar + index, sizeof(distChar) - index, "%s", addition_info);
            free(addition_info);
        }else{
            index += snprintf(distChar + index, sizeof(distChar) - index, "(null),");
        }
    }
    int len = strlen(distChar);
    if (len > 0)
    {
        if ((distChar[len - 1] == ',') || (distChar[len - 1] == ';'))
        {
            distChar[len - 1] = '\0';
        }
        return strdup(distChar);
    }
    return NULL;
}

// 指定 tag_t 注册告警信息
int register_alarm_by_tag(tag_t* tag, alarm_info_cond_t* info)
{
    char          key[144]   = {0};
    int           key_len    = 0;
    alarm_info_t* alarm_info = NULL;

    key_len = snprintf(key, sizeof(key), "%d.%d", info->alarm_code, info->reason_code);
    if (hash_intptr_findptr(alarm_control.alarm_code_hash, key, key_len, (void**)&alarm_info) != 0 || alarm_info == NULL)
    {
        ems_syslog(LOG_NOTICE, "get alarm info from temp hash failed-key: %s, alarm tag do not has alarm code", key);
        ems_syslog(LOG_CRIT, "[告警]读取[告警码：%s]告警信息失败,确认文件[%s]中是否存在告警定义 ", key,ALARM_INFO_FILE);
        return -1;
    }

    alarm_info = make_alarm_info_with_cond_para(alarm_info, info, tag);
    add_alarm_info_to_alarm_tag(tag, alarm_info);
    return 0;
}

// 注册用户自定义报警
int register_alarm_with_info(tag_t* tag, ALARM_CONDITION condition, int value, int alarm_code, int reason_code, char* param)
{
    alarm_info_cond_t info = {0};

    char addition_name[128] = {0};

    snprintf(addition_name, sizeof(addition_name), "%%%s;", param);
    info.additional_para[0] = strdup(addition_name);

    info.alarm_code  = alarm_code;
    info.reason_code = reason_code;
    info.cond        = condition;
    info.value       = value;
    info.update_cond = true;
    register_alarm_by_tag(tag, &info);
    return 0;
}

int register_ems_user_define_alarm_with_info(alarm_condition_list* register_alarm_param, int alarm_code, int reason_code, char* params[], int num)
{
    alarm_info_cond_t info               = {0};
    char              addition_name[128] = {0};
    int               index              = 0;
    for (size_t i = 0; i < num; i++)
    {
        snprintf(addition_name, sizeof(addition_name), "%%%s;", params[i]);
        info.additional_para[index++] = strdup(addition_name);
        if (index == ALARM_CHILD_CONDS_NUM_MAX) break;
    }
    info.alarm_code  = alarm_code;
    info.reason_code = reason_code;
    info.cond        = register_alarm_param->register_alarm_param_info[0].condition;
    info.value       = register_alarm_param->register_alarm_param_info[0].value;
    info.update_cond = true;
    for (size_t i = 1; i < register_alarm_param->num; i++)
    {
        info.child_conds[i - 1].tag_name = register_alarm_param->register_alarm_param_info[i].tag->dev_tag_name;
        info.child_conds[i - 1].cond     = register_alarm_param->register_alarm_param_info[i].condition;
        info.child_conds[i - 1].value    = register_alarm_param->register_alarm_param_info[i].value;
        if (i == ALARM_CHILD_CONDS_NUM_MAX) break;
    }
    register_alarm_by_tag(register_alarm_param->register_alarm_param_info[0].tag, &info);
    for (int i = 0; i < index; i++)
    {
        if (info.additional_para[i] != NULL)
            free(info.additional_para[i]);
    }
    return 0;
}

int register_ems_user_define_alarm(alarm_condition_list* register_alarm_param, int alarm_code, int reason_code)
{
    alarm_info_cond_t info = {0};
    char addition_name[98] = {0};
    int  index             = 0;
    for (size_t i = 0; i < register_alarm_param->num; i++)
    {
        if (strcmp(register_alarm_param->register_alarm_param_info[i].tag->dev_tag_name, "EMS.EnIoProtect") == 0) //使能开关不作为附加信息上报
        {
            continue;
        }
        snprintf(addition_name, sizeof(addition_name), "&%s;", register_alarm_param->register_alarm_param_info[i].tag->dev_tag_name);
        info.additional_para[index++] = strdup(addition_name);
        if (index == ALARM_CHILD_CONDS_NUM_MAX) break;
    }
    info.alarm_code  = alarm_code;
    info.reason_code = reason_code;
    info.cond        = register_alarm_param->register_alarm_param_info[0].condition;
    info.value       = register_alarm_param->register_alarm_param_info[0].value;
    info.update_cond = true;
    for (size_t i = 1; i < register_alarm_param->num; i++)
    {
        info.child_conds[i - 1].tag_name = register_alarm_param->register_alarm_param_info[i].tag->dev_tag_name;
        info.child_conds[i - 1].cond     = register_alarm_param->register_alarm_param_info[i].condition;
        info.child_conds[i - 1].value    = register_alarm_param->register_alarm_param_info[i].value;
        if(i == ALARM_CHILD_CONDS_NUM_MAX) break;
    }
    register_alarm_by_tag(register_alarm_param->register_alarm_param_info[0].tag, &info);
    for (int i = 0; i < index; i++)
    {
        if (info.additional_para[i] != NULL)
            free(info.additional_para[i]);
    }
    return 0;
}

// 注册IO保护报警
int register_ems_io_protect_alarm(alarm_condition_list* register_alarm_param)
{
    static int ems_io_protect_reason_code = 1;
    return register_ems_user_define_alarm(register_alarm_param, 20015, ems_io_protect_reason_code++);
}
// 注册用户自定义报警
int register_ems_device_alarm(alarm_condition_list* register_alarm_param)
{
    static int ems_user_reason_code = 1;
    return register_ems_user_define_alarm(register_alarm_param, 20016, ems_user_reason_code++);
}

// 手动删除告警
int delete_alarm_by_code(char* dev_no, int alarm_code, int reason_code)
{
    alarm_real_t* alarm = NULL;
    int ret = -1;
    pthread_mutex_lock(&alarm_control.alarm_real_list_mutex);
    if (!list_empty(&alarm_control.alarm_real_list))
    {
        alarm_real_t* pos = NULL;
        list_for_each_entry(pos, &alarm_control.alarm_real_list, list)
        {
            if (pos->alarm->alarm_code == alarm_code && pos->alarm->reason_code == reason_code && strcmp(pos->entity, dev_no) == 0)
            {
                list_del(&pos->list);
                alarm = pos;
                alarm_control.alarm_real_list_size--;
                break;
            }
        }
    }
    pthread_mutex_unlock(&alarm_control.alarm_real_list_mutex);
    if (alarm != NULL)
    {
        ems_syslog(LOG_WARNING, "alarm recovered, delete from real list by manual: %s, %d,%d", dev_no, alarm->alarm->alarm_code, alarm->alarm->reason_code);
        alarm->recovery = get_time_stamp_ms();
        alarm->status   = ALARM_RECOVERY;
        mqtt_add_alarm_report_s(alarm);
        recovery_alarm_to_db(alarm);
        destory_alarm_real(alarm);
        ret = 0;
    }
    return ret;
}

int delete_alarm_by_tag(char* dev_tag_name)
{
    alarm_tag_t* alarm_tag = NULL;

    if (hash_intptr_findptr(alarm_control.alarm_tag_hash, dev_tag_name, strlen(dev_tag_name), ((void**)&alarm_tag)) != 0)
    {
        ems_syslog(LOG_WARNING, "alarm tag not exist: %s", dev_tag_name);
        return -1;
    }
    char* dev_no = ((device_t*)(alarm_tag->tag->dev_ptr))->no;
    pthread_mutex_lock(&alarm_control.alarm_real_list_mutex);
    for (int i = 0; i < alarm_tag->alarm_info_num; i++)
    {
        alarm_info_t* info = alarm_tag->alarm_info[i];
        alarm_real_t* alarm = NULL;
        if (!list_empty(&alarm_control.alarm_real_list))
        {
            alarm_real_t* pos = NULL;
            list_for_each_entry(pos, &alarm_control.alarm_real_list, list)
            {
                if (pos->alarm->alarm_code == info->alarm_code && pos->alarm->reason_code == info->reason_code && strcmp(pos->entity, dev_no) == 0)
                {
                    list_del(&pos->list);
                    alarm = pos;
                    alarm_control.alarm_real_list_size--;
                    break;
                }
            }
        }
        if (alarm != NULL)
        {
            ems_syslog(LOG_WARNING, "alarm recovered, delete from real list by manual: %s, %d,%d", dev_no, alarm->alarm->alarm_code, alarm->alarm->reason_code);
            alarm->recovery = get_time_stamp_ms();
            alarm->status   = ALARM_RECOVERY;
            mqtt_add_alarm_report_s(alarm);
            recovery_alarm_to_db(alarm);
            destory_alarm_real(alarm);
        }
    }
    pthread_mutex_unlock(&alarm_control.alarm_real_list_mutex);
    return 0;
}
