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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.YearMonth;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import com.ruoyi.web.modules.industryservice.domain.dto.BreedingIndustryYakSnapshot;
import com.ruoyi.web.modules.industryservice.support.BreedingIndustryRules;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenAppointmentStatDto;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenAppointmentStatDto;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenMonthCountDto;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenTrainingMonthDto;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenAgriClassroomVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenAppointmentVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenAgeBandVo;
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.HomeScreenSubsidyVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenTrainingTrendVo;

/**
 * DP-SY-UT-003～018
 */
@DisplayName("HomeScreenSupport")
class HomeScreenSupportTest
{

    @Test
    @DisplayName("DP-SY-UT-004 历史年 statDate 为 12-31")
    void ut004_historicalStatDate()
    {
        assertEquals(LocalDate.of(2024, 12, 31), HomeScreenSupport.resolveStatDate(2024));
    }

    @Test
    @DisplayName("DP-SY-UT-005c 最近12个月存栏趋势")
    void ut005c_rolling12MonthBullCow()
    {
        YearMonth anchor = YearMonth.of(2026, 7);
        com.ruoyi.web.modules.screen.domain.dto.HomeScreenYearMonthBullCowDto row =
                new com.ruoyi.web.modules.screen.domain.dto.HomeScreenYearMonthBullCowDto();
        row.setStatYear(2026);
        row.setStatMonth(7);
        row.setBullCount(100);
        row.setCowCount(200);
        List<HomeScreenInventoryMonthVo> trend = HomeScreenSupport.buildRolling12MonthBullCowTrend(
                Collections.singletonList(row), anchor);
        assertEquals(12, trend.size());
        assertEquals(2026, trend.get(11).getStatYear());
        assertEquals(7, trend.get(11).getMonth());
        assertEquals(100, trend.get(11).getBullCount());
        assertEquals(200, trend.get(11).getCowCount());
        assertEquals(2025, trend.get(0).getStatYear());
        assertEquals(8, trend.get(0).getMonth());
        assertEquals(0, trend.get(0).getBullCount());
    }

    @Test
    @DisplayName("DP-SY-UT-007b 最近12个月出栏")
    void ut007b_rolling12MonthOutbound()
    {
        YearMonth anchor = YearMonth.of(2026, 7);
        com.ruoyi.web.modules.screen.domain.dto.HomeScreenYearMonthCountDto row =
                new com.ruoyi.web.modules.screen.domain.dto.HomeScreenYearMonthCountDto();
        row.setStatYear(2026);
        row.setStatMonth(5);
        row.setCount(88);
        List<HomeScreenOutboundMonthVo> list = HomeScreenSupport.buildRolling12MonthOutbound(
                Collections.singletonList(row), anchor);
        assertEquals(12, list.size());
        assertEquals(2026, list.get(9).getStatYear());
        assertEquals(5, list.get(9).getMonth());
        assertEquals(88, list.get(9).getOutboundCount());
    }

    @Test
    @DisplayName("DP-SY-UT-005b 存栏填报公母牛趋势 12 月补零")
    void ut005b_herdReportBullCowMonthlyTwelve()
    {
        com.ruoyi.web.modules.screen.domain.dto.HomeScreenHerdGenderMonthDto m5 =
                new com.ruoyi.web.modules.screen.domain.dto.HomeScreenHerdGenderMonthDto();
        m5.setMonth(5);
        m5.setBullCount(10);
        m5.setCowCount(20);
        List<HomeScreenInventoryMonthVo> trend = HomeScreenSupport.buildBullCowMonthlyTrendFromHerdReport(
                Collections.singletonList(m5), LocalDate.of(2024, 12, 31));
        assertEquals(12, trend.size());
        assertEquals(10, trend.get(4).getBullCount());
        assertEquals(20, trend.get(4).getCowCount());
    }

    @Test
    @DisplayName("DP-SY-UT-006 母牛分龄两档")
    void ut006_cowAgeStructure()
    {
        com.ruoyi.web.modules.screen.domain.dto.HomeScreenHerdCowAgeSumDto sums =
                new com.ruoyi.web.modules.screen.domain.dto.HomeScreenHerdCowAgeSumDto();
        sums.setCowYoungCount(40);
        sums.setCowAdultCount(60);
        List<HomeScreenAgeBandVo> bands = HomeScreenSupport.buildCowAgeStructureFromHerdReport(sums);
        assertEquals(2, bands.size());
        assertEquals(100, bands.stream().mapToInt(b -> b.getCount()).sum());
        assertEquals(HomeScreenSupport.BAND_COW_YOUNG, bands.get(0).getBandCode());
        assertEquals(HomeScreenSupport.BAND_COW_ADULT, bands.get(1).getBandCode());
    }

    @Test
    @DisplayName("DP-SY-UT-005 公母牛趋势 12 月补零")
    void ut005_bullCowMonthlyTwelve()
    {
        BreedingIndustryYakSnapshot bull = yak(1L, BreedingIndustryRules.ASSET_STATUS_NORMAL, "公", null);
        List<HomeScreenInventoryMonthVo> trend = HomeScreenSupport.buildBullCowMonthlyTrend(
                Collections.singletonList(bull), LocalDate.of(2024, 12, 31));
        assertEquals(12, trend.size());
        assertTrue(trend.get(11).getBullCount() >= 1);
    }

    @Test
    @DisplayName("DP-SY-UT-007 出栏按月缺月补零")
    void ut007_outboundMonthly()
    {
        HomeScreenMonthCountDto m3 = monthCount(3, 1);
        HomeScreenMonthCountDto m8 = monthCount(8, 2);
        List<HomeScreenOutboundMonthVo> list = HomeScreenSupport.buildOutboundMonthly(
                Arrays.asList(m3, m8), LocalDate.of(2024, 12, 31));
        assertEquals(12, list.size());
        assertEquals(1, list.get(2).getOutboundCount());
        assertEquals(0, list.get(0).getOutboundCount());
    }

    @Test
    @DisplayName("DP-SY-UT-011 预约排除拒绝取消")
    void ut011_appointmentAnnualMapping()
    {
        HomeScreenAppointmentStatDto vet = appt(null, 1, 2);
        HomeScreenAppointmentStatDto expert = appt(null, 3, 1);
        HomeScreenAppointmentVo vo = HomeScreenSupport.buildAppointment(
                Arrays.asList(vet, expert), Collections.emptyList(), YearMonth.of(2026, 7));
        assertEquals(2, vo.getAnnualVetCount());
        assertEquals(1, vo.getAnnualExpertCount());
        assertEquals(12, vo.getMonthlyStacked().size());
    }

    @Test
    @DisplayName("DP-SY-UT-011b 预约滚动 12 月堆叠")
    void ut011b_rolling12MonthAppointment()
    {
        YearMonth anchor = YearMonth.of(2026, 7);
        HomeScreenAppointmentStatDto row = new HomeScreenAppointmentStatDto();
        row.setStatYear(2026);
        row.setStatMonth(5);
        row.setProviderType(1);
        row.setCount(3);
        HomeScreenAppointmentVo vo = HomeScreenSupport.buildAppointment(
                Collections.emptyList(), Collections.singletonList(row), anchor);
        assertEquals(12, vo.getMonthlyStacked().size());
        assertEquals(2026, vo.getMonthlyStacked().get(9).getStatYear());
        assertEquals(5, vo.getMonthlyStacked().get(9).getMonth());
        assertEquals(3, vo.getMonthlyStacked().get(9).getVetCount());
    }

    @Test
    @DisplayName("DP-SY-UT-013 补贴万元换算")
    void ut013_subsidyWan()
    {
        assertEquals(new BigDecimal("1.00"), HomeScreenSupport.toAmountWan(new BigDecimal("10000")));
    }

    @Test
    @DisplayName("DP-SY-UT-014 无补贴 hasSubsidyData=false")
    void ut014_noSubsidy()
    {
        HomeScreenSubsidyVo vo = HomeScreenSupport.buildSubsidy(Collections.emptyList(), false);
        assertFalse(vo.isHasSubsidyData());
        assertEquals(3, vo.getTypeStats().size());
        assertEquals(new BigDecimal("0.00"), vo.getTypeStats().get(0).getAmountWan());
    }

    @Test
    @DisplayName("DP-SY-UT-015 农技课堂合计")
    void ut015_agriTotal()
    {
        HomeScreenAgriClassroomVo vo = HomeScreenSupport.buildAgriClassroom(2, 1);
        assertEquals(3, vo.getTrainingContentTotal());
        assertTrue(vo.isHasAgriData());
    }

    @Test
    @DisplayName("DP-SY-UT-016 农技双零")
    void ut016_agriEmpty()
    {
        HomeScreenAgriClassroomVo vo = HomeScreenSupport.buildAgriClassroom(0, 0);
        assertFalse(vo.isHasAgriData());
    }

    @Test
    @DisplayName("DP-SY-UT-017b 培训滚动 12 月")
    void ut017b_rolling12MonthTraining()
    {
        YearMonth anchor = YearMonth.of(2026, 7);
        HomeScreenTrainingMonthDto row = new HomeScreenTrainingMonthDto();
        row.setStatYear(2026);
        row.setStatMonth(3);
        row.setActivityCount(1);
        row.setEnrolledCount(20);
        HomeScreenTrainingTrendVo vo = HomeScreenSupport.buildTrainingTrend(
                Collections.singletonList(row), true, anchor);
        assertEquals(12, vo.getMonthly().size());
        assertEquals(2026, vo.getMonthly().get(7).getStatYear());
        assertEquals(3, vo.getMonthly().get(7).getMonth());
        assertEquals(1, vo.getMonthly().get(7).getActivityCount());
        assertEquals(20, vo.getMonthly().get(7).getEnrolledCount());
    }

    @Test
    @DisplayName("DP-SY-UT-018 无培训空态")
    void ut018_noTraining()
    {
        HomeScreenTrainingTrendVo vo = HomeScreenSupport.buildTrainingTrend(
                Collections.emptyList(), false, YearMonth.of(2026, 5));
        assertFalse(vo.isHasTrainingData());
        assertEquals(12, vo.getMonthly().size());
    }

    @Test
    @DisplayName("DP-SY-UT-019 标准分类解析")
    void ut019_categoryParse()
    {
        assertEquals(HomeScreenStandardCategory.FEEDING, HomeScreenStandardCategory.parse("FEEDING"));
    }

    private static BreedingIndustryYakSnapshot yak(Long pastureId, int status, String gender, Integer ageMonths)
    {
        BreedingIndustryYakSnapshot s = new BreedingIndustryYakSnapshot();
        s.setPastureId(pastureId);
        s.setAssetStatus(status);
        s.setGender(gender);
        s.setAgeMonths(ageMonths);
        return s;
    }

    private static HomeScreenMonthCountDto monthCount(int month, int count)
    {
        HomeScreenMonthCountDto dto = new HomeScreenMonthCountDto();
        dto.setMonth(month);
        dto.setCount(count);
        return dto;
    }

    private static HomeScreenAppointmentStatDto appt(Integer month, int providerType, int count)
    {
        HomeScreenAppointmentStatDto dto = new HomeScreenAppointmentStatDto();
        dto.setMonth(month);
        dto.setProviderType(providerType);
        dto.setCount(count);
        return dto;
    }

}
