#include "power_manage.h"
#include "collector-api.h"
#include "../adapter/pe_adapter.h"
#include "define.h"
#include "pub_fun.h"
#include "deviceLayer.h"
#include <semaphore.h>
extern void *get_tag_value_point_by_name(const char *name, int type);

typedef struct lc_cab
{
    const int *on_off;              // 开关机
    const int *prohibite_cha;       // 禁充
    const int *prohibite_disc;      // 禁放
    const int *status;              // 状态
    const double *set_power;        // 设置的功率
    const double *limit_power;      // 功率功率
    const int *en_bsm_limit;        // 使能bms功率限制
    const double *bms_max_chrge;    // bms最大充电
    const double *bms_max_dischrge; // bms最大放电
    const double *max_soc;
    const double *min_soc;
    //
    const int *dod_cha;       // DOD禁充
    const int *dod_disc;      // DOD禁放
    time_t start_0_power_time; // 0功率开始时间
    double exp_powert;         // 期望功率
    //
    sem_t write_sem;//信号量
} lc_cab;

lc_cab lc_info;

static double get_bms_max_charge_power(char *bms_no)
{
    double vol = 0;
    double cur = 0;
    if ((dev_get_dev_tag_float_with_result(bms_no, RACK_VOLTAGE, &vol) == 0) &&
        (dev_get_dev_tag_float_with_result(bms_no, RACK_MAX_CHARGE_CUR, &cur) == 0))
    {
        return ((vol * cur) / 1000);
    }
    else
    {
        return 0;
    }
}

static double get_bms_max_discharge_power(char *bms_no)
{
    double vol = 0;
    double cur = 0;
    if ((dev_get_dev_tag_float_with_result(bms_no, RACK_VOLTAGE, &vol) == 0) &&
        (dev_get_dev_tag_float_with_result(bms_no, RACK_MAX_DISCHA_CUR, &cur) == 0))
    {
        return ((vol * cur) / 1000);
    }
    else
    {
        return 0;
    }
}

static void update_bms_power_limit(void)
{
    double p = get_bms_max_charge_power(DEV_NO_BMS);
    dev_set_dev_tag_float(DEV_NO_LC, MAX_CHARGE_POWER, p);
    p = get_bms_max_discharge_power(DEV_NO_BMS);
    dev_set_dev_tag_float(DEV_NO_LC, MAX_DISCHA_POWER, p);
}

static double get_bms_soc(char *bms_no)
{
    double soc = 0;
    if (dev_get_dev_tag_float_with_result(bms_no, CURRENT_SOC, &soc) == 0)
    {
        return soc;
    }
    else
        return 0;
}

static void update_other_param(void)
{
    double soc = get_bms_soc(DEV_NO_BMS);
    dev_set_dev_tag_float(DEV_NO_LC, GET_SOC, soc);

    int onoff = pe_get_onoff(DEV_NO_PCS);
    dev_set_dev_tag_int(DEV_NO_LC, GET_ON_OFF, onoff);

    int connect = pe_get_connect(DEV_NO_PCS);
    dev_set_dev_tag_int(DEV_NO_LC, GET_CONNECT, connect);

    double act_power = 0;
    pe_get_power(DEV_NO_PCS, &act_power);
    dev_set_dev_tag_float(DEV_NO_LC, GET_ACT_POWER, act_power);

    double act_repower = 0;
    pe_get_repower(DEV_NO_PCS, &act_repower);
    dev_set_dev_tag_float(DEV_NO_LC, GET_REACTPOWER, act_repower);
}

static int man_init(lc_cab *this_p)
{
    this_p->on_off = get_tag_value_point_by_name(DEV_NO_LC "." ON_OFF_STATE, 0);
    if (this_p->on_off == NULL)
    {
        return -1;
    }
    this_p->status = get_tag_value_point_by_name(DEV_NO_LC "." SYSTEM_STATUS, 0);
    if (this_p->status == NULL)
    {
        return -2;
    }
    this_p->prohibite_cha = get_tag_value_point_by_name(DEV_NO_LC "." PROHIBITE_CHARGE, 0);
    if (this_p->prohibite_cha == NULL)
    {
        return -3;
    }
    this_p->prohibite_disc = get_tag_value_point_by_name(DEV_NO_LC "." PROHIBITE_DISCHARGE, 0);
    if (this_p->prohibite_disc == NULL)
    {
        return -4;
    }
    this_p->set_power = get_tag_value_point_by_name(DEV_NO_LC "." SET_ACT_POWER, 1);
    if (this_p->set_power == NULL)
    {
        return -5;
    }
    this_p->limit_power = get_tag_value_point_by_name(DEV_NO_LC "." POWER_LIMIT, 1);
    if (this_p->limit_power == NULL)
    {
        return -6;
    }
    this_p->en_bsm_limit = get_tag_value_point_by_name(DEV_NO_LC "." BMS_POWER_LIMIT, 0);
    if (this_p->en_bsm_limit == NULL)
    {
        return -7;
    }

    this_p->bms_max_chrge = get_tag_value_point_by_name(DEV_NO_LC "." MAX_CHARGE_POWER, 1);
    if (this_p->bms_max_chrge == NULL)
    {
        return -8;
    }

    this_p->bms_max_dischrge = get_tag_value_point_by_name(DEV_NO_LC "." MAX_DISCHA_POWER, 1);
    if (this_p->bms_max_dischrge == NULL)
    {
        return -9;
    }

    this_p->dod_cha = get_tag_value_point_by_name(DEV_NO_LC "." DOD_LIMITED_CH, 0);
    if (this_p->dod_cha == NULL)
    {
        return -10;
    }

    this_p->dod_disc = get_tag_value_point_by_name(DEV_NO_LC "." DOD_LIMITED_DC, 0);
    if (this_p->dod_disc == NULL)
    {
        return -11;
    }

    if (sem_init(&this_p->write_sem, 0, 0) < 0)
    {
        return -12;
    }

    this_p->max_soc = get_tag_value_point_by_name(DEV_NO_LC "." EMS_SOCMAX, 1);
    if (this_p->max_soc == NULL)
    {
        return -13;
    }

    this_p->min_soc = get_tag_value_point_by_name(DEV_NO_LC "." EMS_SOCMIN, 1);
    if (this_p->min_soc == NULL)
    {
        return -14;
    }

    return 0;
}

static int check_charge_discharge_status(lc_cab *this_p, double set_power)
{
#if 0 // 有回差了，就不在这儿检查禁充禁放了
    if (IS_CHARGE(set_power))
    {
        if (*(this_p->min_soc) > dev_get_dev_tag_int(DEV_NO_BMS, CURRENT_SOC))
        {
            return 0;
        }
        
        if (*(this_p->prohibite_disc) != 0)
        {
            dev_set_dev_tag_int(DEV_NO_LC, PROHIBITE_DISCHARGE, 0); // 清除禁放
        }
        if (*(this_p->dod_disc) != 0)
        {
            dev_set_dev_tag_int(DEV_NO_LC, DOD_LIMITED_DC, 0);
        }
    }
    else if (IS_DISCHARGE(set_power))
    {
        if (*(this_p->max_soc) < dev_get_dev_tag_int(DEV_NO_BMS, CURRENT_SOC))
        {
            return 0;
        }
        
        if (*(this_p->prohibite_cha) != 0)
        {
            dev_set_dev_tag_int(DEV_NO_LC, PROHIBITE_CHARGE, 0); // 清除禁充
        }
        if (*(this_p->dod_cha) != 0)
        {
            dev_set_dev_tag_int(DEV_NO_LC, DOD_LIMITED_CH, 0);
        }
    }
    else
    {
    }
#endif
    if ((*(this_p->prohibite_disc) != 0) && (*(this_p->prohibite_cha) != 0)) // 解决禁充禁放都触发的情况
    {
        int state = 0x00;
        if (get_lc_stop_discharge_tab() != 0)
        {
            state |= 0x01;
        }

        if (get_lc_stop_charge_tab() != 0)
        {
            state |= 0x02;
        }

        switch (state)
        {
        case 0x00:
            dev_set_dev_tag_int(DEV_NO_LC, PROHIBITE_CHARGE, 0);
            dev_set_dev_tag_int(DEV_NO_LC, PROHIBITE_DISCHARGE, 0);
            break;

        case 0x01: // 有禁放无禁充
            dev_set_dev_tag_int(DEV_NO_LC, PROHIBITE_CHARGE, 0);
            break;

        case 0x02: // 有禁充无禁放
            dev_set_dev_tag_int(DEV_NO_LC, PROHIBITE_DISCHARGE, 0);
        default:
            break;
        }
    }
    return 0;
}

static double power_limit(lc_cab *this_p)
{
    double set_power = 0;
    double tmp = 0;
    //
    if (*(this_p->status) == 0) // 系统正常
    {
        set_power = *(this_p->set_power);
        check_charge_discharge_status(this_p, set_power);
        if (IS_CHARGE(set_power))
        {
            if (*(this_p->prohibite_cha) != 0)
            {
                ems_syslog(LOG_ERR, "系统禁充导致期望功率，请检查BMS的SOC和过压告警");
                set_power = 0;
            }
            else
            {
                if (*(this_p->en_bsm_limit) != 0)
                {
                    tmp = 0 - *(this_p->bms_max_chrge);
                    if (set_power < tmp)
                    {
                        ems_syslog(LOG_ERR, "BMS限制功率，当前BMS最大可充功率为%.2f", *(this_p->bms_max_chrge));
                        set_power = tmp;
                    }
                }
                //
                tmp = 0 - *(this_p->limit_power);
                if (set_power < tmp)
                {
                    ems_syslog(LOG_ERR, "限制功率，限制功率为%.2f", tmp);
                    set_power = tmp;
                }
            }
        }
        else if (IS_DISCHARGE(set_power))
        {
            if (*(this_p->prohibite_disc) != 0)
            {
                ems_syslog(LOG_ERR, "系统禁充导致期望功率，请检查BMS的SOC和过压告警");
                set_power = 0;
            }
            else
            {
                if (*(this_p->en_bsm_limit) != 0)
                {
                    tmp = *(this_p->bms_max_dischrge);
                    if (set_power > tmp)
                    {
                        ems_syslog(LOG_ERR, "BMS限制功率，当前BMS最大可放功率为%.2f", *(this_p->bms_max_dischrge));
                        set_power = tmp;
                    }
                }
                //
                tmp = *(this_p->limit_power);
                if (set_power > tmp)
                {
                    ems_syslog(LOG_ERR, "限制功率，限制功率为%.2f", tmp);
                    set_power = tmp;
                }
            }
        }
        else
        {
            set_power = 0;
        }

        
    }
    else
    {
        ems_syslog(LOG_ERR, "系统状态异常，功率写0，请查看系统状态字确认系统异常原因");
        set_power = 0;
    }

    this_p->exp_powert = set_power;
    ems_syslog(LOG_NOTICE, "set_power=%f,exp_powert=%f,prohibite_cha=%d,prohibite_disc=%d,status=%d", *(this_p->set_power), this_p->exp_powert, *(this_p->prohibite_cha), *(this_p->prohibite_disc), *(this_p->status));
    return set_power;
}

static int power_sync(lc_cab *this_p)
{
    power_limit(this_p);
    dev_set_dev_tag_float(DEV_NO_LC, EXPECT_ACT_POWER, this_p->exp_powert);
    //
    int onoff = pe_get_onoff(DEV_NO_PCS);
    if (onoff >= 0)
    {
        if (IS_IDLE(this_p->exp_powert))
        {
            if (dev_get_dev_tag_int(DEV_NO_LC, PCS_AUTO_TURN) != 0) // 使能自动关机
            {
                if (this_p->start_0_power_time == 0)
                {
                    this_p->start_0_power_time = time(NULL);
                }
                else
                {
                    int time_interval = dev_get_dev_tag_int(DEV_NO_LC, PCS_AUTO_TURN_OFF_TIME);
                    if (onoff == PE_ADP_ON)
                    {
                        pe_set_power(DEV_NO_PCS, this_p->exp_powert);
                        if (time(NULL) - this_p->start_0_power_time >= time_interval)
                        {
                            pe_set_onoff(DEV_NO_PCS, PE_ADP_OFF);
                        }
                    }
                }
                return 0;
            }
        }
        //
        this_p->start_0_power_time = 0;
        if ((!(IS_IDLE(this_p->exp_powert))) && (onoff == PE_ADP_OFF)) // 没有开机
        {
            if (pe_set_onoff(DEV_NO_PCS, PE_ADP_ON) != 0)
            {
                ems_syslog(LOG_ERR, "设置PCS开关机失败");
            }
        }
        if (0 != pe_set_power(DEV_NO_PCS, this_p->exp_powert))
        {
            ems_syslog(LOG_ERR, "设置PCS功率失败");
        }
    }
    else
    {
        ems_syslog(LOG_ERR, "获取%s开关机状态错误", DEV_NO_PCS);
    }

    return 0;
}


int sem_timedwait_power_update(int timeout_ms)
{
    struct timespec now;
    struct timespec wt;
    if (clock_gettime(CLOCK_REALTIME, &now) != 0)
    {
        ems_syslog(LOG_ERR, "clock_gettime error");
    }
    wt.tv_sec = now.tv_sec + timeout_ms / 1000;
    wt.tv_nsec = now.tv_nsec + (timeout_ms % 1000) * 1000 * 1000;
    if (wt.tv_nsec >= 1000000000)
    {
        wt.tv_nsec -= 1000000000;
        wt.tv_sec += 1;
    }
    if (sem_timedwait(&lc_info.write_sem, &wt) < 0)
    {
        int err = errno;
        if (ETIMEDOUT != err)
        {
            ems_syslog(LOG_ERR, "sem_timedwait error,%d[%s]", err, strerror(err));
            return -1;
        }
        else
        {
            ems_syslog(LOG_NOTICE, "sem_timedwait,%d[%s]", err, strerror(err));
        }
    }
    return 0;
}


void *lc_power_manage(void *args)
{
    if (0 != man_init(&lc_info))
    {
        ems_syslog(LOG_ERR, "main init error");
        exit(-999);
    }

    while (1)
    {
        sem_timedwait_power_update(1000);
        ems_syslog(LOG_NOTICE, "lc_power_manage loop");
        update_bms_power_limit();
        update_other_param();
        check_ems_offline();
        power_sync(&lc_info);
        
    }
}
int sem_post_power_update(void)
{
    if (0 != sem_post(&lc_info.write_sem))
    {
        ems_syslog(LOG_ERR, "sem_post error");
        return -1;
    }
    return 0;
}

LC_CHARGE_DISCHARGE_STATUS get_lc_charge_discharge_status(void)
{
    double power = *(lc_info.set_power);
    if (IS_CHARGE(power))
    {
        return LC_IS_CHARGE;
    }
    else if (IS_DISCHARGE(power))
    {
        return LC_IS_DISCHARGE;
    }
    else
    {
        return LC_IS_IDLE;
    }
}