#include "data_process.h"
#include "data_publish.h"

static int dev_comm_fault_calculate(uint32_t offline_cnt, uint32_t unknown_cnt, uint32_t grp_num)
{
    if(offline_cnt == grp_num || (offline_cnt + unknown_cnt == grp_num && offline_cnt > 0)) {
        return 1;
    }

    return 0;
}

static void total_data_calculate(energy_var_t *var)
{
    pthread_rwlock_rdlock(&var->lock_calcu);
    int grp_idx;
    int grp_size = var->eng_ass_grp_num;
    eng_ass_data_t tmp = {0};
    tmp.fault_level = FAULT_LEVLE_3;
    tmp.pcs_fault   = 0;
    tmp.bms_fault   = 0;
    uint32_t pcs_comm_unknown_cnt   = 0;
    uint32_t pcs_comm_offline_cnt   = 0;
    uint32_t meter_comm_unknown_cnt = 0;
    uint32_t meter_comm_offline_cnt = 0;
    uint32_t bms_comm_unknown_cnt   = 0;
    uint32_t bms_comm_offline_cnt   = 0;

    for(grp_idx = 0; grp_idx < var->eng_ass_grp_num; grp_idx++)
    {
        eng_ass_grp_t *grp = &var->grp[grp_idx];
        if(var->grp[grp_idx].eng_ass_grp_data.dev_sta.meter_online == ENG_ASS_DEV_STA_ONLINE) {
            //TODO 
            //计算电表数值
            //算数平均:电压
            //累加和:电流;功率;电量
            tmp.meter_a_current += grp->eng_ass_grp_data.meter_a_current;
            tmp.meter_a_voltage += grp->eng_ass_grp_data.meter_a_voltage;
            tmp.meter_b_current += grp->eng_ass_grp_data.meter_b_current;
            tmp.meter_b_voltage += grp->eng_ass_grp_data.meter_b_voltage;
            tmp.meter_c_current += grp->eng_ass_grp_data.meter_c_current;
            tmp.meter_c_voltage += grp->eng_ass_grp_data.meter_c_voltage;
            tmp.meter_total_power += grp->eng_ass_grp_data.meter_total_power;
        }else {
            //从PCS读数中拿到数据
        }

        if(var->grp[grp_idx].eng_ass_grp_data.dev_sta.pcs_online == ENG_ASS_DEV_STA_ONLINE){
            //TODO 
            //计算电表数值
            //算数平均:电压
            //累加和:电流;功率
            //有1置1:开机认为开机
            //有1置1:并网认为并网
            tmp.pcs_active_power += grp->eng_ass_grp_data.pcs_active_power;
            tmp.pcs_reactive_power += grp->eng_ass_grp_data.pcs_reactive_power;
            tmp.pcs_connect_state = (tmp.pcs_connect_state || grp->eng_ass_grp_data.pcs_connect_state);
            tmp.pcs_fault = (tmp.pcs_fault || grp->eng_ass_grp_data.pcs_fault);
            tmp.pcs_remote = (tmp.pcs_remote || grp->eng_ass_grp_data.pcs_remote);
            tmp.pcs_run_state = (tmp.pcs_run_state || grp->eng_ass_grp_data.pcs_run_flag);//运行状态，只要有个运行就是运行状态
        }else {

        }

        if(var->grp[grp_idx].eng_ass_grp_data.dev_sta.bms_online == ENG_ASS_DEV_STA_ONLINE){
            //TODO
            //算数平均:电压
            //有1置1:电操作状态;上高压状态
            //有一个正常:置为正常工作状态
            //算数平均:电压
            //累加和:电流
            tmp.bms_cha_discha_state = (tmp.bms_cha_discha_state || grp->eng_ass_grp_data.bms_cha_discha_state);
            tmp.bms_soc += grp->eng_ass_grp_data.bms_soc;
            tmp.bms_total_current += grp->eng_ass_grp_data.bms_total_current;
            tmp.bms_total_voltage += grp->eng_ass_grp_data.bms_total_voltage;
            tmp.bms_work_state = (tmp.bms_work_state || grp->eng_ass_grp_data.bms_work_state);
        }else {

        }

        tmp.pcs_fault = tmp.pcs_fault || var->grp[grp_idx].eng_ass_grp_data.pcs_fault;
        tmp.bms_fault = tmp.bms_fault || var->grp[grp_idx].eng_ass_grp_data.bms_fault;

        if(var->grp[grp_idx].eng_ass_grp_data.dev_sta.pcs_online == ENG_ASS_DEV_STA_UNKNOW) {
            pcs_comm_unknown_cnt++;
        }else if(var->grp[grp_idx].eng_ass_grp_data.dev_sta.pcs_online == ENG_ASS_DEV_STA_OFFLINE) {
            pcs_comm_offline_cnt++;
        }

        if(var->grp[grp_idx].eng_ass_grp_data.dev_sta.meter_online == ENG_ASS_DEV_STA_UNKNOW) {
            meter_comm_unknown_cnt++;
        }else if(var->grp[grp_idx].eng_ass_grp_data.dev_sta.meter_online == ENG_ASS_DEV_STA_OFFLINE) {
            meter_comm_offline_cnt++;
        }

        if(var->grp[grp_idx].eng_ass_grp_data.dev_sta.bms_online == ENG_ASS_DEV_STA_UNKNOW) {
            bms_comm_unknown_cnt++;
        }else if(var->grp[grp_idx].eng_ass_grp_data.dev_sta.bms_online == ENG_ASS_DEV_STA_OFFLINE) {
            bms_comm_offline_cnt++;
        }

        // if(var->grp[grp_idx].eng_ass_grp_data.fault_level < tmp.fault_level) {
        //     tmp.fault_level = var->grp[grp_idx].eng_ass_grp_data.fault_level;
        // }

        if(var->grp[grp_idx].eng_ass_grp_ctrl.connect != ENG_ASS_DATA_VALUE_INIT && var->grp[grp_idx].eng_ass_grp_data.pcs_connect_state != var->grp[grp_idx].eng_ass_grp_ctrl.connect) {
            if(var->grp[grp_idx].eng_ass_grp_data.last_conn_conflict_time == 0) {
                var->grp[grp_idx].eng_ass_grp_data.last_conn_conflict_time = time(NULL);
            }
            if (time(NULL) - var->grp[grp_idx].eng_ass_grp_data.last_conn_conflict_time > 180) {//英博pcs从0功率到待机时间为2min,统一延长
                var->grp[grp_idx].eng_ass_grp_data.pcs_conn_fb_fault = 1;
            }
        }else {
            var->grp[grp_idx].eng_ass_grp_data.last_conn_conflict_time = 0;
            var->grp[grp_idx].eng_ass_grp_data.pcs_conn_fb_fault = 0;
        }
        tmp.pcs_conn_fb_fault = tmp.pcs_conn_fb_fault || var->grp[grp_idx].eng_ass_grp_data.pcs_conn_fb_fault;

        if(var->grp[grp_idx].eng_ass_grp_ctrl.run_state != ENG_ASS_DATA_VALUE_INIT 
        &&  ((var->grp[grp_idx].eng_ass_grp_data.pcs_stop_flag != 1 && var->grp[grp_idx].eng_ass_grp_ctrl.run_state == 0)
            || ((var->grp[grp_idx].eng_ass_grp_data.pcs_run_flag != 1 && var->grp[grp_idx].eng_ass_grp_data.pcs_standby_flag != 1) && var->grp[grp_idx].eng_ass_grp_ctrl.run_state == 2))
        ) {
            if(var->grp[grp_idx].eng_ass_grp_data.last_run_conflict_time == 0) {
                var->grp[grp_idx].eng_ass_grp_data.last_run_conflict_time = time(NULL);
            }
            if (time(NULL) - var->grp[grp_idx].eng_ass_grp_data.last_run_conflict_time > 180) {//英博pcs从0功率到待机时间为2min
                var->grp[grp_idx].eng_ass_grp_data.pcs_run_fb_fault = 1;
            }
        }else {
            var->grp[grp_idx].eng_ass_grp_data.last_run_conflict_time = 0;
            var->grp[grp_idx].eng_ass_grp_data.pcs_run_fb_fault = 0;
        }
        tmp.pcs_run_fb_fault = tmp.pcs_run_fb_fault || var->grp[grp_idx].eng_ass_grp_data.pcs_run_fb_fault;
    }

    tmp.pcs_comm_fault   = dev_comm_fault_calculate(pcs_comm_offline_cnt, pcs_comm_unknown_cnt, var->eng_ass_grp_num);
    tmp.bms_comm_fault   = dev_comm_fault_calculate(bms_comm_offline_cnt, bms_comm_unknown_cnt, var->eng_ass_grp_num);
    tmp.meter_comm_fault = dev_comm_fault_calculate(meter_comm_offline_cnt, meter_comm_unknown_cnt, var->eng_ass_grp_num);

    //TODO 赋值
    //meter
    var->eng_ass_data->meter_a_current = tmp.meter_a_current;
    var->eng_ass_data->meter_a_voltage = tmp.meter_a_voltage/grp_size;
    // dbg_syslog(LOG_INFO, "voltage %f,current %f",var->eng_ass_data->meter_a_voltage,var->eng_ass_data->meter_a_current);
    var->eng_ass_data->meter_b_current = tmp.meter_b_current;
    var->eng_ass_data->meter_b_voltage = tmp.meter_b_voltage/grp_size;
    // dbg_syslog(LOG_INFO, "voltage %f,current %f",var->eng_ass_data->meter_b_voltage,var->eng_ass_data->meter_b_current);
    var->eng_ass_data->meter_c_current = tmp.meter_c_current;
    var->eng_ass_data->meter_c_voltage = tmp.meter_c_voltage/grp_size;
    // dbg_syslog(LOG_INFO, "voltage %f,current %f",var->eng_ass_data->meter_c_voltage,var->eng_ass_data->meter_c_current);
    
    var->eng_ass_data->meter_total_power = tmp.meter_total_power;
    // dbg_syslog(LOG_INFO, "meter_total_power %f",var->eng_ass_data->meter_total_power);
    
    //pcs
    var->eng_ass_data->pcs_active_power = tmp.pcs_active_power;
    var->eng_ass_data->pcs_reactive_power = tmp.pcs_reactive_power;
    // dbg_syslog(LOG_INFO, "active_power %f,reactive_power %f",var->eng_ass_data->pcs_active_power,var->eng_ass_data->pcs_reactive_power);
    //var->eng_ass_data->pcs_connect_state = tmp.pcs_connect_state;//发离网的问题不需要汇聚数据
    var->eng_ass_data->pcs_fault = tmp.pcs_fault;
    var->eng_ass_data->pcs_remote = tmp.pcs_remote;
    var->eng_ass_data->pcs_run_state = tmp.pcs_run_state;
    // dbg_syslog(LOG_INFO, "connect_state %f,fault %f,remote %f,run_state %f",var->eng_ass_data->pcs_connect_state,var->eng_ass_data->pcs_fault = tmp.pcs_fault,var->eng_ass_data->pcs_remote = tmp.pcs_remote,var->eng_ass_data->pcs_run_state = tmp.pcs_run_state);

    //bms
    var->eng_ass_data->bms_cha_discha_state = tmp.bms_cha_discha_state;
    var->eng_ass_data->bms_soc = tmp.bms_soc/grp_size;
    var->eng_ass_data->bms_total_current = tmp.bms_total_current;
    var->eng_ass_data->bms_total_voltage = tmp.bms_total_voltage;
    // dbg_syslog(LOG_INFO, "active_power %f,reactive_power %f,soc %f",var->eng_ass_data->bms_total_current,var->eng_ass_data->bms_total_voltage,var->eng_ass_data->bms_soc);
    var->eng_ass_data->bms_work_state = tmp.bms_work_state;
    // dbg_syslog(LOG_INFO, "bms_cha_discha_state %f,bms_work_state %f",var->eng_ass_data->bms_cha_discha_state,var->eng_ass_data->bms_work_state);
    var->eng_ass_data->pcs_fault         = tmp.pcs_fault;
    var->eng_ass_data->bms_fault         = tmp.bms_fault;
    // var->eng_ass_data->fault_level       = tmp.fault_level;
    var->eng_ass_data->pcs_conn_fb_fault = tmp.pcs_conn_fb_fault;
    var->eng_ass_data->pcs_run_fb_fault  = tmp.pcs_run_fb_fault;
    var->eng_ass_data->pcs_comm_fault    = tmp.pcs_comm_fault;
    var->eng_ass_data->bms_comm_fault    = tmp.bms_comm_fault;
    var->eng_ass_data->meter_comm_fault  = tmp.meter_comm_fault;
    pthread_rwlock_unlock(&var->lock_calcu);

}

static void devs_online_state_calculate(energy_var_t *var)
{
    pthread_rwlock_rdlock(&var->lock_calcu);
    int i;
    time_t last_pcs_recv_time = 0;
    time_t last_meter_recv_time = 0;
    time_t last_bms_recv_time = 0;
    time_t now = time(NULL);

    for(i = 0; i < var->eng_ass_grp_num; i++) {
        last_pcs_recv_time = var->grp[i].eng_ass_grp_data.pcs_recv_time;
        last_meter_recv_time = var->grp[i].eng_ass_grp_data.meter_recv_time;
        last_bms_recv_time = var->grp[i].eng_ass_grp_data.bms_recv_time;

        // dbg_syslog(LOG_INFO, "last_pcs_recv_time   : %d\n", last_pcs_recv_time);
        // dbg_syslog(LOG_INFO, "last_meter_recv_time : %d\n", last_meter_recv_time);
        // dbg_syslog(LOG_INFO, "last_bms_recv_time   : %d\n", last_bms_recv_time);
        // dbg_syslog(LOG_INFO, "now                  : %d\n", now);
        if(last_pcs_recv_time == 0) {
            var->grp[i].eng_ass_grp_data.dev_sta.pcs_online = ENG_ASS_DEV_STA_UNKNOW;
        }else {
            if(now - last_pcs_recv_time > var->dev_online_timeout) {
                var->grp[i].eng_ass_grp_data.dev_sta.pcs_online = ENG_ASS_DEV_STA_OFFLINE;
            } else {
                var->grp[i].eng_ass_grp_data.dev_sta.pcs_online = ENG_ASS_DEV_STA_ONLINE;
            }
        }

        if(last_meter_recv_time == 0) {
            var->grp[i].eng_ass_grp_data.dev_sta.meter_online = ENG_ASS_DEV_STA_UNKNOW;
        }else {
            if(now - last_meter_recv_time > var->dev_online_timeout) {
                var->grp[i].eng_ass_grp_data.dev_sta.meter_online = ENG_ASS_DEV_STA_OFFLINE;
            } else {
                var->grp[i].eng_ass_grp_data.dev_sta.meter_online = ENG_ASS_DEV_STA_ONLINE;
            }
        }

        if(last_bms_recv_time == 0) {
            var->grp[i].eng_ass_grp_data.dev_sta.bms_online = ENG_ASS_DEV_STA_UNKNOW;
        }else {
            if(now - last_bms_recv_time > var->dev_online_timeout) {
                var->grp[i].eng_ass_grp_data.dev_sta.bms_online = ENG_ASS_DEV_STA_OFFLINE;
            } else {
                var->grp[i].eng_ass_grp_data.dev_sta.bms_online = ENG_ASS_DEV_STA_ONLINE;
            }
        }
    }
    pthread_rwlock_unlock(&var->lock_calcu);
}

static void group_fault_level_calculate(energy_var_t *var)
{
    pthread_rwlock_rdlock(&var->lock_calcu);
    int i = 0;
    bool fault_level_1 = false;
    bool fault_level_2 = false;
    bool fault_level_3 = false;

    for(i = 0; i < var->eng_ass_grp_num; i++) {
        // if (var->grp[i].eng_ass_grp_data.dev_sta.bms_online == ENG_ASS_DEV_STA_OFFLINE) {
        //     fault_level_1 = true;
        // }else {
        //     fault_level_1 = false;
        // }
        if (var->grp[i].eng_ass_grp_data.dev_sta.bms_online == ENG_ASS_DEV_STA_OFFLINE ||
            var->grp[i].eng_ass_grp_data.dev_sta.pcs_online == ENG_ASS_DEV_STA_OFFLINE ||
            var->grp[i].eng_ass_grp_data.pcs_fault != 0 ||
            var->grp[i].eng_ass_grp_data.bms_fault != 0)
        {
            fault_level_2 = true;
        }else {
            fault_level_2 = false;
        }

        if (fault_level_3) {
            var->grp[i].eng_ass_grp_data.fault_level = ENG_ASS_PROTECT_FAULT_3;

            continue;
        }
        if (fault_level_2) {
            var->grp[i].eng_ass_grp_data.fault_level = ENG_ASS_PROTECT_FAULT_2;;
            continue;
        }
        if (fault_level_1) {
            var->grp[i].eng_ass_grp_data.fault_level = ENG_ASS_PROTECT_FAULT_1;
            continue;
        }

        var->grp[i].eng_ass_grp_data.fault_level = ENG_ASS_PROTECT_FAULT_NONE;
        
    }
    //快卜增加
    int total_fault_level = 0;
    for(i = 0; i < var->eng_ass_grp_num; i++) {
        total_fault_level = MIN(total_fault_level,var->grp[i].eng_ass_grp_data.fault_level);
    }
    var->eng_ass_data->fault_level = total_fault_level;
    pthread_rwlock_unlock(&var->lock_calcu);
}

void *data_process_loop(void *param)
{
    energy_var_t *var = param;
    while (1)
    {
        //data_report_meter(var);
        data_report_vpcs(var);
        data_report_protect_level(var);
        devs_online_state_calculate(var);
        group_fault_level_calculate(var);
        total_data_calculate(var);
        data_report_fault(var);
        //data_report_to_station_control(var);
        data_report_all_pcs(var);
        sleep(1);
    }
}

int data_process_init(energy_var_t *var)
{
    pthread_rwlock_init(&var->lock_calcu, NULL);
    /* 创建一个单独的线程, 专用于执行aiot_mqtt_process, 它会自动发送心跳保活, 以及重发QoS1的未应答报文 */
    int res = pthread_create(&var->thread_calcu, NULL, data_process_loop, var);
    if (res < 0) {
        dbg_syslog(LOG_WARNING, "failed to created pthread for data process %s\n", strerror(errno));
        return -1;
    }
    return 0;
}
