package com.ruoyi.web.modules.industryservice.support;

import java.math.BigDecimal;
import java.math.RoundingMode;
import com.ruoyi.web.modules.industryservice.domain.dto.GrassLivestockBalanceCalculateRequest;
import com.ruoyi.web.modules.industryservice.domain.vo.GrassLivestockBalanceResultVo;

/**
 * 草畜平衡纯计算（无持久化）。
 */
public final class GrassLivestockBalanceCalculator
{
    private static final BigDecimal ZERO = BigDecimal.ZERO;

    private static final BigDecimal ONE = BigDecimal.ONE;

    private static final BigDecimal HUNDRED = new BigDecimal("100");

    private GrassLivestockBalanceCalculator()
    {
    }

    public static GrassLivestockBalanceResultVo calculate(GrassLivestockBalanceCalculateRequest request,
            String grasslandName)
    {
        BigDecimal availableForageKg = request.getAreaMu()
                .multiply(request.getGrassYieldPerMu())
                .multiply(request.getUtilizationRate());
        BigDecimal theoreticalCarryingSu = availableForageKg.divide(
                request.getSheepUnitAnnualForageKg(), GrassLivestockBalanceRules.SCALE + 4,
                RoundingMode.HALF_UP);
        BigDecimal actualCarryingSu = request.getSheepUnitConvertCoeff()
                .multiply(new BigDecimal(request.getBreedingHeadCount()));

        GrassLivestockBalanceResultVo result = new GrassLivestockBalanceResultVo();
        result.setGrasslandId(request.getGrasslandId());
        result.setGrasslandName(grasslandName);
        result.setAvailableForageKg(scale2(availableForageKg));
        result.setTheoreticalCarryingSu(scale2(theoreticalCarryingSu));
        result.setActualCarryingSu(scale2(actualCarryingSu));

        if (theoreticalCarryingSu.compareTo(ZERO) == 0)
        {
            handleZeroTheoretical(request, result, availableForageKg, actualCarryingSu);
            return result;
        }

        BigDecimal balanceIndex = actualCarryingSu.divide(theoreticalCarryingSu, GrassLivestockBalanceRules.SCALE + 4,
                RoundingMode.HALF_UP);
        BigDecimal overloadRateRatio = balanceIndex.subtract(ONE);
        BigDecimal overloadRatePercent = overloadRateRatio.multiply(HUNDRED);

        result.setBalanceIndex(scale2(balanceIndex));
        result.setOverloadRate(scale2(overloadRatePercent));
        result.setOverloadSu(scale2(actualCarryingSu.subtract(theoreticalCarryingSu)));
        BigDecimal annualDemand = actualCarryingSu.multiply(request.getSheepUnitAnnualForageKg());
        result.setAnnualForageDemandKg(scale2(annualDemand));
        result.setForageGapKg(scale2(annualDemand.subtract(availableForageKg)));
        BigDecimal suitableHeads = theoreticalCarryingSu.divide(request.getSheepUnitConvertCoeff(),
                GrassLivestockBalanceRules.SCALE, RoundingMode.HALF_UP);
        result.setTheoreticalSuitableHeads(suitableHeads);
        result.setActualOverloadHeads(resolveActualOverloadHeads(request.getBreedingHeadCount(), suitableHeads));

        int level = resolveBalanceLevel(overloadRateRatio);
        result.setBalanceLevel(level);
        result.setBalanceLevelName(resolveBalanceLevelName(level));
        return result;
    }

    private static void handleZeroTheoretical(GrassLivestockBalanceCalculateRequest request,
            GrassLivestockBalanceResultVo result, BigDecimal availableForageKg, BigDecimal actualCarryingSu)
    {
        result.setTheoreticalCarryingSu(scale2(ZERO));
        result.setOverloadSu(scale2(actualCarryingSu));
        result.setAnnualForageDemandKg(scale2(actualCarryingSu.multiply(request.getSheepUnitAnnualForageKg())));
        result.setForageGapKg(scale2(result.getAnnualForageDemandKg().subtract(availableForageKg)));
        result.setTheoreticalSuitableHeads(scale2(ZERO));
        result.setActualOverloadHeads(0);

        if (request.getBreedingHeadCount() > 0)
        {
            result.setBalanceIndex(null);
            result.setOverloadRate(null);
            result.setBalanceLevel(GrassLivestockBalanceRules.BALANCE_LEVEL_SEVERE);
            result.setBalanceLevelName(resolveBalanceLevelName(GrassLivestockBalanceRules.BALANCE_LEVEL_SEVERE));
            result.setWarning("无饲草供给");
        }
        else
        {
            result.setBalanceIndex(scale2(ZERO));
            result.setOverloadRate(scale2(new BigDecimal("-100")));
            result.setBalanceLevel(GrassLivestockBalanceRules.BALANCE_LEVEL_NOT_OVERLOAD);
            result.setBalanceLevelName(resolveBalanceLevelName(GrassLivestockBalanceRules.BALANCE_LEVEL_NOT_OVERLOAD));
        }
    }

    public static int resolveBalanceLevel(BigDecimal overloadRateRatio)
    {
        BigDecimal r = overloadRateRatio.setScale(GrassLivestockBalanceRules.RATE_COMPARE_SCALE, RoundingMode.HALF_UP);
        if (r.compareTo(ZERO) <= 0)
        {
            return GrassLivestockBalanceRules.BALANCE_LEVEL_NOT_OVERLOAD;
        }
        if (r.compareTo(GrassLivestockBalanceRules.RATE_THRESHOLD_BASIC) <= 0)
        {
            return GrassLivestockBalanceRules.BALANCE_LEVEL_BASIC;
        }
        if (r.compareTo(GrassLivestockBalanceRules.RATE_THRESHOLD_OVERLOAD) <= 0)
        {
            return GrassLivestockBalanceRules.BALANCE_LEVEL_OVERLOAD;
        }
        return GrassLivestockBalanceRules.BALANCE_LEVEL_SEVERE;
    }

    public static String resolveBalanceLevelName(int level)
    {
        switch (level)
        {
            case GrassLivestockBalanceRules.BALANCE_LEVEL_BASIC:
                return "基本平衡";
            case GrassLivestockBalanceRules.BALANCE_LEVEL_OVERLOAD:
                return "超载";
            case GrassLivestockBalanceRules.BALANCE_LEVEL_SEVERE:
                return "严重超载";
            case GrassLivestockBalanceRules.BALANCE_LEVEL_NOT_OVERLOAD:
            default:
                return "未超载";
        }
    }

    public static int resolveActualOverloadHeads(int breedingHeadCount, BigDecimal theoreticalSuitableHeads)
    {
        BigDecimal diff = new BigDecimal(breedingHeadCount).subtract(theoreticalSuitableHeads);
        if (diff.compareTo(ZERO) <= 0)
        {
            return 0;
        }
        return diff.setScale(0, RoundingMode.HALF_UP).intValue();
    }

    public static BigDecimal scale2(BigDecimal value)
    {
        if (value == null)
        {
            return null;
        }
        return value.setScale(GrassLivestockBalanceRules.SCALE, RoundingMode.HALF_UP);
    }
}
