#include "define.h"
#include "collector-api.h"
#include "deviceLayer.h"
#include "deviceLayer.h"
#include <bits/pthreadtypes.h>
#include <pthread.h>
#include <stdint.h>
#include <string.h>
#include <sys/syslog.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "g100_protect.h"
#include "../multilanguage.h"

#ifdef EN_TDENGINE
#include "../database/taos_database.h"
void* init_g100_protect_db()
{
    const char* ip    =  DEFINE_TAOS_HOST;
    const char* user  = DEFINE_TAOS_USERNAME;
    const char* passw =  DEFINE_TAOS_PASSWD;
    const int   p     =  DEFINE_TAOS_PORT;
    TAOS_RES* res  = NULL;
    TAOS*       taos  = taos_connect(ip, user, passw, NULL, p);
    if (taos == NULL)
    {
        ems_syslog(LOG_ERR, "taos connect g100 database failed");
        goto ERROR;
    }
    res = taos_query(taos, TAOS_CREATE_G100_HISTORY_DB);
    if (res == NULL || taos_errno(res) != 0)
    {
        ems_syslog(LOG_ERR, "create alarm history db failed, err=%s", res ? taos_errstr(res) : "NULL");
        goto ERROR;
    }
    taos_free_result(res);

    res = taos_query(taos, TAOS_USE_G100_HISTORY_DB);
    if (res == NULL || taos_errno(res) != 0)
    {
        ems_syslog(LOG_ERR, "use alarm history db failed, err=%s", res ? taos_errstr(res) : "NULL");
        goto ERROR;
    }
    taos_free_result(res);

    res = taos_query(taos, CREATE_G100_HISTORY_STB);
    if (res == NULL || taos_errno(res) != 0)
    {
        ems_syslog(LOG_ERR, "create alarm history stb failed, err=%s", res ? taos_errstr(res) : "NULL");
        goto ERROR;
    }
    taos_free_result(res);
    return taos;

ERROR:
    if (res != NULL) taos_free_result(res);
    if (taos != NULL) taos_close(taos);
    return NULL;
}

// 获取数据库最后一条记录
int g100_protect_db_get_last_record(g100_protect_t* g100_protect)
{
    if (g100_protect->db == NULL)
    {
        return -1;
    }
    char sql[1024] = {0};
    snprintf(sql, sizeof(sql), TAOS_SELECT_G100_LAST_RECORD);
    TAOS_RES* res = taos_query(g100_protect->db, sql);
    if (res == NULL || taos_errno(res) != 0)
    {
        ems_syslog(LOG_ERR, "get g100 history last record failed, err=%s", res ? taos_errstr(res) : "NULL");
        goto ERROR;
    }
    TAOS_ROW row = taos_fetch_row(res);
    if (row != NULL)
    {
        g100_protect->start_time = *(int64_t*)row[0];
        g100_protect->abnormal   = *(int32_t*)(row[1]);
        g100_protect->result     = *(int32_t*)(row[2]);
    }
    taos_free_result(res);
    return 0;

ERROR:
    if (res != NULL) taos_free_result(res);
    return -1;
}

int g100_protect_db_insert(g100_protect_t* g100_protect)
{
    if (g100_protect->db == NULL)
    {
        return -1;
    }
    char sql[1024] = {0};
    snprintf(sql, sizeof(sql), TAOS_INSERT_G100_HISTORY_STB, g100_protect->start_time, g100_protect->abnormal, g100_protect->result);
    TAOS_RES* res = taos_query(g100_protect->db, sql);
    if (res == NULL || taos_errno(res) != 0)
    {
        ems_syslog(LOG_ERR, "insert g100 history failed, err=%s", res ? taos_errstr(res) : "NULL");
        goto ERROR;
    }
    taos_free_result(res);
    return 0;

ERROR:
    if (res != NULL) taos_free_result(res);
    return -1;
}

int g100_protect_db_update(g100_protect_t* g100_protect)
{
    if (g100_protect->db == NULL)
    {
        return -1;
    }
    char sql[1024] = {0};
    snprintf(sql, sizeof(sql), TAOS_INSERT_G100_HISTORY_STB, g100_protect->start_time, g100_protect->abnormal, g100_protect->result);
    TAOS_RES* res = taos_query(g100_protect->db, sql);
    if (res == NULL || taos_errno(res) != 0)
    {
        ems_syslog(LOG_ERR, "insert g100 history failed, err=%s", res ? taos_errstr(res) : "NULL");
        goto ERROR;
    }
    taos_free_result(res);
    return 0;

ERROR:
    if (res != NULL) taos_free_result(res);
    return -1;
}

int g100_protect_db_get_10min_count(g100_protect_t* g100_protect)
{
    if (g100_protect->db == NULL)
    {
        return -1;
    }
    int      count     = 0;
    char     sql[1024] = {0};
    uint64_t now       = get_time_stamp_ms();
    snprintf(sql, sizeof(sql), TAOS_SELECT_G100_COUNT_10MIN, now - 600000);
    TAOS_RES* res = taos_query(g100_protect->db, sql);
    if (res == NULL || taos_errno(res) != 0)
    {
        ems_syslog(LOG_ERR, "get g100 history 10min count failed, err=%s", res ? taos_errstr(res) : "NULL");
        goto END;
    }

    TAOS_ROW row = NULL;
    while ((row = taos_fetch_row(res)) != NULL)
    {
        count++;
        int result = *(int32_t*)(row[2]);
        if (result == G100_RESULT_ADUNLOCK)
        {
            count = 0;
        }
    }
END:
    if (res != NULL) taos_free_result(res);
    return count;
}

int g100_protect_db_get_day_count(g100_protect_t* g100_protect)
{
    if (g100_protect->db == NULL)
    {
        return -1;
    }
    int      count     = 0;
    char     sql[1024] = {0};
    uint64_t now       = get_time_stamp_ms();
    snprintf(sql, sizeof(sql), TAOS_SELECT_G100_COUNT_DAY, now - 86400000);
    TAOS_RES* res = taos_query(g100_protect->db, sql);
    if (res == NULL || taos_errno(res) != 0)
    {
        ems_syslog(LOG_ERR, "get g100 history data failed, err=%s", res ? taos_errstr(res) : "NULL");
        goto END;
    }
    TAOS_ROW row = NULL;
    while ((row = taos_fetch_row(res)) != NULL)
    {
        count++;
        int result = *(int32_t*)(row[2]);
        if (result == G100_RESULT_ADUNLOCK)
        {
            count = 0;
        }
    }
END:
    if (res != NULL) taos_free_result(res);
    return count;
}

int g100_protect_db_clear(g100_protect_t* g100_protect)
{
    char sql[512] = {0};
    sprintf(sql, TAOS_GET_DEL_G100_HISTORY_TIME, G100_DATABASE_COUNT);
    TAOS_RES* res = taos_query(g100_protect->db, sql);
    if (res == NULL || taos_errno(res) != 0)
    {
        if (res != NULL) ems_syslog(LOG_ERR, "Failed to query alarm history: %s", res ? taos_errstr(res) : "NULL");
        goto END;
    }
    TAOS_ROW row = taos_fetch_row(res);
    if (row == NULL)
    {
        goto END;
    }
    int64_t del_time = *(int64_t*)row[0];
    taos_free_result(res);
    sprintf(sql, TAOS_DE_G100L_HISTORY_SQL, del_time);
    res = taos_query(g100_protect->db, sql);
    if (res == NULL || taos_errno(res) != 0)
    {
        if (res != NULL) ems_syslog(LOG_ERR, "Failed to query alarm history: %s", res ? taos_errstr(res) : "NULL");
        goto END;
    }

END:
    if (res != NULL) taos_free_result(res);
    return 0;
}

int g100_protect_db_get_reset_count_in_30days(g100_protect_t* g100_protect)
{
    if (g100_protect->db == NULL)
    {
        return -1;
    }
    int      count     = 0;
    char     sql[1024] = {0};
    uint64_t now       = get_time_stamp_ms();
    snprintf(sql, sizeof(sql), TAOS_SELECT_G100_RECORD_30DAY, now - 259200000);
    TAOS_RES* res = taos_query(g100_protect->db, sql);
    if (res == NULL || taos_errno(res) != 0)
    {
        ems_syslog(LOG_ERR, "get g100 history data failed, err=%s", res ? taos_errstr(res) : "NULL");
        goto END;
    }
    TAOS_ROW row = NULL;
    while ((row = taos_fetch_row(res)) != NULL)
    {
        int result = *(int32_t*)(row[2]);
        if (result == G100_RESULT_UNLOCK)
        {
            count++;
        }
        else if (result == G100_RESULT_ADUNLOCK)
        {
            count = 0;
        }
    }
END:
    if (res != NULL) taos_free_result(res);
    return count;
}

#else
void* init_g100_protect_db()
{
    sqlite3* db  = NULL;
    int      ret = sqlite3_open(G100_SQLITE_DATABASE_PATH, (sqlite3**)&db);
    if (ret != SQLITE_OK)
    {
        ems_syslog(LOG_ERR, "sqlite3 open failed, ret=%d", ret);
        goto ERROR;
    }

    ret = sqlite3_exec(db, CREATE_G100_HISTORY_STB, NULL, NULL, NULL);
    if (ret != SQLITE_OK)
    {
        ems_syslog(LOG_ERR, "sqlite3 exec failed, ret=%d", ret);
        goto ERROR;
    }
    return db;

ERROR:
    if (db != NULL) sqlite3_close(db);
    return NULL;
}
// 获取数据库最后一条记录
int g100_protect_db_get_last_record(g100_protect_t* g100_protect)
{
    if (g100_protect->db == NULL)
    {
        return -1;
    }
    sqlite3_stmt* stmt;
    int ret = sqlite3_prepare_v2(g100_protect->db, TAOS_SELECT_G100_LAST_RECORD, -1, &stmt, NULL);
    if (ret != SQLITE_OK)
    {
        ems_syslog(LOG_ERR, "prepare sql failed: %s", sqlite3_errmsg(g100_protect->db));
        goto END;
    }

    if (sqlite3_step(stmt) == SQLITE_ROW)
    {
        g100_protect->start_time = sqlite3_column_int64(stmt, 0);
        g100_protect->abnormal      = sqlite3_column_int(stmt, 1);
        g100_protect->result     = sqlite3_column_int(stmt, 2);
    }
END:
    if (stmt) sqlite3_finalize(stmt);
    return ret;
}

int g100_protect_db_insert(g100_protect_t* g100_protect)
{
    if (g100_protect->db == NULL)
    {
        return -1;
    }
    char sql[1024] = {0};
    snprintf(sql, sizeof(sql), TAOS_INSERT_G100_HISTORY_STB, g100_protect->start_time, g100_protect->abnormal, g100_protect->result);
    int ret = sqlite3_exec(g100_protect->db, sql, NULL, NULL, NULL);
    if (ret != SQLITE_OK)
    {
        ems_syslog(LOG_ERR, "sqlite3 exec failed, ret=%d", ret);
    }
    return ret;
    
}

int g100_protect_db_update(g100_protect_t* g100_protect)
{
    if (g100_protect->db == NULL)
    {
        return -1;
    }
    char sql[1024] = {0};
    snprintf(sql, sizeof(sql), SQL_UPDATA_G100_HISTORY_STB, g100_protect->result, g100_protect->start_time);
    int ret = sqlite3_exec(g100_protect->db, sql, NULL, NULL, NULL);
    if (ret != SQLITE_OK)
    {
        ems_syslog(LOG_ERR, "sqlite3 exec failed, ret=%d", ret);
    }
    return ret;
}

int g100_protect_db_get_10min_count(g100_protect_t* g100_protect)
{
    if (g100_protect->db == NULL)
    {
        return -1;
    }
    int           count = 0;
    sqlite3_stmt* stmt;
    uint64_t      now       = get_time_stamp_ms();
    char          sql[1024] = {0};
    snprintf(sql, sizeof(sql), TAOS_SELECT_G100_COUNT_10MIN, now - 600000);
    int ret = sqlite3_prepare_v2(g100_protect->db, sql, -1, &stmt, NULL);
    if (ret != SQLITE_OK)
    {
        ems_syslog(LOG_ERR, "prepare sql failed: %s", sqlite3_errmsg(g100_protect->db));
        goto END;
    }
    while (sqlite3_step(stmt) == SQLITE_ROW)
    {
        count++;
        int result = sqlite3_column_int(stmt, 2);
        if (result == G100_RESULT_ADUNLOCK)
        {
            count = 0;
        }
    }
END:
    if (stmt) sqlite3_finalize(stmt);
    return count;
}

int g100_protect_db_get_day_count(g100_protect_t* g100_protect)
{
    if (g100_protect->db == NULL)
    {
        return -1;
    }
    int           count = 0;
    sqlite3_stmt* stmt;
    char          sql[1024] = {0};
    uint64_t      now       = get_time_stamp_ms();
    snprintf(sql, sizeof(sql), TAOS_SELECT_G100_COUNT_10MIN, now - 86400000);
    int ret = sqlite3_prepare_v2(g100_protect->db, sql, -1, &stmt, NULL);
    if (ret != SQLITE_OK)
    {
        ems_syslog(LOG_ERR, "prepare sql failed: %s", sqlite3_errmsg(g100_protect->db));
        goto END;
    }
    while (sqlite3_step(stmt) == SQLITE_ROW)
    {
        count++;
        int result = sqlite3_column_int(stmt, 2);
        if (result == G100_RESULT_ADUNLOCK)
        {
            count = 0;
        }
    }
END:
    if (stmt) sqlite3_finalize(stmt);
    return count;
}

int g100_protect_db_clear(g100_protect_t* g100_protect)
{
    if (g100_protect->db == NULL)
    {
        return -1;
    }
    char sql[1024] = {0};
    snprintf(sql, sizeof(sql), SQL_DEL_G100_HISTORY, G100_DATABASE_COUNT);
    int ret = sqlite3_exec(g100_protect->db, sql, NULL, NULL, NULL);
    if (ret != SQLITE_OK)
    {
        ems_syslog(LOG_ERR, "sqlite3 exec failed, ret=%d", ret);
    }
    return ret;
}

int g100_protect_db_get_reset_count_in_30days(g100_protect_t* g100_protect)
{
    if (g100_protect->db == NULL)
    {
        return -1;
    }
    int           count = 0;
    sqlite3_stmt* stmt;
    char          sql[1024] = {0};
    uint64_t      now       = get_time_stamp_ms();
    snprintf(sql, sizeof(sql), TAOS_SELECT_G100_RECORD_30DAY, now - 259200000);
    int ret = sqlite3_prepare_v2(g100_protect->db, sql, -1, &stmt, NULL);
    if (ret != SQLITE_OK)
    {
        ems_syslog(LOG_ERR, "prepare sql failed: %s", sqlite3_errmsg(g100_protect->db));
        goto END;
    }

    while (sqlite3_step(stmt) == SQLITE_ROW)
    {
        int result = sqlite3_column_int(stmt, 2);
        if (result == G100_RESULT_UNLOCK)
        {
            count++;
        }
        else if (result == G100_RESULT_ADUNLOCK)
        {
            count = 0;
        }
    }
END:
    if (stmt) sqlite3_finalize(stmt);
    return count;
}

#endif

g100_protect_t         g100_protect       = {0};
static pthread_mutex_t g100_protect_mutex = PTHREAD_MUTEX_INITIALIZER;

int g100_protect_init(g100_protect_t* g100_protect)
{
    g100_protect->db = init_g100_protect_db();
    if (g100_protect->db == NULL)
    {
        ems_syslog(LOG_ERR, "init g100_protect db failed");
        return -1;
    }

    int ret = g100_protect_db_get_last_record(g100_protect); // 获取最后一条记录
    if (ret != 0)
    {
        ems_syslog(LOG_ERR, "G100 模块获取记录失败, ret=%d", ret);
        // 获取失败
        int locked = dev_get_dev_tag_int(DEV_NO_EMS, G100_LOCK_STATE);
        if (locked) // 如果当前是锁定的, 则直接设置成异常状态, 但是可以直接解锁
        {
            g100_protect->abnormal   = dev_get_dev_tag_int(DEV_NO_EMS, G100_ABNORMAL_STATE);
            g100_protect->state      = G100_STATE_ABNORMAL;
            g100_protect->start_time = get_time_stamp_ms() - dev_get_dev_tag_int(DEV_NO_EMS, G100_UNLOCK_TIME);
            g100_protect->result     = 0;
        }
        else
        {
            g100_protect->state      = G100_STATE_NORMAL;
            g100_protect->abnormal   = G100_ABNORMAL_STATE_NONE;
            g100_protect->start_time = 0;
            g100_protect->result     = 0;
        }
    }
    else
    {
        if (g100_protect->result == G100_RESULT_LOCK || g100_protect->result == G100_RESULT_ADMIN_LOCK)
        {
            g100_protect->state = G100_STATE_LOCK;
            dev_set_dev_tag_int(DEV_NO_EMS, G100_LOCK_STATE, g100_protect->result - G100_RESULT_LOCK + 1);
            dev_set_dev_tag_int(DEV_NO_EMS, G100_ABNORMAL_STATE, g100_protect->abnormal);
        }
        else
        {
            g100_protect->abnormal   = G100_ABNORMAL_STATE_NONE;
            g100_protect->state      = G100_STATE_NORMAL;
            g100_protect->start_time = 0;
            g100_protect->result     = 0;
        }
    }
    dev_set_dev_tag_int(DEV_NO_EMS, G100_COUNT_10MIN, g100_protect_db_get_10min_count(g100_protect));
    dev_set_dev_tag_int(DEV_NO_EMS, G100_COUNT_DAY, g100_protect_db_get_day_count(g100_protect));
    dev_set_dev_tag_int(DEV_NO_EMS, G100_RESET_COUNT, g100_protect_db_get_reset_count_in_30days(g100_protect));
    return 0;
}

static int g100_protect_normal_task(g100_protect_t* g100_protect, uint64_t now)
{
    double grid_p         = dev_get_dev_tag_float(DEV_NO_GRID_MT, METER_POWER);
    double grid_s         = dev_get_dev_tag_float(DEV_NO_GRID_MT, APPARENT_POWER);  // 需量使用的视在功率;
    double backflow_limit = dev_get_dev_tag_float(DEV_NO_EMS, G100_BACKFLOW_LIMIT); // 逆流限值
    double overload_limit = dev_get_dev_tag_float(DEV_NO_EMS, G100_OVERLOAD_LIMIT); // 超载限值
    int    pmlmax         = dev_get_dev_tag_int(DEV_NO_EMS, EMS_PMLMAX);            // 变压器容量
    int en_reverse = dev_get_dev_tag_int(DEV_NO_EMS, EN_PROTECT_REVERSE);
    int en_trasformer = dev_get_dev_tag_int(DEV_NO_EMS, EN_PROTECT_TRANSF);
    if (grid_p < backflow_limit && en_reverse > 0)
    {
        // 发生逆流
        ems_syslog(LOG_WARNING, "G100模块监测到逆流, grid_p=%lf, backflow_limit=%lf", grid_p, backflow_limit);
        g100_protect->state      = G100_STATE_TO_ABNORMAL;
        g100_protect->abnormal   = G100_ABNORMAL_STATE_BACKFLOW;
        g100_protect->start_time = now;
        g100_protect->result     = 0;
    }
    else if (grid_s > overload_limit && en_trasformer > 0)
    {
        // 发生超载
        ems_syslog(LOG_WARNING, "G100模块监测到超载, grid_s=%lf, pmlmax=%d, overload_limit=%lf", grid_p, pmlmax, overload_limit);
        g100_protect->state      = G100_STATE_TO_ABNORMAL;
        g100_protect->abnormal   = G100_ABNORMAL_STATE_OVERLOAD;
        g100_protect->start_time = now;
        g100_protect->result     = 0;
    }
    return 0;
}

static int g100_protect_to_abnormal_task(g100_protect_t* g100_protect, uint64_t now)
{
    double grid_p         = dev_get_dev_tag_float(DEV_NO_GRID_MT, METER_POWER);
    double grid_s         = dev_get_dev_tag_float(DEV_NO_GRID_MT, APPARENT_POWER);  // 需量使用的视在功率;
    double backflow_limit = dev_get_dev_tag_float(DEV_NO_EMS, G100_BACKFLOW_LIMIT); // 逆流限值
    double overload_limit = dev_get_dev_tag_float(DEV_NO_EMS, G100_OVERLOAD_LIMIT); // 超载限值

    if (grid_p < backflow_limit)
    {
        int backflow_sec_limit = dev_get_dev_tag_int(DEV_NO_EMS, G100_BACKFLOW_SEC); //  逆流滤波
        if (now - g100_protect->start_time > backflow_sec_limit * 1000)
        {
            ems_syslog(LOG_WARNING, "G100模块 持续逆流超过 backflow_sec_limit=%d 秒, 本次逆流被记录", backflow_sec_limit);
            dev_set_dev_tag_int(DEV_NO_EMS, G100_ABNORMAL_STATE, G100_ABNORMAL_STATE_BACKFLOW);
            g100_protect->state      = G100_STATE_ABNORMAL;
            g100_protect->result     = 0;
            g100_protect->start_time = now;
            // 入数据库
            g100_protect_db_insert(g100_protect);
        }
    }
    else if (grid_s > overload_limit)
    {
        int overload_sec_limit = dev_get_dev_tag_int(DEV_NO_EMS, G100_OVERLOAD_SEC); // 超载时间
        if (now - g100_protect->start_time > overload_sec_limit * 1000)
        {
            ems_syslog(LOG_WARNING, "G100模块 持续超载超过 overload_sec_limit=%d 秒, 本次超载被记录", overload_sec_limit);
            dev_set_dev_tag_int(DEV_NO_EMS, G100_ABNORMAL_STATE, G100_ABNORMAL_STATE_OVERLOAD);
            g100_protect->state      = G100_STATE_ABNORMAL;
            g100_protect->result     = 0;
            g100_protect->start_time = now;
            // 入数据库
            g100_protect_db_insert(g100_protect);
        }
    }
    else
    {
        dev_set_dev_tag_int(DEV_NO_EMS, G100_ABNORMAL_STATE, G100_ABNORMAL_STATE_NONE);
        ems_syslog(LOG_WARNING, "G100模块 异常状态恢复, 本次 %s 未记录", g100_protect->abnormal == G100_ABNORMAL_STATE_BACKFLOW ? "逆流" : "超载");
        g100_protect->state      = G100_STATE_NORMAL;
        g100_protect->abnormal   = G100_ABNORMAL_STATE_NONE;
        g100_protect->result     = 0;
        g100_protect->start_time = 0;
    }

    if (g100_protect->state == G100_STATE_ABNORMAL)
    {
        double total_power = dev_get_dev_tag_float(DEV_NO_EMS, PCS_ACTIVEPOWER);
        if ((total_power < 0.1 && g100_protect->abnormal == G100_ABNORMAL_STATE_BACKFLOW) ||
            (total_power > 0.1 && g100_protect->abnormal == G100_ABNORMAL_STATE_OVERLOAD))
        {
            // 当前系统总功率为充电但是逆流, 或者是放电但是超载时, 只进入异常状态,但是不锁设备
            return 0;
        }

        int min10_count = dev_get_dev_tag_int(DEV_NO_EMS, G100_COUNT_10MIN) + 1;
        int min10_limit = dev_get_dev_tag_int(DEV_NO_EMS, G100_MAXCOUNT_10MIN); // 10 分钟内逆流次数
        if (min10_limit > 0 && min10_count > min10_limit)                      // 10分钟内出现两次异常 直接锁定
        {
            ems_syslog(LOG_WARNING, "G100模块 10 分钟内逆流次数超过 min10_limit=%d 次, 设备锁定", min10_limit);
            g100_protect->state = G100_STATE_TO_LOCK;
            return 0;
        }
        int day_count = dev_get_dev_tag_int(DEV_NO_EMS, G100_COUNT_DAY) + 1;
        int day_limit = dev_get_dev_tag_int(DEV_NO_EMS, G100_MAXCOUNT_DAY); // 1 天内逆流次数
        if (day_limit > 0 && day_count > day_limit)                     // 1天内出现4次 直接锁定
        {
            ems_syslog(LOG_WARNING, "G100模块 1 天内逆流次数超过 day_limit=%d 次, 设备锁定", day_limit);
            g100_protect->state = G100_STATE_TO_LOCK;
            return 0;
        }
    }
    return 0;
}

static int g100_protect_abnormal_task(g100_protect_t* g100_protect, uint64_t now)
{
    double backflow_limit = dev_get_dev_tag_float(DEV_NO_EMS, G100_BACKFLOW_LIMIT); // 逆流限值
    double grid_p         = dev_get_dev_tag_float(DEV_NO_GRID_MT, METER_POWER);
    double grid_s         = dev_get_dev_tag_float(DEV_NO_GRID_MT, APPARENT_POWER);  // 需量使用的视在功率;
    double overload_limit = dev_get_dev_tag_float(DEV_NO_EMS, G100_OVERLOAD_LIMIT); // 超载限值
    double total_power = dev_get_dev_tag_float(DEV_NO_EMS, PCS_ACTIVEPOWER);

    if ((total_power > 0.1 && g100_protect->abnormal == G100_ABNORMAL_STATE_BACKFLOW) ||
        (total_power < 0.1 && g100_protect->abnormal == G100_ABNORMAL_STATE_OVERLOAD))
    {
        // 当前系统总功率为放电且逆流, 或者是充电且超载时
        if (grid_p < backflow_limit && g100_protect->abnormal == G100_ABNORMAL_STATE_BACKFLOW)
        {
            int backflow_sec_lock = dev_get_dev_tag_int(DEV_NO_EMS, G100_BACKFLOW_LOCK_TIME); // 逆流达到锁定时间
            if (now - g100_protect->start_time > backflow_sec_lock * 1000)
            {
                g100_protect->state = G100_STATE_TO_LOCK;
            }
        }
        else if (grid_s > overload_limit && g100_protect->abnormal == G100_ABNORMAL_STATE_OVERLOAD)
        {
            int overload_sec_limit = dev_get_dev_tag_int(DEV_NO_EMS, G100_OVERLOAD_LOCK_TIME); // 超载到锁定时间
            if (now - g100_protect->start_time > overload_sec_limit * 1000)
            {
                g100_protect->state = G100_STATE_TO_LOCK;
            }
        }
    }

    if ((grid_p >= backflow_limit && g100_protect->abnormal == G100_ABNORMAL_STATE_BACKFLOW) || (grid_s <= overload_limit && g100_protect->abnormal == G100_ABNORMAL_STATE_OVERLOAD))
    {
        dev_set_dev_tag_int(DEV_NO_EMS, G100_ABNORMAL_STATE, G100_ABNORMAL_STATE_NONE);
        ems_syslog(LOG_WARNING, "G100模块 逆流恢复, 本次 %s 异常自动恢复, 未锁定", g100_protect->abnormal == G100_ABNORMAL_STATE_BACKFLOW ? "逆流" : "超载");
        g100_protect->state      = G100_STATE_NORMAL;
        g100_protect->abnormal   = G100_ABNORMAL_STATE_NONE;
        g100_protect->result     = 0;
        g100_protect->start_time = 0;
    }

    return 0;
}

static int g100_protect_to_lock_task(g100_protect_t* g100_protect, uint64_t now)
{
    int reset_count = dev_get_dev_tag_int(DEV_NO_EMS, G100_RESET_COUNT) + 1;
    // dev_set_dev_tag_int(DEV_NO_EMS, G100_RESET_COUNT, reset_count);
    int reset_limit = dev_get_dev_tag_int(DEV_NO_EMS, G100_MAXCOUNT_MON); 
    g100_protect->state = G100_STATE_LOCK;
    if (reset_count > reset_limit)
    {
        ems_syslog(LOG_WARNING, "G100模块 30 天内锁定次数超过 lock_limit=%d 次, 设备锁定, 本次解锁需超级管理员权限", reset_limit);
        g100_protect->result = G100_RESULT_ADMIN_LOCK;
        g100_protect_db_update(g100_protect);
        dev_set_dev_tag_int(DEV_NO_EMS, G100_LOCK_STATE, 2);
    }
    else
    {
        int min = dev_get_dev_tag_int(DEV_NO_EMS, G100_UNLOCK_TIME);
        ems_syslog(LOG_WARNING, "G100模块 30 天内锁定次数未超过 lock_limit=%d 次, 设备锁定, 请于 %d 分钟后手动解锁设备", reset_limit, min);
        g100_protect->result = G100_RESULT_LOCK;
        g100_protect_db_update(g100_protect);
        dev_set_dev_tag_int(DEV_NO_EMS, G100_LOCK_STATE, 1);
    }
    return 0;
}

int g100_protect_task(g100_protect_t* g100_protect,time_t n)
{

    dev_set_dev_tag_int(DEV_NO_EMS, G100_COUNT_10MIN, g100_protect_db_get_10min_count(g100_protect));
    dev_set_dev_tag_int(DEV_NO_EMS, G100_COUNT_DAY, g100_protect_db_get_day_count(g100_protect));
    dev_set_dev_tag_int(DEV_NO_EMS, G100_RESET_COUNT, g100_protect_db_get_reset_count_in_30days(g100_protect));
    // enable or locked
    pthread_mutex_lock(&g100_protect_mutex);
    if (dev_get_dev_tag_int(DEV_NO_EMS, G100_ENABLE) <= 0 || g100_protect->state == G100_STATE_LOCK) goto END;
    // get grid
    uint64_t now = get_time_stamp_ms();

    switch (g100_protect->state)
    {
        case G100_STATE_NORMAL:
        {
            g100_protect_normal_task(g100_protect, now);
            break;
        }
        case G100_STATE_TO_ABNORMAL:
        {
            g100_protect_to_abnormal_task(g100_protect, now);
            break;
        }
        case G100_STATE_ABNORMAL:
        {
            g100_protect_abnormal_task(g100_protect, now);
            break;
        }
        case G100_STATE_TO_LOCK:
        {
            g100_protect_to_lock_task(g100_protect, now);
            break;
        }
        default: break;
    }
END:
    pthread_mutex_unlock(&g100_protect_mutex);
    return 0;
}

int g100_protoec_unlock(g100_protect_t* g100_protect, char* result)
{
    int ret = -1;
    pthread_mutex_lock(&g100_protect_mutex);
    if (g100_protect->state != G100_STATE_LOCK)
    {
        sprintf(result, "%s", _("Failed to reset, the system is not in the reflux failed state"));
        goto END;
    }
    uint64_t now       = get_time_stamp_ms();
    int      lock_time = dev_get_dev_tag_int(DEV_NO_EMS, G100_UNLOCK_TIME);

    if (g100_protect->result == G100_RESULT_ADMIN_LOCK)
    {
        sprintf(result, "%s", _("Reset failed. Administrator privileges are required for this reset"));
        goto END;
    }
    else if (now - g100_protect->start_time > lock_time * 60 * 1000)
    {
        // 解锁
        ems_syslog(LOG_INFO, "G100模块 解锁");
        g100_protect->result = G100_RESULT_UNLOCK;
        g100_protect_db_update(g100_protect);

        dev_set_dev_tag_int(DEV_NO_EMS, G100_LOCK_STATE, 0);
        dev_set_dev_tag_int(DEV_NO_EMS, G100_ABNORMAL_STATE, 0);
        g100_protect->state      = G100_STATE_NORMAL;
        g100_protect->start_time = 0;
        g100_protect->abnormal   = G100_ABNORMAL_STATE_NONE;
        g100_protect->result     = G100_RESULT_NONE;
        sprintf(result, _("Success"));
        ret = 0;
    }
    else
    {
        ems_syslog(LOG_INFO, "G100模块 解锁失败, 请于 %d 分钟后重试", lock_time - (int)(now - g100_protect->start_time / 60000));
        char       time_buffer[128];
        time_t     t = g100_protect->start_time / 1000 + lock_time * 60 + 1;
        struct tm target_time = {};  
        localtime_r(&t, &target_time);
        struct tm *l = &target_time;
        strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S", l);
        sprintf(result, _("Cannot reset. Reset is allowed after %s"), time_buffer);
    }
END:
    pthread_mutex_unlock(&g100_protect_mutex);
    return ret;
}

int g100_protoec_admin_unlock(g100_protect_t* g100_protect, char* result)
{
    pthread_mutex_lock(&g100_protect_mutex);
    ems_syslog(LOG_INFO, "G100模块 超级管理员权限解锁, 异常状态恢复");
    if (g100_protect->state > G100_STATE_TO_ABNORMAL)
    {
        g100_protect->result = G100_RESULT_ADUNLOCK;
        g100_protect_db_update(g100_protect);
    }
    else
    {
        g100_protect_t tmp = {0};
        memcpy(&tmp, g100_protect, sizeof(g100_protect_t));
        g100_protect_db_get_last_record(&tmp);
        if (tmp.start_time > 0 && tmp.result != G100_RESULT_ADUNLOCK)
        {
            tmp.result = G100_RESULT_ADUNLOCK;
            g100_protect_db_update(&tmp);
        }
    }
    dev_set_dev_tag_int(DEV_NO_EMS, G100_RESET_COUNT, 0);
    dev_set_dev_tag_int(DEV_NO_EMS, G100_LOCK_STATE, 0);
    dev_set_dev_tag_int(DEV_NO_EMS, G100_ABNORMAL_STATE, 0);
    g100_protect->state      = G100_STATE_NORMAL;
    g100_protect->start_time = 0;
    g100_protect->abnormal   = G100_ABNORMAL_STATE_NONE;
    g100_protect->result     = G100_RESULT_NONE;
    pthread_mutex_unlock(&g100_protect_mutex);
    sprintf(result, _("Success"));
    return 0;
}
