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

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import com.ruoyi.web.modules.industryservice.domain.dto.BreedingIndustryYakSnapshot;
import com.ruoyi.web.modules.industryservice.domain.vo.BreedingIndustryAgeBandVo;
import com.ruoyi.web.modules.industryservice.domain.vo.BreedingIndustryDegradationStatVo;
import com.ruoyi.web.modules.industryservice.support.BreedingIndustryCalculator;
import com.ruoyi.web.modules.industryservice.support.BreedingIndustryRules;
import com.ruoyi.web.modules.industryservice.support.GrasslandRules;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenAppointmentStatDto;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenHerdCowAgeSumDto;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenHerdGenderMonthDto;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenMonthCountDto;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenYearMonthBullCowDto;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenYearMonthCountDto;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenSubsidyTypeSumDto;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenTrainingMonthDto;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenAgeBandVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenAppointmentMonthVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenAppointmentVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenAgriClassroomVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenDegradationStatVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenGrasslandVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenInventoryMonthVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenOutboundMonthVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenStandardListItemVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenSubsidyTypeStatVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenSubsidyVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenTrainingMonthVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenTrainingTrendVo;

/**
 * 大屏首页口径组装与纯计算（无 DB / HTTP 依赖，便于单测）。
 * <p>
 * 核心约定：{@link #resolveStatDate(int)} 决定统计截止日；当年未到的月份在趋势类方法中补 0。
 */
public final class HomeScreenSupport
{
    private static final DateTimeFormatter STAT_DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    private static final String[] DEGRADATION_LABELS = {
            "", "未退化", "轻度", "中度", "重度", "极重度"
    };

    private static final int PROVIDER_VET = 1;

    private static final int PROVIDER_ORG = 2;

    private static final int PROVIDER_EXPERT = 3;

    /** 母牛分龄 bandCode（存栏填报口径：0-1.5 / 1.5+） */
    public static final String BAND_COW_YOUNG = "COW_YOUNG";

    public static final String BAND_COW_ADULT = "COW_ADULT";

    public static final String LABEL_COW_YOUNG = "0～1.5岁幼畜";

    public static final String LABEL_COW_ADULT = "1.5岁以上成畜";

    /** @deprecated 旧四档常量保留避免外部硬编码编译失败，大屏已切两档 */
    @Deprecated
    public static final String BAND_COW_UNDER_1 = BAND_COW_YOUNG;

    @Deprecated
    public static final String BAND_COW_1_3 = "COW_1_3";

    @Deprecated
    public static final String BAND_COW_3_12 = "COW_3_12";

    @Deprecated
    public static final String BAND_COW_OVER_12 = "COW_O12";

    @Deprecated
    public static final String LABEL_COW_UNDER_1 = LABEL_COW_YOUNG;

    @Deprecated
    public static final String LABEL_COW_1_3 = "1～3岁";

    @Deprecated
    public static final String LABEL_COW_3_12 = "3～12岁";

    @Deprecated
    public static final String LABEL_COW_OVER_12 = "12岁以上";

    private static final Map<String, String> STANDARD_TYPE_NAMES;

    static
    {
        Map<String, String> map = new HashMap<>();
        map.put("001001", "繁育作业");
        map.put("001002", "饲养工作");
        map.put("001003", "免疫程序");
        map.put("001004", "环境调控");
        map.put("001005", "饲料配方");
        map.put("001006", "牦牛投喂");
        map.put("001007", "设备操作");
        map.put("001008", "设备保养");
        map.put("001009", "设备排障");
        map.put("001010", "设备维修");
        map.put("001011", "牦牛生长");
        map.put("001012", "牦牛出栏");
        map.put("001013", "疾病决策");
        STANDARD_TYPE_NAMES = Collections.unmodifiableMap(map);
    }

    private HomeScreenSupport()
    {
    }

    /**
     * 统计截止日：当前年取上海时区今天，历史年取 12-31。
     * 所有大屏模块的年区间 [{@code yearStart}, {@code yearEnd}] 均依赖此方法。
     */
    public static LocalDate resolveStatDate(int statYear)
    {
        LocalDate today = LocalDate.now(ZoneId.of(BreedingIndustryRules.ZONE_SHANGHAI));
        if (statYear == today.getYear())
        {
            return today;
        }
        return LocalDate.of(statYear, 12, 31);
    }

    public static String formatStatDate(LocalDate statDate)
    {
        return statDate.format(STAT_DATE_FMT);
    }

    /** 截止 statDate 月末仍计入存栏的牦牛数量（复用养殖产业快照口径）。 */
    public static int countInventoryAtDate(List<BreedingIndustryYakSnapshot> assets, LocalDate statDate)
    {
        int count = 0;
        for (BreedingIndustryYakSnapshot asset : assets)
        {
            if (BreedingIndustryCalculator.countsAtMonthEnd(asset, statDate))
            {
                count++;
            }
        }
        return count;
    }

    public static int[] countGenderAtDate(List<BreedingIndustryYakSnapshot> assets, LocalDate statDate)
    {
        int bull = 0;
        int cow = 0;
        for (BreedingIndustryYakSnapshot asset : assets)
        {
            if (!BreedingIndustryCalculator.countsAtMonthEnd(asset, statDate))
            {
                continue;
            }
            String gender = BreedingIndustryCalculator.normalizeGender(asset.getGender());
            if (BreedingIndustryRules.GENDER_BULL.equals(gender))
            {
                bull++;
            }
            else if (BreedingIndustryRules.GENDER_COW.equals(gender))
            {
                cow++;
            }
        }
        return new int[] { bull, cow };
    }

    /**
     * 公母牛月度存栏趋势；当前年未来月份填 0。
     *
     * @return 长度 12 的列表，{@code month} 为 1～12
     */
    public static List<HomeScreenInventoryMonthVo> buildBullCowMonthlyTrend(
            List<BreedingIndustryYakSnapshot> assets, LocalDate statDate)
    {
        List<HomeScreenInventoryMonthVo> points = new ArrayList<>();
        int statYear = statDate.getYear();
        int futureAfter = statDate.getMonthValue();
        for (int month = 1; month <= 12; month++)
        {
            HomeScreenInventoryMonthVo point = new HomeScreenInventoryMonthVo();
            point.setMonth(month);
            if (statYear == LocalDate.now(ZoneId.of(BreedingIndustryRules.ZONE_SHANGHAI)).getYear()
                    && month > futureAfter)
            {
                point.setBullCount(0);
                point.setCowCount(0);
            }
            else
            {
                LocalDate monthEnd = BreedingIndustryCalculator.resolveMonthEnd(statYear, month, statDate);
                int bull = 0;
                int cow = 0;
                for (BreedingIndustryYakSnapshot asset : assets)
                {
                    if (!BreedingIndustryCalculator.countsAtMonthEnd(asset, monthEnd))
                    {
                        continue;
                    }
                    String gender = BreedingIndustryCalculator.normalizeGender(asset.getGender());
                    if (BreedingIndustryRules.GENDER_BULL.equals(gender))
                    {
                        bull++;
                    }
                    else if (BreedingIndustryRules.GENDER_COW.equals(gender))
                    {
                        cow++;
                    }
                }
                point.setBullCount(bull);
                point.setCowCount(cow);
            }
            points.add(point);
        }
        return points;
    }

    /** 距 anchor 月（含）向前共 12 个自然月的 yyyyMM 键。 */
    public static int yearMonthKey(YearMonth ym)
    {
        return ym.getYear() * 100 + ym.getMonthValue();
    }

    /** 当前上海时区年月，作为「最近 12 个月」窗口右端点。 */
    public static YearMonth currentYearMonth()
    {
        return YearMonth.now(ZoneId.of(BreedingIndustryRules.ZONE_SHANGHAI));
    }

    /** 成果/趋势类 stat_period 格式 {@code yyyy-MM}。 */
    public static String formatStatPeriod(YearMonth ym)
    {
        return String.format("%04d-%02d", ym.getYear(), ym.getMonthValue());
    }

    /**
     * 滚动 12 月窗口结束日：当前月取今天，历史月取该月最后一天（上海时区）。
     */
    public static LocalDate rolling12MonthWindowEnd(YearMonth anchor)
    {
        ZoneId zone = ZoneId.of(BreedingIndustryRules.ZONE_SHANGHAI);
        if (anchor.equals(YearMonth.now(zone)))
        {
            return LocalDate.now(zone);
        }
        return anchor.atEndOfMonth();
    }

    /**
     * 存栏变动：最近 12 个月公母牛合计趋势（按时间升序，含 {@code statYear}、{@code month}）。
     */
    public static List<HomeScreenInventoryMonthVo> buildRolling12MonthBullCowTrend(
            List<HomeScreenYearMonthBullCowDto> rows, YearMonth anchor)
    {
        Map<Integer, HomeScreenYearMonthBullCowDto> byYm = new HashMap<>();
        if (rows != null)
        {
            for (HomeScreenYearMonthBullCowDto row : rows)
            {
                if (row.getStatYear() != null && row.getStatMonth() != null)
                {
                    byYm.put(yearMonthKey(YearMonth.of(row.getStatYear(), row.getStatMonth())), row);
                }
            }
        }
        List<HomeScreenInventoryMonthVo> points = new ArrayList<>();
        YearMonth start = anchor.minusMonths(11);
        for (int slot = 0; slot < 12; slot++)
        {
            YearMonth ym = start.plusMonths(slot);
            HomeScreenYearMonthBullCowDto src = byYm.get(yearMonthKey(ym));
            HomeScreenInventoryMonthVo point = new HomeScreenInventoryMonthVo();
            point.setStatYear(ym.getYear());
            point.setMonth(ym.getMonthValue());
            point.setBullCount(src != null && src.getBullCount() != null ? src.getBullCount() : 0);
            point.setCowCount(src != null && src.getCowCount() != null ? src.getCowCount() : 0);
            points.add(point);
        }
        return points;
    }

    /**
     * 出栏统计：最近 12 个月牦牛出栏合计（按时间升序，含 {@code statYear}、{@code month}）。
     */
    public static List<HomeScreenOutboundMonthVo> buildRolling12MonthOutbound(
            List<HomeScreenYearMonthCountDto> rows, YearMonth anchor)
    {
        Map<Integer, Integer> byYm = new HashMap<>();
        if (rows != null)
        {
            for (HomeScreenYearMonthCountDto row : rows)
            {
                if (row.getStatYear() != null && row.getStatMonth() != null && row.getCount() != null)
                {
                    byYm.put(yearMonthKey(YearMonth.of(row.getStatYear(), row.getStatMonth())), row.getCount());
                }
            }
        }
        List<HomeScreenOutboundMonthVo> list = new ArrayList<>();
        YearMonth start = anchor.minusMonths(11);
        for (int slot = 0; slot < 12; slot++)
        {
            YearMonth ym = start.plusMonths(slot);
            HomeScreenOutboundMonthVo vo = new HomeScreenOutboundMonthVo();
            vo.setStatYear(ym.getYear());
            vo.setMonth(ym.getMonthValue());
            vo.setOutboundCount(byYm.getOrDefault(yearMonthKey(ym), 0));
            list.add(vo);
        }
        return list;
    }

    /**
     * 线下服务预约：最近 12 个月堆叠柱（按时间升序，含 {@code statYear}、{@code month}）。
     */
    public static List<HomeScreenAppointmentMonthVo> buildRolling12MonthAppointmentStacked(
            List<HomeScreenAppointmentStatDto> rows, YearMonth anchor)
    {
        Map<Integer, Map<Integer, Integer>> byYmAndType = new HashMap<>();
        if (rows != null)
        {
            for (HomeScreenAppointmentStatDto row : rows)
            {
                if (row.getStatYear() != null && row.getStatMonth() != null && row.getProviderType() != null)
                {
                    int key = yearMonthKey(YearMonth.of(row.getStatYear(), row.getStatMonth()));
                    byYmAndType.computeIfAbsent(key, k -> new HashMap<>())
                            .put(row.getProviderType(), row.getCount() != null ? row.getCount() : 0);
                }
            }
        }
        List<HomeScreenAppointmentMonthVo> stacked = new ArrayList<>();
        YearMonth start = anchor.minusMonths(11);
        for (int slot = 0; slot < 12; slot++)
        {
            YearMonth ym = start.plusMonths(slot);
            Map<Integer, Integer> types = byYmAndType.getOrDefault(yearMonthKey(ym), Collections.emptyMap());
            HomeScreenAppointmentMonthVo point = new HomeScreenAppointmentMonthVo();
            point.setStatYear(ym.getYear());
            point.setMonth(ym.getMonthValue());
            point.setVetCount(types.getOrDefault(PROVIDER_VET, 0));
            point.setExpertCount(types.getOrDefault(PROVIDER_EXPERT, 0));
            point.setOrgCount(types.getOrDefault(PROVIDER_ORG, 0));
            stacked.add(point);
        }
        return stacked;
    }

    /**
     * 实战培训报名：最近 12 个月活动数/报名人数（按时间升序，含 {@code statYear}、{@code month}）。
     */
    public static List<HomeScreenTrainingMonthVo> buildRolling12MonthTraining(
            List<HomeScreenTrainingMonthDto> rows, YearMonth anchor)
    {
        Map<Integer, HomeScreenTrainingMonthDto> byYm = new HashMap<>();
        if (rows != null)
        {
            for (HomeScreenTrainingMonthDto row : rows)
            {
                if (row.getStatYear() != null && row.getStatMonth() != null)
                {
                    byYm.put(yearMonthKey(YearMonth.of(row.getStatYear(), row.getStatMonth())), row);
                }
            }
        }
        List<HomeScreenTrainingMonthVo> monthly = new ArrayList<>();
        YearMonth start = anchor.minusMonths(11);
        for (int slot = 0; slot < 12; slot++)
        {
            YearMonth ym = start.plusMonths(slot);
            HomeScreenTrainingMonthDto src = byYm.get(yearMonthKey(ym));
            HomeScreenTrainingMonthVo point = new HomeScreenTrainingMonthVo();
            point.setStatYear(ym.getYear());
            point.setMonth(ym.getMonthValue());
            point.setActivityCount(src != null && src.getActivityCount() != null ? src.getActivityCount() : 0);
            point.setEnrolledCount(src != null && src.getEnrolledCount() != null ? src.getEnrolledCount() : 0);
            monthly.add(point);
        }
        return monthly;
    }

    /**
     * 公母牛月度存栏趋势（存栏填报表 {@code bull_total}/{@code cow_total} 全县按月合计）；当前年未来月份填 0。
     */
    public static List<HomeScreenInventoryMonthVo> buildBullCowMonthlyTrendFromHerdReport(
            List<HomeScreenHerdGenderMonthDto> rows, LocalDate statDate)
    {
        Map<Integer, HomeScreenHerdGenderMonthDto> byMonth = new HashMap<>();
        if (rows != null)
        {
            for (HomeScreenHerdGenderMonthDto row : rows)
            {
                if (row.getMonth() != null)
                {
                    byMonth.put(row.getMonth(), row);
                }
            }
        }
        int statYear = statDate.getYear();
        int futureAfter = statDate.getMonthValue();
        boolean currentYear = statYear == LocalDate.now(ZoneId.of(BreedingIndustryRules.ZONE_SHANGHAI)).getYear();
        List<HomeScreenInventoryMonthVo> points = new ArrayList<>();
        for (int month = 1; month <= 12; month++)
        {
            HomeScreenInventoryMonthVo point = new HomeScreenInventoryMonthVo();
            point.setMonth(month);
            if (currentYear && month > futureAfter)
            {
                point.setBullCount(0);
                point.setCowCount(0);
            }
            else
            {
                HomeScreenHerdGenderMonthDto src = byMonth.get(month);
                point.setBullCount(src != null && src.getBullCount() != null ? src.getBullCount() : 0);
                point.setCowCount(src != null && src.getCowCount() != null ? src.getCowCount() : 0);
            }
            points.add(point);
        }
        return points;
    }

    /** 母牛分龄结构（存栏填报两档）；接口字段 bandCode/bandLabel/count/ratio 不变。 */
    public static List<HomeScreenAgeBandVo> buildCowAgeStructureFromHerdReport(HomeScreenHerdCowAgeSumDto sums)
    {
        int young = safeInt(sums != null ? sums.getCowYoungCount() : null);
        int adult = safeInt(sums != null ? sums.getCowAdultCount() : null);
        int total = young + adult;
        List<HomeScreenAgeBandVo> result = new ArrayList<>();
        result.add(cowAgeBandVo(BAND_COW_YOUNG, LABEL_COW_YOUNG, young, total));
        result.add(cowAgeBandVo(BAND_COW_ADULT, LABEL_COW_ADULT, adult, total));
        return result;
    }

    private static HomeScreenAgeBandVo cowAgeBandVo(String code, String label, int count, int total)
    {
        HomeScreenAgeBandVo vo = new HomeScreenAgeBandVo();
        vo.setBandCode(code);
        vo.setBandLabel(label);
        vo.setCount(count);
        vo.setRatio(BreedingIndustryCalculator.ratioPercent(count, total));
        return vo;
    }

    private static int safeInt(Integer value)
    {
        return value != null ? value : 0;
    }

    public static List<HomeScreenAgeBandVo> buildAgeStructureAtDate(
            List<BreedingIndustryYakSnapshot> assets, LocalDate statDate)
    {
        Map<String, Integer> bandCounts = new HashMap<>();
        bandCounts.put(BreedingIndustryRules.BAND_M1_6, 0);
        bandCounts.put(BreedingIndustryRules.BAND_M7_12, 0);
        bandCounts.put(BreedingIndustryRules.BAND_M13_PLUS, 0);
        int total = 0;
        for (BreedingIndustryYakSnapshot asset : assets)
        {
            if (!BreedingIndustryCalculator.countsAtMonthEnd(asset, statDate))
            {
                continue;
            }
            total++;
            String band = BreedingIndustryCalculator.bandCodeOf(
                    BreedingIndustryCalculator.resolveAgeMonths(asset, statDate));
            bandCounts.put(band, bandCounts.get(band) + 1);
        }
        List<BreedingIndustryAgeBandVo> breedingBands =
                BreedingIndustryCalculator.buildAgeStructure(bandCounts, total);
        List<HomeScreenAgeBandVo> result = new ArrayList<>();
        for (BreedingIndustryAgeBandVo band : breedingBands)
        {
            HomeScreenAgeBandVo vo = new HomeScreenAgeBandVo();
            vo.setBandCode(band.getBandCode());
            vo.setBandLabel(band.getBandLabel());
            vo.setCount(band.getCount());
            vo.setRatio(band.getRatio());
            result.add(vo);
        }
        return result;
    }

    public static List<HomeScreenOutboundMonthVo> buildOutboundMonthly(
            List<HomeScreenMonthCountDto> rows, LocalDate statDate)
    {
        Map<Integer, Integer> byMonth = new HashMap<>();
        if (rows != null)
        {
            for (HomeScreenMonthCountDto row : rows)
            {
                if (row.getMonth() != null && row.getCount() != null)
                {
                    byMonth.put(row.getMonth(), row.getCount());
                }
            }
        }
        int futureAfter = statDate.getMonthValue();
        boolean currentYear = statDate.getYear()
                == LocalDate.now(ZoneId.of(BreedingIndustryRules.ZONE_SHANGHAI)).getYear();
        List<HomeScreenOutboundMonthVo> list = new ArrayList<>();
        for (int month = 1; month <= 12; month++)
        {
            HomeScreenOutboundMonthVo vo = new HomeScreenOutboundMonthVo();
            vo.setMonth(month);
            if (currentYear && month > futureAfter)
            {
                vo.setOutboundCount(0);
            }
            else
            {
                vo.setOutboundCount(byMonth.getOrDefault(month, 0));
            }
            list.add(vo);
        }
        return list;
    }

    public static HomeScreenGrasslandVo buildGrasslandVo(
            int grasslandTotal, int availableCount, int inUseCount,
            List<BreedingIndustryDegradationStatVo> grouped)
    {
        Map<Integer, Integer> countByLevel = new HashMap<>();
        if (grouped != null)
        {
            for (BreedingIndustryDegradationStatVo row : grouped)
            {
                countByLevel.put(row.getDegradationLevel(), row.getCount());
            }
        }
        List<HomeScreenDegradationStatVo> stats = new ArrayList<>();
        for (int level = GrasslandRules.DEGRADATION_NONE; level <= GrasslandRules.DEGRADATION_EXTREME; level++)
        {
            int count = countByLevel.getOrDefault(level, 0);
            HomeScreenDegradationStatVo stat = new HomeScreenDegradationStatVo();
            stat.setDegradationLevel(level);
            stat.setDegradationLabel(DEGRADATION_LABELS[level]);
            stat.setCount(count);
            stat.setRatio(BreedingIndustryCalculator.ratioPercent(count, grasslandTotal));
            stats.add(stat);
        }
        HomeScreenGrasslandVo vo = new HomeScreenGrasslandVo();
        vo.setAvailableCount(availableCount);
        vo.setInUseCount(inUseCount);
        vo.setDegradationStats(stats);
        return vo;
    }

    public static HomeScreenAppointmentVo buildAppointment(
            List<HomeScreenAppointmentStatDto> annualRows,
            List<HomeScreenAppointmentStatDto> rollingMonthlyRows,
            YearMonth anchor)
    {
        int vet = 0;
        int expert = 0;
        int org = 0;
        if (annualRows != null)
        {
            for (HomeScreenAppointmentStatDto row : annualRows)
            {
                int c = row.getCount() != null ? row.getCount() : 0;
                if (row.getProviderType() != null)
                {
                    if (row.getProviderType() == PROVIDER_VET)
                    {
                        vet = c;
                    }
                    else if (row.getProviderType() == PROVIDER_EXPERT)
                    {
                        expert = c;
                    }
                    else if (row.getProviderType() == PROVIDER_ORG)
                    {
                        org = c;
                    }
                }
            }
        }
        HomeScreenAppointmentVo vo = new HomeScreenAppointmentVo();
        vo.setAnnualVetCount(vet);
        vo.setAnnualExpertCount(expert);
        vo.setAnnualOrgCount(org);
        vo.setMonthlyStacked(buildRolling12MonthAppointmentStacked(rollingMonthlyRows, anchor));
        return vo;
    }

    /** 按 {@code biz_subsidy_grant_record.subsidy_type} 汇总金额（万元），无记录时 hasSubsidyData=false。 */
    public static HomeScreenSubsidyVo buildSubsidy(List<HomeScreenSubsidyTypeSumDto> sums, boolean hasSubsidyData)
    {
        Map<Integer, BigDecimal> amountByType = new HashMap<>();
        if (sums != null)
        {
            for (HomeScreenSubsidyTypeSumDto row : sums)
            {
                if (row.getSubsidyType() != null && row.getAmountSum() != null)
                {
                    amountByType.put(row.getSubsidyType(), row.getAmountSum());
                }
            }
        }
        List<HomeScreenSubsidyTypeStatVo> stats = new ArrayList<>();
        stats.add(subsidyTypeStat(1, "农业生产", amountByType.get(1)));
        stats.add(subsidyTypeStat(2, "住房基建", amountByType.get(2)));
        stats.add(subsidyTypeStat(3, "民生保障", amountByType.get(3)));
        HomeScreenSubsidyVo vo = new HomeScreenSubsidyVo();
        vo.setHasSubsidyData(hasSubsidyData);
        vo.setTypeStats(stats);
        return vo;
    }

    public static BigDecimal toAmountWan(BigDecimal amountYuan)
    {
        if (amountYuan == null)
        {
            return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
        }
        return amountYuan.divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP);
    }

    public static HomeScreenAgriClassroomVo buildAgriClassroom(int videoCount, int trainingCount)
    {
        HomeScreenAgriClassroomVo vo = new HomeScreenAgriClassroomVo();
        vo.setVideoCourseCount(videoCount);
        vo.setPracticalTrainingCount(trainingCount);
        vo.setTrainingContentTotal(videoCount + trainingCount);
        vo.setHasAgriData(videoCount > 0 || trainingCount > 0);
        return vo;
    }

    public static HomeScreenTrainingTrendVo buildTrainingTrend(
            List<HomeScreenTrainingMonthDto> rollingRows, boolean hasTrainingData, YearMonth anchor)
    {
        List<HomeScreenTrainingMonthVo> monthly = buildRolling12MonthTraining(rollingRows, anchor);
        if (!hasTrainingData)
        {
            for (HomeScreenTrainingMonthVo point : monthly)
            {
                point.setActivityCount(0);
                point.setEnrolledCount(0);
            }
        }
        HomeScreenTrainingTrendVo vo = new HomeScreenTrainingTrendVo();
        vo.setHasTrainingData(hasTrainingData);
        vo.setMonthly(monthly);
        return vo;
    }

    /** 合并各数据源年份并降序，始终包含当前年供前端年份切换。 */
    public static List<Integer> buildAvailableYears(List<Integer>... yearLists)
    {
        Set<Integer> set = new TreeSet<>(Collections.reverseOrder());
        int currentYear = LocalDate.now(ZoneId.of(BreedingIndustryRules.ZONE_SHANGHAI)).getYear();
        set.add(currentYear);
        if (yearLists != null)
        {
            for (List<Integer> list : yearLists)
            {
                if (list != null)
                {
                    set.addAll(list);
                }
            }
        }
        return new ArrayList<>(set);
    }

    public static void enrichStandardTypeNames(List<HomeScreenStandardListItemVo> rows)
    {
        if (rows == null)
        {
            return;
        }
        for (HomeScreenStandardListItemVo row : rows)
        {
            String code = row.getStandardType();
            row.setStandardTypeName(STANDARD_TYPE_NAMES.getOrDefault(code, code));
        }
    }

    private static HomeScreenSubsidyTypeStatVo subsidyTypeStat(int type, String name, BigDecimal amountYuan)
    {
        HomeScreenSubsidyTypeStatVo stat = new HomeScreenSubsidyTypeStatVo();
        stat.setSubsidyType(type);
        stat.setSubsidyTypeName(name);
        stat.setAmountWan(toAmountWan(amountYuan));
        return stat;
    }
}
