#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <sys/syslog.h>
#include <time.h>
#include <float.h>
#include "pf_controller.h"
#include "emsctrlProc.h"
#include "deviceLayer.h"
#include "main.h"
#include "lc_discovery.h"
#include "pub_fun.h"

extern usercfg_variant_t g_usercfg_variant;
extern key_info_t key_info;

typedef struct {
    int cnt;
    int alarm_fired;
} pf_unreach_bucket_t;

static pf_unreach_bucket_t s_unreach[PF_ENTRY_MAX] = { {0, 0}, {0, 0}, {0, 0} };

/* 关口级 P_limit 请求标志（供有功下发点主动查询）
 * 无功优先超容时由 pf_grid_cap_guard 设置，有功下发点（AC/DC）下发 SET_ACT_POWER 前查询钳位
 * pf_controller 每周期入口无条件复位，避免标志残留导致有功被长期压低 */
static double s_pf_p_limit_per_cab[CABINET_NUM_MAX];
static int    s_pf_p_limit_cab_num = 0;
static int    s_pf_p_limit_active  = 0;

double pf_get_p_limit_per_cab(int idx)
{
    if (!s_pf_p_limit_active || idx < 0 || idx >= s_pf_p_limit_cab_num) {
        return -1.0;
    }
    return s_pf_p_limit_per_cab[idx];
}

static void pf_clear_p_limit_request(void)
{
    s_pf_p_limit_active = 0;
    s_pf_p_limit_cab_num = 0;
}

static void pf_log_alloc(const double *q_cab, int num, double q_sum)
{
    if (!q_cab || num <= 0) {
        return;
    }
    char buf[1024];
    int pos = 0;
    buf[0] = '\0';
    for (int i = 0; i < num && pos < (int)sizeof(buf) - 64; i++) {
        int n = snprintf(buf + pos, sizeof(buf) - pos, "PCS%d.Q=%lf, ", i + 1, q_cab[i]);
        if (n > 0) {
            pos += n;
        }
    }
    ems_syslog(LOG_INFO, "PF ADJUST:  | %s Q_sum = %lf", buf, q_sum);
}

static void pf_log_cap(double p, double q_exp, double rated_s, double q_result)
{
    ems_syslog(LOG_WARNING,
        "PF ADJUST: | Capacity exceed!!!  P=%lf, Expect:Q=%lf, Rated_S = %lf |  Result:Q = %lf",
        p, q_exp, rated_s, q_result);
}

static void pf_log_grid_cap(double grid_p, double s_max_grid, double q_sum_before, double ratio)
{
    ems_syslog(LOG_WARNING,
        "PF ADJUST: | Grid capacity exceed!!! P=%lf, S_max=Pmlmax·K1/100=%lf | Q_sum_before=%lf, shrink ratio=%.4f",
        grid_p, s_max_grid, q_sum_before, ratio);
}

static void pf_log_total(const pf_calc_result_t *r, double target_f, double dev, double q_target)
{
    if (!r) {
        return;
    }
    double q_target_total = q_target + r->grid_q;
    /* q_target 已是扣除 PV_Q 后的 PCS 需发值，还原关口期望总无功 = q_target + pv_q_total */
    ems_syslog(LOG_INFO,
        "PF ADJUST:  |  Grid:P=%lf, Q=%lf, S=%lf, PF=%lf  |  Target:PF=%lf, Δ=%lf  | "
        "Q_target_grid=%lf, Q_grid_cur=%lf, PCS_delta=%lf)",
        r->grid_p, r->grid_q, r->grid_s, r->pf_real, target_f, dev,
        q_target_total, r->grid_q, q_target);
}

static void pf_reset_unreach_counter(pf_entry_tag_t entry_tag)
{
    if (entry_tag < 0 || entry_tag >= PF_ENTRY_MAX) {
        return;
    }
    s_unreach[entry_tag].cnt = 0;
    s_unreach[entry_tag].alarm_fired = 0;
}

static int pf_update_unreach_counter(pf_entry_tag_t entry_tag)
{
    if (entry_tag < 0 || entry_tag >= PF_ENTRY_MAX) {
        return 0;
    }

    int alarm_time = dev_get_dev_tag_int(DEV_NO_EMS, PF_ADJUST_ALARM_TIME) * 60;
    int period = dev_get_dev_tag_int(DEV_NO_EMS, POWERFACTOR_ADJ_PER);
    if (period < 1) {
        period = 1;
    }

    if (alarm_time <= 0) {
        return 0;
    }
    s_unreach[entry_tag].cnt++;
    int N = alarm_time / period;
    if (N < 1) {
        N = 1;
    }

    if (s_unreach[entry_tag].cnt >= N && !s_unreach[entry_tag].alarm_fired) {
        s_unreach[entry_tag].alarm_fired = 1;
        ems_syslog(LOG_WARNING,
            "PF ADJUST: [%s]功率因数调节不到位告警：连续 %d 个周期（约 %ds）未达目标 PF=%lf±%lf",
            (entry_tag == PF_ENTRY_DC) ? "DC" :
            (entry_tag == PF_ENTRY_AC) ? "AC" : "Standard",
            N, alarm_time,
            g_usercfg_variant.PowerFactorTargetValue,
            g_usercfg_variant.PowerFactorDeviation);
        return 1;
    }
    return 0;
}

#define PF_ISFINITE(x)    isfinite(x)
#define PF_ABS(x)         fabs(x)

static int pf_scene_detect(int major_state, int control_mode)
{
    /* 使能开关必须打开 */
    if (!g_usercfg_variant.EnDynamicPowerFactorCorrection) {
        return 0;
    }
    /* 自动模式 */
    if (control_mode != EMS_AUTO_MODE) {
        return 0;
    }

    if (major_state != STATE_CONNECT_GRID) {
        return 0;
    }

    if (dev_get_dev_tag_float(DEV_NO_GRID_MT, STATE_ONLINE) == 0) {
        return -1;
    }

    if (dev_get_dev_tag_int(DEV_NO_EMS, ENPROTECTRASLV) == 1) {
        if (dev_get_dev_tag_int(DEV_NO_TRAS_LV_MT, STATE_ONLINE) == 0) {
            return -1;
        }
    }

    return 1;
}

static int pf_calc(pf_calc_result_t *out, double target_pf, double pcs_q_cur)
{
    if (!out) {
        return PF_ERR_PARAM;
    }

    /* 参数校验：F 必须在 (0,1] */
    if (target_pf <= 0.0 || target_pf > 1.0) {
        return PF_ERR_TARGET_ILLEGAL;
    }

    /* 采集关口 P/Q/S */
    out->grid_p = dev_get_dev_tag_float(DEV_NO_GRID_MT, ACTIVE_POWER);
    out->grid_q = dev_get_dev_tag_float(DEV_NO_GRID_MT, REACTIVE_POWER);
    out->grid_s = dev_get_dev_tag_float(DEV_NO_GRID_MT, APPARENT_POWER);

    if (!PF_ISFINITE(out->grid_p) || !PF_ISFINITE(out->grid_q) || !PF_ISFINITE(out->grid_s)) {
        return PF_ERR_METER_OFFLINE;
    }

    /* 计算实时功率因数：优先用关口表点位，失败则用 P/S 计算 */
    double meter_pf = dev_get_dev_tag_float(DEV_NO_GRID_MT, "PowerFactor");
    if (PF_ISFINITE(meter_pf) && PF_ABS(meter_pf) > 1e-9) {
        out->pf_real = meter_pf;
    } else if (PF_ABS(out->grid_s) > 1e-9) {
        out->pf_real = out->grid_p / out->grid_s;
    } else {
        out->pf_real = 1.0; /* 视在为0默认PF=1 */
    }

    /* 期望总无功 Q = sqrt( (1-F²)/F² × P² ) */
    double f_sq = target_pf * target_pf;
    if (f_sq < 1e-12) {
        return PF_ERR_TARGET_ILLEGAL;
    }
    double coef = (1.0 - f_sq) / f_sq;
    double p_sq = out->grid_p * out->grid_p;
    out->q_exp_total = sqrt(coef * p_sq);

    double q_target_abs = sqrt(coef * p_sq);  /* 关口目标无功绝对值 */

    /* Q_target 符号: 按 P 方向(放电发感性+, 充电发容性-) */
    double q_sign = (out->grid_p >= 0.0) ? 1.0 : -1.0;
    double q_target = q_target_abs * q_sign;

    /* PCS 目标 = 关口目标Q - 关口当前Q + PCS当前Q (闭环绝对目标)
     * 关口 Q_grid = Q_load + Q_pv + Q_pcs_cur
     * 目标: Q_load + Q_pv + Q_pcs_new = Q_target
     * => Q_pcs_new = Q_target - Q_load - Q_pv
     * => Q_pcs_new = Q_target - (Q_grid - Q_pv - Q_pcs_cur) - Q_pv
     * => Q_pcs_new = Q_target - Q_grid + Q_pcs_cur
     * 注: 关口当前Q 含 PCS 已有贡献, 需加回 Q_pcs_cur 才是 PCS 的绝对目标值,
     *     否则连续调节周期会过冲(上周期下发的Q被当作"需补偿的差额"再扣一次) */
    if (pcs_q_cur < 0.0) {
        pcs_q_cur = 0.0;
        int cab_num = dev_info_all.cabinet_info.num;
        if (cab_num > CABINET_NUM_MAX) {
            cab_num = CABINET_NUM_MAX;
        }
        for (int i = 0; i < cab_num; i++) {
            cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];
            if (cab && cab->cab_data.on_line != 0) {
                pcs_q_cur += cab->cab_data.pcs_output_repower;
            }
        }
    }
    out->q_exp_total = q_target - out->grid_q + pcs_q_cur;

    if (!PF_ISFINITE(out->q_exp_total)) {
        return PF_ERR_NAN_INF;
    }
    return PF_OK;
}

int pf_controller(double *q_target_total, time_t *last_adjust,
                  int major_state, int control_mode, pf_entry_tag_t entry_tag, double pcs_q_cur)
{
    if (!q_target_total || !last_adjust) {
        return PF_ERR_PARAM;
    }
    if (entry_tag < 0 || entry_tag >= PF_ENTRY_MAX) {
        return PF_ERR_PARAM;
    }

    *q_target_total = 0.0;

    /* 每周期入口无条件清除 P_limit 请求标志，避免残留导致有功被长期压低。
     * 若本周期关口超容(无功优先)，pf_grid_cap_guard 会重新置位 */
    pf_clear_p_limit_request();

    /* 场景识别 */
    int scene = pf_scene_detect(major_state, control_mode);
    if (scene <= 0) {
        /* 不允许调节（使能关/手动模式/离网），此处不清零Q——由调用方统一在非PF_OK时清零 */
        *q_target_total = 0.0;
        return PF_ERR_NO_ADJUST;
    }

    double F = g_usercfg_variant.PowerFactorTargetValue;
    double D = g_usercfg_variant.PowerFactorDeviation;

    /* 回差 D 校验 */
    if (D < 0.0 || D >= 1.0 || (F - D) <= 0.0 || (F + D) > 1.0) {
        return PF_ERR_DEVIATION_ILLEGAL;
    }

    /* 计算实时 PF 与期望无功 */
    pf_calc_result_t calc;
    int rc = pf_calc(&calc, F, pcs_q_cur);
    if (rc != PF_OK) {
        return rc;
    }

    /* 死区判定：|f - F| <= D 不调节 */
    double diff = PF_ABS(calc.pf_real - F);
    if (diff <= D) {
        pf_reset_unreach_counter(entry_tag);
        return PF_ERR_NO_ADJUST;
    }

    /* 节流判定：周期不到不调节 */
    time_t now = time(NULL);
    int period = g_usercfg_variant.PowerFactorAdjustmentPeriod;
    if (period < 1) {
        period = 1;
    }
    if ((now - *last_adjust) < period) {
        return PF_ERR_NO_ADJUST;
    }

    /* === 有/无功优先级说明 ===
     * EnReactivePriority 配置项仅在"关口表超出视在功率"时用于选择先降有功还是先降无功：
     *   - 柜内超容 pf_cap_guard：一律钳位 Q=√(R²-P²) 保 P（PCS 硬件极限，无法改 P）
     *   - 关口超容 pf_grid_cap_guard：按优先级分流
     *     =0(有功优先): 缩减 Q 保 P
     *     =1(无功优先): 保留 Q，按 P_limit=√(S_max²-Q²) 等比分配各柜 P_limit 到全局数组，
     *                   由有功下发点(AC cabinet_loop/DC micro_dev_model)查询 pf_get_p_limit_per_cab() 钳位
     * 非超容阶段两种优先级完全等价，统一按 Q_exp 全量补偿。
     */
    double q_exp = calc.q_exp_total;

    *q_target_total = q_exp;
    *last_adjust = now;

    /* 更新不到位计数器（本周期实际仍不达标） */
    (void)pf_update_unreach_counter(entry_tag);

    pf_log_total(&calc, F, D, q_exp);

    return PF_OK;
}

static int pf_alloc_scale(double q_total, double *q_cab, const double *cab_scales, int cab_num)
{
    if (!q_cab || !cab_scales || cab_num <= 0) {
        return PF_ERR_PARAM;
    }

    double sum_scale = 0.0;
    for (int i = 0; i < cab_num; i++) {
        if (cab_scales[i] < 0.0) {
            ems_syslog(LOG_WARNING, "cab_scales[%d] %lf < 0.0", i, cab_scales[i]);
            return PF_ERR_PARAM;
        }
        sum_scale += cab_scales[i];
    }
    if (sum_scale < 1e-9) {
        return PF_ERR_RATED_POWER;
    }

    double acc = 0.0;
    for (int i = 0; i < cab_num; i++) {
        q_cab[i] = q_total * (cab_scales[i] / sum_scale);
        acc += q_cab[i];
    }
    /* 浮点误差补偿：最后一柜吃掉残差 */
    q_cab[cab_num - 1] += (q_total - acc);
    return PF_OK;
}

int pf_cap_guard(double q_alloc, double rated_power, double act_power,
                 double *q_result, int *was_clamped)
{
    if (!q_result) {
        return PF_ERR_PARAM;
    }
    if (rated_power <= 0.0) {
        return PF_ERR_RATED_POWER;
    }

    /* Q_max = sqrt(R² - P²) */
    double r_sq = rated_power * rated_power;
    double p_sq = act_power * act_power;
    double diff = r_sq - p_sq;
    double q_max;

    if (diff <= 0.0) {
        /* 额定功率不足，完全无法带无功，Q 强制 0 */
        q_max = 0.0;
    } else {
        q_max = sqrt(diff);
    }

    /* 钳位：保留符号，按绝对值 MIN */
    double sign = (q_alloc >= 0.0) ? 1.0 : -1.0;
    double abs_q = PF_ABS(q_alloc);
    double clamped_q = (abs_q > q_max) ? q_max : abs_q;

    if (was_clamped) {
        *was_clamped = (abs_q > q_max) ? 1 : 0;
    }
    *q_result = clamped_q * sign;
    return PF_OK;
}

int pf_grid_cap_guard(double *q_cab, double *p_cab, int cab_num,
                      double grid_p, double s_max_grid, double sum_pv_p_ac)
{
    if (!q_cab || cab_num <= 0) {
        return 0;
    }
    if (s_max_grid <= 0.0) {
        return 0; /* 未配置，不做限制 */
    }

    double sum_q = 0.0;
    for (int i = 0; i < cab_num; i++) {
        sum_q += q_cab[i];
    }
    double q_sum_before = sum_q;

    double s_sq_now = grid_p * grid_p + sum_q * sum_q;
    double s_max_sq = s_max_grid * s_max_grid;
    if (s_sq_now <= s_max_sq) {
        return 0; /* 未超限 */
    }

    /* === 优先级分流 === */
    if (g_usercfg_variant.EnActivePriority == 0) {
        if (g_usercfg_variant.EnSwC2D) {
            /* 使能 C2D: 退化为有功优先, 等比例缩 Q 保 P, 不设 P_limit, 让 C2D 独占放电降 S */
            double diff_c2d = s_max_sq - grid_p * grid_p;
            double q_limit_c2d = (diff_c2d > 0.0) ? sqrt(diff_c2d) : 0.0;
            double ratio_c2d = (PF_ABS(sum_q) > 1e-9) ? (q_limit_c2d / PF_ABS(sum_q)) : 0.0;
            for (int i = 0; i < cab_num; i++) {
                q_cab[i] *= ratio_c2d;
            }
            ems_syslog(LOG_WARNING,
                "PF ADJUST: | Grid capacity exceed!!! P=%lf, S_max=%lf | "
                "EnSwC2D=1 & ReactivePriority=1, YIELD to C2D, shrink Q_sum=%lf->%lf, ratio=%lf (C2D discharge will reduce S)",
                grid_p, s_max_grid, q_sum_before, q_limit_c2d, ratio_c2d);
            return 1; /* 退化为有功优先: 已缩减 Q, 未设 P_limit */
        }

        double diff_p = s_max_sq - sum_q * sum_q;
        double p_limit_total = (diff_p > 0.0) ? sqrt(diff_p) : 0.0;
        double pcs_p_limit_total = p_limit_total - sum_pv_p_ac;
        if (pcs_p_limit_total < 0.0) {
            /* 光伏单独已超关口允许总P，PCS P_limit 全让给 PV */
            pcs_p_limit_total = 0.0;
        }
        /* 按各柜当前 P 幅值比例分配 P_limit */
        double p_sum_abs = 0.0;
        if (p_cab) {
            for (int i = 0; i < cab_num; i++) {
                p_sum_abs += PF_ABS(p_cab[i]);
            }
        }
        int n = (cab_num > CABINET_NUM_MAX) ? CABINET_NUM_MAX : cab_num;
        for (int i = 0; i < n; i++) {
            if (p_cab && p_sum_abs > 1e-9) {
                s_pf_p_limit_per_cab[i] = pcs_p_limit_total * (PF_ABS(p_cab[i]) / p_sum_abs);
            } else {
                s_pf_p_limit_per_cab[i] = pcs_p_limit_total / n; /* 无当前P数据时等分 */
            }
        }
        s_pf_p_limit_cab_num = n;
        s_pf_p_limit_active  = 1;
        ems_syslog(LOG_WARNING,
            "PF ADJUST: | Grid capacity exceed!!! P=%lf, S_max=Pmlmax·K1/100=%lf | "
           "ReactivePriority=1, keep Q_sum=%lf, P_limit_total=%lf, sum_pv_p_ac=%lf, pcs_p_limit_total=%lf (REQUEST ACTIVE-PRIORITY CLAMP)",
            grid_p, s_max_grid, q_sum_before, p_limit_total, sum_pv_p_ac, pcs_p_limit_total);
        return 2;
    }

    /* 有功优先(=1)：等比例缩减 Q，保 P（安全底线） */
    double diff = s_max_sq - grid_p * grid_p;
    double q_limit_grid = (diff > 0.0) ? sqrt(diff) : 0.0;
    double ratio = 1.0;

    if (PF_ABS(sum_q) > 1e-9) {
        ratio = q_limit_grid / PF_ABS(sum_q);
    } else {
        ratio = 0.0;
    }
    for (int i = 0; i < cab_num; i++) {
        q_cab[i] *= ratio;
    }

    pf_log_grid_cap(grid_p, s_max_grid, q_sum_before, ratio);

    return 1;
}

static int set_pcs_ctrl_chargerepower(cabinet_inside_t *cab, void *arg)
{
    if (!cab || !arg) {
        return -1;
    }
    double q_target = *(double *)arg;
    /* 复用既有 SET_REACTPOWER 写点位机制 */
    dev_set_dev_tag_float(cab->no, SET_REACTPOWER, (float)q_target);
    return 0;
}

void pf_zero_all_cabs_q(void)
{
    pf_clear_p_limit_request();

    int cab_num = dev_info_all.cabinet_info.num;
    if (cab_num > CABINET_NUM_MAX) {
        cab_num = CABINET_NUM_MAX;
    }
    for (int i = 0; i < cab_num; i++) {
        cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];
        if (cab) {
            double q_zero = 0.0;
            (void)set_pcs_ctrl_chargerepower(cab, &q_zero);
        }
    }
}

int pf_update_penalty_flag(void)
{
    double low  = g_usercfg_variant.PfAlarmLowThreshold;
    double high = g_usercfg_variant.PfAlarmHighThreshold;

    if (low >= high) {
        ems_syslog(LOG_WARNING,
            "PF ADJUST: PfAlarm阈值非法（low=%.3f >= high=%.3f），强制回退默认值 low=0.90, high=1.00",
            low, high);
        low  = 0.90;
        high = 1.00;
    }

    int flag = 0;
    double meter_pf = dev_get_dev_tag_float(DEV_NO_GRID_MT, "PowerFactor");
    if (PF_ISFINITE(meter_pf)) {
        if (meter_pf < low || meter_pf > high) {
            flag = 1;
        }
    } else {
        /* 关口点位取不到时，尝试 P/S 计算 */
        double p = dev_get_dev_tag_float(DEV_NO_GRID_MT, ACTIVE_POWER);
        double s = dev_get_dev_tag_float(DEV_NO_GRID_MT, APPARENT_POWER);
        if (PF_ISFINITE(p) && PF_ISFINITE(s) && PF_ABS(s) > 1e-9) {
            double pf = p / s;
            if (pf < low || pf > high) {
                flag = 1;
            }
        }
    }

    g_usercfg_variant.PfPenaltyFlag = flag;
    dev_set_dev_tag_int(DEV_NO_EMS, PF_PENALTY_FLAG, flag);
    return flag;
}

void pf_adjust_and_dispatch(time_t *last_adjust, pf_entry_tag_t entry_tag, double sum_pv_p_ac)
{
    double q_target_total = 0.0;
    int rc = pf_controller(&q_target_total, last_adjust,
                           STATE_CONNECT_GRID,
                           g_usercfg_variant.ControlMode,
                           entry_tag, -1.0);

    if (rc == PF_ERR_NO_ADJUST) {
        return;
    }
    if (rc != PF_OK) {
        pf_zero_all_cabs_q();
        return;
    }

    int cab_num = dev_info_all.cabinet_info.num;
    if (cab_num > CABINET_NUM_MAX) {
        cab_num = CABINET_NUM_MAX;
    }
    if (cab_num <= 0) {
        return;
    }

    double cab_scales[CABINET_NUM_MAX];
    double q_cab[CABINET_NUM_MAX];
    double rated_pw[CABINET_NUM_MAX];
    double act_pw[CABINET_NUM_MAX];
    double p_cab[CABINET_NUM_MAX];   /* 带符号各柜当前P，供关口超容降P使用 */
    for (int i = 0; i < cab_num; i++) {
        cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];
        /* 离线柜(cab==NULL或on_line==0)scale=0不参与分配，Q自动归集到在线柜 */
        int cab_online = (cab && cab->cab_data.on_line != 0) ? 1 : 0;
        cab_scales[i] = (cab_online && cab->cab_cfg.scale > 0) ? cab->cab_cfg.scale : 0.0;
        rated_pw[i] = (cab_online && cab->cab_ctrl.discharge_max_cfg > 0) ? cab->cab_ctrl.discharge_max_cfg : 0.0;
        act_pw[i] = cab_online ? fabs(cab->cab_data.pcs_output_power) : 0.0;
        p_cab[i] = cab_online ? cab->cab_data.pcs_output_power : 0.0;
    }

    (void)pf_alloc_scale(q_target_total, q_cab, cab_scales, cab_num);

    for (int i = 0; i < cab_num; i++) {
        int clamped = 0;
        double q_res = 0.0;
        if (rated_pw[i] > 0.0) {
            (void)pf_cap_guard(q_cab[i], rated_pw[i], act_pw[i], &q_res, &clamped);
            if (clamped) {
                pf_log_cap(act_pw[i], q_cab[i], rated_pw[i], q_res);
            }
        } else {
            q_res = 0.0;
        }
        q_cab[i] = q_res;
    }

    /* 关口级(HV)视在校验：S_max = Pmlmax * K1 / 100
     * 无功优先超容时 pf_grid_cap_guard 设置 P_limit 请求标志，
     * 由有功下发点（AC cabinet_loop / DC micro_dev_model 的 SET_ACT_POWER 处）
     * 主动查询钳位 */
    double grid_p = dev_get_dev_tag_float(DEV_NO_GRID_MT, ACTIVE_POWER);
    if (!isfinite(grid_p)) {
        grid_p = 0.0;
    }
    double s_max_grid = 0.0;
    if (microgrid_ctrl.Pmlmax > 0.0 && microgrid_ctrl.K1 > 0) {
        s_max_grid = microgrid_ctrl.Pmlmax * (double)microgrid_ctrl.K1 / 100.0;
    }
    if (s_max_grid > 0.0) {
        (void)pf_grid_cap_guard(q_cab, p_cab, cab_num, grid_p, s_max_grid, sum_pv_p_ac);
    }

    /* 低压侧视在校验（双变压器场景）：低压侧关口表存在且在线时额外校验
     * S_max_lv = PLVmlmax * K4 / 100；低压侧不存在时跳过，不阻断高压侧PF调节
     */
    if (dev_get_dev_tag_int(DEV_NO_EMS, ENPROTECTRASLV) == 1) {
        if (dev_get_dev_tag_int(DEV_NO_TRAS_LV_MT, STATE_ONLINE) == 1) {
            double lv_grid_p = dev_get_dev_tag_float(DEV_NO_TRAS_LV_MT, ACTIVE_POWER);
            if (!isfinite(lv_grid_p)) {
                lv_grid_p = 0.0;
            }
            double s_max_lv = 0.0;
            if (microgrid_ctrl.PLVmlmax > 0.0 && microgrid_ctrl.k4 > 0) {
                s_max_lv = microgrid_ctrl.PLVmlmax * (double)microgrid_ctrl.k4 / 100.0;
            }
            if (s_max_lv > 0.0) {
                (void)pf_grid_cap_guard(q_cab, p_cab, cab_num, lv_grid_p, s_max_lv, sum_pv_p_ac);
            }
        } else {
            pf_zero_all_cabs_q();
            (void)pf_update_penalty_flag();
            return;
        }
    }

    double q_sum = 0.0;
    for (int i = 0; i < cab_num; i++) {
        q_sum += q_cab[i];
    }
    pf_log_alloc(q_cab, cab_num, q_sum);
    for (int i = 0; i < cab_num; i++) {
        cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];
        if (cab) {
            (void)set_pcs_ctrl_chargerepower(cab, &q_cab[i]);
        }
    }
}

int pf_cap_guard_standard(double q_target, double *q_result)
{
    if (!q_result) {
        return PF_ERR_PARAM;
    }

    pcs_ctrl_var_t *var = get_pcs_ctrl_var();
    int cab_num = var->cabinet_cnt;
    if (cab_num < 1) {
        ems_syslog(LOG_WARNING, "cab num %d < 1", cab_num);
        *q_result = 0.0;
        return PF_ERR_PARAM;
    }

    double q_cab[CABINET_NUM_MAX];
    double p_cab[CABINET_NUM_MAX];
    double scales[CABINET_NUM_MAX];
    int valid_num = 0;
    char pcs_no[DEV_NAME_LEN];
    for (int i = 0; i < cab_num; i++) {
        if (i == 0) {
            snprintf(pcs_no, sizeof(pcs_no), DEV_NO_PCS);
        } else {
            snprintf(pcs_no, sizeof(pcs_no), DEV_NO_PCS "%d", i + 1);
        }
        double p_act = dev_get_dev_tag_float(pcs_no, ACTIVE_POWER);
        if (!isfinite(p_act)) {
            scales[i] = 0.0;
            p_cab[i] = 0.0;
        } else {
            scales[i] = 1.0;
            p_cab[i] = p_act;
            valid_num++;
        }
        q_cab[i] = 0.0;
    }
    if (valid_num < 1) {
        *q_result = 0.0;
        return PF_ERR_RATED_POWER;
    }

    int rc = pf_alloc_scale(q_target, q_cab, scales, cab_num);
    if (rc != PF_OK) {
        ems_syslog(LOG_WARNING, "pf_alloc_scale rc:%d", rc);
        *q_result = 0.0;
        return rc;
    }

    double rated_per_cab = fabs((double)g_usercfg_variant.dischargeThreshold) /
                           (double)valid_num;
    if (rated_per_cab <= 0.0) {
        *q_result = 0.0;
        return PF_ERR_RATED_POWER;
    }
    for (int i = 0; i < cab_num; i++) {
        if (scales[i] < 1e-9) {
            continue;
        }
        int clamped = 0;
        double q_res = 0.0;
        rc = pf_cap_guard(q_cab[i], rated_per_cab, p_cab[i], &q_res, &clamped);
        if (rc != PF_OK) {
            ems_syslog(LOG_WARNING, "pf_cap_guard rc:%d", rc);
            *q_result = 0.0;
            return rc;
        }
        if (clamped) {
            pf_log_cap(p_cab[i], q_cab[i], rated_per_cab, q_res);
        }
        q_cab[i] = q_res;
    }

    double grid_p = dev_get_dev_tag_float(DEV_NO_GRID_MT, ACTIVE_POWER);
    if (!isfinite(grid_p)) {
        grid_p = 0.0;
    }
    if (g_usercfg_variant.Pmlmax > 0 && g_usercfg_variant.K1 > 0) {
        double s_max_hv = (double)g_usercfg_variant.Pmlmax *
                          (double)g_usercfg_variant.K1 / 100.0;
        if (s_max_hv > 0.0) {
            (void)pf_grid_cap_guard(q_cab, p_cab, cab_num, grid_p, s_max_hv, 0.0);
        }
    }

    if (dev_get_dev_tag_int(DEV_NO_EMS, ENPROTECTRASLV) == 1) {
        if (dev_get_dev_tag_int(DEV_NO_TRAS_LV_MT, STATE_ONLINE) == 1) {
            double lv_grid_p = dev_get_dev_tag_float(DEV_NO_TRAS_LV_MT, ACTIVE_POWER);
            if (!isfinite(lv_grid_p)) {
                lv_grid_p = 0.0;
            }
            double s_max_lv = 0.0;
            if (microgrid_ctrl.PLVmlmax > 0.0 && microgrid_ctrl.k4 > 0) {
                s_max_lv = microgrid_ctrl.PLVmlmax * (double)microgrid_ctrl.k4 / 100.0;
            }
            if (s_max_lv > 0.0) {
                (void)pf_grid_cap_guard(q_cab, p_cab, cab_num, lv_grid_p, s_max_lv, 0.0);
            }
        } else {
            pf_zero_all_cabs_q();
            (void)pf_update_penalty_flag();
            return PF_OK;
        }
    }

    double q_sum = 0.0;
    for (int i = 0; i < cab_num; i++) {
        q_sum += q_cab[i];
    }
    *q_result = q_sum;
    return PF_OK;
}

