package com.zksy.api.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 告警等级计算工具类
 * 采用"偏离正常范围的偏差率"来定级
 * 1级最高，4级最低
 */
public class AlarmLevelUtil {

    private static final BigDecimal HUNDRED = new BigDecimal("100");
    private static final BigDecimal TEN = new BigDecimal("10");
    private static final BigDecimal THIRTY = new BigDecimal("30");
    private static final BigDecimal SIXTY = new BigDecimal("60");

    /**
     * 计算告警等级
     *
     * @param actual 实际值
     * @param min    最小值
     * @param max    最大值
     * @return 告警等级 1-4，1级最高，4级最低；若参数无效返回4级
     */
    public static int calculateLevel(BigDecimal actual, BigDecimal min, BigDecimal max) {
        BigDecimal deviationRatio = calculateDeviationRatio(actual, min, max);
        return mapToLevel(deviationRatio);
    }

    /**
     * 计算偏差率（百分比，范围0-100）
     *
     * @param actual 实际值
     * @param min    最小值
     * @param max    最大值
     * @return 偏差率百分比，例如返回 25 表示 25%
     */
    public static BigDecimal calculateDeviationRatio(BigDecimal actual, BigDecimal min, BigDecimal max) {
        // 参数校验
        if (actual == null || min == null || max == null) {
            return BigDecimal.ZERO;
        }

        BigDecimal deviation;
        BigDecimal denominator;

        // 计算偏差
        if (actual.compareTo(min) < 0) {
            // 低于下限：偏差 = min - actual
            deviation = min.subtract(actual);
        } else if (actual.compareTo(max) > 0) {
            // 高于上限：偏差 = actual - max
            deviation = actual.subtract(max);
        } else {
            // 在正常范围内，无偏差
            return BigDecimal.ZERO;
        }

        // 计算分母
        BigDecimal range = max.subtract(min);
        if (range.compareTo(BigDecimal.ZERO) != 0) {
            denominator = range;
        } else {
            // 特殊兜底：max - min 为 0 或无效
            BigDecimal maxAbs = max.abs();
            BigDecimal minAbs = min.abs();
            if (maxAbs.compareTo(BigDecimal.ZERO) > 0) {
                denominator = maxAbs;
            } else if (minAbs.compareTo(BigDecimal.ZERO) > 0) {
                denominator = minAbs;
            } else {
                // 都为 0，偏差率视为 100%
                return HUNDRED;
            }
        }

        // 计算偏差率 = (偏差 / 分母) * 100
        if (denominator.compareTo(BigDecimal.ZERO) == 0) {
            return HUNDRED;
        }

        BigDecimal ratio = deviation.divide(denominator, 4, RoundingMode.HALF_UP)
                .multiply(HUNDRED);

        // 限制在 0-100 范围内
        if (ratio.compareTo(BigDecimal.ZERO) < 0) {
            return BigDecimal.ZERO;
        }
        if (ratio.compareTo(HUNDRED) > 0) {
            return HUNDRED;
        }

        return ratio;
    }

    /**
     * 将偏差率映射到告警等级
     *
     * @param deviationRatio 偏差率（百分比）
     * @return 告警等级 1-4
     */
    private static int mapToLevel(BigDecimal deviationRatio) {
        if (deviationRatio == null) {
            return 4;
        }

        // 偏差率 < 10% → 4级
        if (deviationRatio.compareTo(TEN) < 0) {
            return 4;
        }
        // 偏差率 >= 10% 且 < 30% → 3级
        if (deviationRatio.compareTo(THIRTY) < 0) {
            return 3;
        }
        // 偏差率 >= 30% 且 < 60% → 2级
        if (deviationRatio.compareTo(SIXTY) < 0) {
            return 2;
        }
        // 偏差率 >= 60% → 1级
        return 1;
    }

    /**
     * 获取等级名称
     *
     * @param level 告警等级
     * @return 等级名称
     */
    public static String getLevelName(int level) {
        switch (level) {
            case 1:
                return "1级（紧急）";
            case 2:
                return "2级（高危）";
            case 3:
                return "3级（警告）";
            case 4:
                return "4级（提醒）";
            default:
                return "未知等级";
        }
    }
}
