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

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

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
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.screen.domain.dto.LivestockResourceBandCountDto;
import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceCategoryCountDto;
import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceDateCountDto;
import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceProblemLevelCountDto;
import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceProductOutputMonthDto;
import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceProductOutputSumDto;
import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceTechPersonnelDto;
import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceThreeAssetsSumDto;
import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceUserStructureDto;
import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceVaccinationSumDto;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceActivityTrendVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceAgriUnitStructureVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceCategoryItemVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceCategoryShareVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceHourlyHeatVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceOverviewVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceProblemReportShareVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceProductOutputListItemVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceProductOutputTrendVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceReplyStatusVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceTechEnvoyStructureVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceThreeAssetsProblemListItemVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVaccinationListItemVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceVaccinationOverviewVo;

/**
 * DP-XM-UT-003～020
 */
@DisplayName("LivestockResourceScreenSupport")
class LivestockResourceScreenSupportTest
{
    @Test
    @DisplayName("DP-XM-UT-004 历史年 statDate")
    void ut004_historicalStatDate()
    {
        assertEquals(LocalDate.of(2024, 12, 31), HomeScreenSupport.resolveStatDate(2024));
    }

    @Test
    @DisplayName("DP-XM-UT-008 核心总览空值归零")
    void ut008_overviewZeroWhenNull()
    {
        LivestockResourceOverviewVo vo = LivestockResourceScreenSupport.buildOverview(
                null, null, null, null, null);
        assertEquals(new BigDecimal("0.00"), vo.getOperatingFixedAssets());
        assertEquals(new BigDecimal("0.00"), vo.getNonOperatingFixedAssets());
        assertEquals(new BigDecimal("0.0000"), vo.getMeatOutput());
        assertEquals(new BigDecimal("0.0000"), vo.getMilkOutput());
        assertEquals(new BigDecimal("0.00"), vo.getImmunityRate());
        assertEquals(0L, vo.getVetCount());
        assertEquals(0L, vo.getTechEnvoyCount());
        assertEquals(0L, vo.getAgriUnitCount());
    }

    @Test
    @DisplayName("DP-XM-UT-010 核心总览精度与免疫率")
    void ut010_overviewScaleAndImmunity()
    {
        LivestockResourceThreeAssetsSumDto assets = new LivestockResourceThreeAssetsSumDto();
        assets.setOperatingFixedAssets(new BigDecimal("12.345"));
        assets.setNonOperatingFixedAssets(new BigDecimal("8.1"));
        LivestockResourceProductOutputSumDto output = new LivestockResourceProductOutputSumDto();
        output.setMeatOutput(new BigDecimal("1.23456"));
        output.setMilkOutput(new BigDecimal("2.5"));
        LivestockResourceVaccinationSumDto vacc = new LivestockResourceVaccinationSumDto();
        vacc.setShouldVaccinateCount(300L);
        vacc.setActualVaccinateCount(295L);
        LivestockResourceTechPersonnelDto tech = new LivestockResourceTechPersonnelDto();
        tech.setEnvoyTotalCount(12L);
        tech.setAgriTotalCount(8L);
        LivestockResourceOverviewVo vo = LivestockResourceScreenSupport.buildOverview(
                assets, output, vacc, 9L, tech);
        assertEquals(new BigDecimal("12.35"), vo.getOperatingFixedAssets());
        assertEquals(new BigDecimal("8.10"), vo.getNonOperatingFixedAssets());
        assertEquals(new BigDecimal("1.2346"), vo.getMeatOutput());
        assertEquals(new BigDecimal("2.5000"), vo.getMilkOutput());
        assertEquals(new BigDecimal("98.33"), vo.getImmunityRate());
        assertEquals(9L, vo.getVetCount());
        assertEquals(12L, vo.getTechEnvoyCount());
        assertEquals(8L, vo.getAgriUnitCount());
    }

    @Test
    @DisplayName("农村三资 / 问题上报 / 产量趋势 / 疫苗接种组装")
    void industryBlocks()
    {
        LivestockResourceThreeAssetsSumDto assets = new LivestockResourceThreeAssetsSumDto();
        assets.setOperatingFixedAssets(new BigDecimal("10"));
        assets.setNonOperatingFixedAssets(new BigDecimal("20"));
        assets.setFixedAssets(new BigDecimal("30"));
        assertEquals(new BigDecimal("30.00"),
                LivestockResourceScreenSupport.buildRuralThreeAssets(assets).getFixedAssets());

        LivestockResourceProblemLevelCountDto row = new LivestockResourceProblemLevelCountDto();
        row.setProblemLevel("key");
        row.setCount(2L);
        LivestockResourceProblemReportShareVo share =
                LivestockResourceScreenSupport.buildProblemReportShare(Collections.singletonList(row));
        assertEquals(2L, share.getTotalCount());
        assertEquals(3, share.getItems().size());
        assertEquals(new BigDecimal("100.0"), share.getItems().get(1).getRatio());

        com.ruoyi.web.modules.industryservice.domain.BizThreeAssetsProblemReport problem =
                new com.ruoyi.web.modules.industryservice.domain.BizThreeAssetsProblemReport();
        problem.setTownName("巴青镇");
        problem.setVillageName("某村");
        problem.setProblemLevel("major");
        problem.setProblemDetail("详情");
        problem.setHandleResult("已处理");
        LivestockResourceThreeAssetsProblemListItemVo problemItem =
                LivestockResourceScreenSupport.buildThreeAssetsProblemListItems(
                        Collections.singletonList(problem)).get(0);
        assertEquals("巴青镇", problemItem.getTownName());
        assertEquals("重大", problemItem.getProblemLevelName());
        assertEquals("详情", problemItem.getProblemDetail());

        com.ruoyi.web.modules.industryservice.domain.BizLivestockProductOutput output =
                new com.ruoyi.web.modules.industryservice.domain.BizLivestockProductOutput();
        output.setStatYear(2026);
        output.setStatMonth(7);
        output.setTownName("巴青镇");
        output.setVillageName("某村");
        output.setMeatOutput(new BigDecimal("1.2"));
        output.setMilkOutput(new BigDecimal("3.4"));
        LivestockResourceProductOutputListItemVo outputItem =
                LivestockResourceScreenSupport.buildProductOutputListItems(
                        Collections.singletonList(output)).get(0);
        assertEquals(2026, outputItem.getStatYear());
        assertEquals(7, outputItem.getStatMonth());
        assertEquals(new BigDecimal("1.2000"), outputItem.getMeatOutput());
        assertEquals(new BigDecimal("3.4000"), outputItem.getMilkOutput());

        com.ruoyi.web.modules.industryservice.domain.BizVaccinationData vaccRow =
                new com.ruoyi.web.modules.industryservice.domain.BizVaccinationData();
        vaccRow.setStatYear(2026);
        vaccRow.setStatMonth(7);
        vaccRow.setTownName("巴青镇");
        vaccRow.setVillageName("某村");
        vaccRow.setShouldVaccinateCount(100);
        vaccRow.setActualVaccinateCount(80);
        LivestockResourceVaccinationListItemVo vaccItem =
                LivestockResourceScreenSupport.buildVaccinationListItems(
                        Collections.singletonList(vaccRow)).get(0);
        assertEquals(100, vaccItem.getShouldVaccinateCount());
        assertEquals(80, vaccItem.getActualVaccinateCount());
        assertEquals(new BigDecimal("80.00"), vaccItem.getImmunityRate());

        LivestockResourceProductOutputMonthDto m3 = new LivestockResourceProductOutputMonthDto();
        m3.setStatMonth(3);
        m3.setMeatOutput(new BigDecimal("1"));
        m3.setMilkOutput(new BigDecimal("2"));
        LivestockResourceProductOutputTrendVo trend =
                LivestockResourceScreenSupport.buildProductOutputTrend(3, Collections.singletonList(m3));
        assertEquals(3, trend.getMaxMonth());
        assertEquals(3, trend.getMonthlySeries().size());
        assertEquals(new BigDecimal("1.0000"), trend.getMonthlySeries().get(2).getMeatOutput());
        assertEquals(new BigDecimal("0.0000"), trend.getMonthlySeries().get(0).getMeatOutput());

        LivestockResourceVaccinationSumDto vacc = new LivestockResourceVaccinationSumDto();
        vacc.setShouldVaccinateCount(100L);
        vacc.setActualVaccinateCount(80L);
        LivestockResourceVaccinationOverviewVo vaccVo =
                LivestockResourceScreenSupport.buildVaccinationOverview(6, vacc);
        assertEquals(6, vaccVo.getStatMonth());
        assertEquals(new BigDecimal("80.00"), vaccVo.getImmunityRate());
        assertEquals(100L, vaccVo.getShouldVaccinateCount());
        assertEquals(80L, vaccVo.getActualVaccinateCount());

        LivestockResourceTechPersonnelDto tech = new LivestockResourceTechPersonnelDto();
        tech.setEnvoyMaleCount(18L);
        tech.setEnvoyFemaleCount(12L);
        tech.setEnvoyPartyMemberCount(10L);
        tech.setEnvoyTotalCount(30L);
        tech.setAgriClerkCount(1L);
        tech.setAgriJuniorCount(2L);
        tech.setAgriIntermediateCount(3L);
        tech.setAgriAssociateSeniorCount(4L);
        tech.setAgriManagementCount(5L);
        tech.setAgriTotalCount(15L);
        LivestockResourceTechEnvoyStructureVo envoy =
                LivestockResourceScreenSupport.buildTechEnvoyStructure(tech);
        assertEquals(30L, envoy.getTotalCount());
        assertEquals(10L, envoy.getPartyShare().get(0).getCount());
        assertEquals(20L, envoy.getPartyShare().get(1).getCount());
        assertEquals(18L, envoy.getGenderShare().get(0).getCount());
        LivestockResourceAgriUnitStructureVo agri =
                LivestockResourceScreenSupport.buildAgriUnitStructure(tech);
        assertEquals(15L, agri.getTotalCount());
        assertEquals("员级", agri.getRankItems().get(0).getItemName());
        assertEquals(5L, agri.getRankItems().get(4).getCount());
    }

    @Test
    @DisplayName("DP-XM-UT-011 7 日补零")
    void ut011_dailySevenPoints()
    {
        LivestockResourceDateCountDto d1 = dayCount("2026-05-14", 3L);
        LivestockResourceActivityTrendVo trend = LivestockResourceScreenSupport.buildActivityTrend(
                Collections.singletonList(d1),
                Collections.emptyList(),
                LocalDate.of(2026, 5, 20));
        assertEquals(7, trend.getDailySeries().size());
        assertEquals(3L, trend.getDailySeries().get(0).getSessionCount());
        assertEquals("2026-05-14", trend.getDailySeries().get(0).getDate());
        assertEquals(0L, trend.getDailySeries().get(6).getSessionCount());
        assertEquals("2026-05-20", trend.getDailySeries().get(6).getDate());
    }

    @Test
    @DisplayName("DP-XM-UT-012 最近 24 小时整点桶")
    void ut012_hourlyTwentyFour()
    {
        LocalDateTime anchor = LocalDateTime.of(2026, 5, 20, 10, 30);
        LivestockResourceHourlyHeatVo heat = LivestockResourceScreenSupport.buildHourlyHeat(
                Collections.singletonList(hourCount("2026052010", 2L)),
                Collections.singletonList(hourCount("2026052010", 5L)),
                anchor);
        assertEquals(24, heat.getHourlySeries().size());
        assertEquals("2026-05-20 10:00", heat.getWindowEnd());
        assertEquals("10:00", heat.getHourlySeries().get(23).getBucketStart());
        assertEquals("2026-05-20 10:00", heat.getHourlySeries().get(23).getBucketDateTime());
        assertEquals(2L, heat.getHourlySeries().get(23).getSessionCount());
        assertEquals(5L, heat.getHourlySeries().get(23).getQuestionCount());
    }

    @Test
    @DisplayName("DP-XM-UT-013 用户结构 180 天")
    void ut013_userStructure()
    {
        LivestockResourceUserStructureDto raw = new LivestockResourceUserStructureDto();
        raw.setNewUserCount(3L);
        raw.setOldUserCount(2L);
        com.ruoyi.web.modules.screen.domain.vo.LivestockResourceUserStructureVo vo =
                LivestockResourceScreenSupport.buildUserStructure(raw);
        assertEquals(3, vo.getNewUserCount());
        assertEquals(new BigDecimal("60.0"), vo.getNewUserRatio());
        assertEquals(new BigDecimal("40.0"), vo.getOldUserRatio());
    }

    @Test
    @DisplayName("DP-XM-UT-015 分类占比 100%")
    void ut015_categoryRatioSum()
    {
        List<LivestockResourceCategoryCountDto> rows = Arrays.asList(
                cat("1", 40L),
                cat("2", 30L),
                cat("UNCAT", 30L));
        LivestockResourceCategoryShareVo share = LivestockResourceScreenSupport.buildCategoryShare(rows, 100L);
        assertEquals(5, share.getItems().size());
        double sum = share.getItems().stream().mapToDouble(i -> i.getRatio().doubleValue()).sum();
        assertEquals(100.0, sum, 0.2);
    }

    @Test
    @DisplayName("DP-XM-UT-017 会话分档四档")
    void ut017_sessionBands()
    {
        List<LivestockResourceBandCountDto> rows = Arrays.asList(
                band(LivestockResourceScreenRules.BAND_LIGHT, 2L),
                band(LivestockResourceScreenRules.BAND_DEEP, 1L));
        List<com.ruoyi.web.modules.screen.domain.vo.LivestockResourceSessionBandVo> list =
                LivestockResourceScreenSupport.buildSessionReplyDistribution(rows, 10L);
        assertEquals(4, list.size());
        assertEquals(2L, list.get(0).getSessionCount());
        assertEquals(new BigDecimal("20.0"), list.get(0).getRatio());
    }

    @Test
    @DisplayName("DP-XM-UT-018 应答状态")
    void ut018_replyStatus()
    {
        LivestockResourceReplyStatusVo vo = LivestockResourceScreenSupport.buildReplyStatus(8L, 2L);
        assertEquals(10, vo.getTotalAiReplies());
        assertEquals(2, vo.getItems().size());
        assertEquals(new BigDecimal("80.0"), vo.getItems().get(0).getRatio());
    }

    @Test
    @DisplayName("DP-XM-UT-019 热点 Top5 条数优先")
    void ut019_hotTopics()
    {
        LivestockResourceCategoryCountDto a = cat("2", 50L);
        LivestockResourceCategoryCountDto b = cat("1", 30L);
        List<LivestockResourceCategoryItemVo> hot = LivestockResourceScreenSupport.buildHotTopics(
                Arrays.asList(a, b), 5);
        assertEquals(2, hot.size());
        assertEquals("2", hot.get(0).getCategoryCode());
        assertEquals(50L, hot.get(0).getCount());
    }

    @Test
    @DisplayName("DP-XM-UT-020 关键词仅文本分词")
    void ut020_keywords()
    {
        List<String> texts = Arrays.asList(
                "牦牛养殖防疫技巧",
                "牦牛养殖防疫技巧",
                "   ",
                null);
        java.util.List<com.ruoyi.web.modules.screen.domain.vo.LivestockResourceKeywordVo> list =
                LivestockResourceScreenSupport.extractTopKeywords(texts, 30);
        assertFalse(list.isEmpty());
        assertTrueMinCount(list.get(0).getCount(), 2L);
        org.junit.jupiter.api.Assertions.assertTrue(
                list.stream().anyMatch(k -> k.getKeyword().contains("牦牛")));
    }

    private static void assertTrueMinCount(long actual, long min)
    {
        org.junit.jupiter.api.Assertions.assertTrue(actual >= min);
    }

    private static LivestockResourceDateCountDto dayCount(String date, long count)
    {
        LivestockResourceDateCountDto dto = new LivestockResourceDateCountDto();
        dto.setBucketKey(date);
        dto.setCount(count);
        return dto;
    }

    private static LivestockResourceDateCountDto hourCount(String bucket, long count)
    {
        LivestockResourceDateCountDto dto = new LivestockResourceDateCountDto();
        dto.setBucketKey(bucket);
        dto.setCount(count);
        return dto;
    }

    private static LivestockResourceCategoryCountDto cat(String code, long count)
    {
        LivestockResourceCategoryCountDto dto = new LivestockResourceCategoryCountDto();
        dto.setCategoryCode(code);
        dto.setCount(count);
        return dto;
    }

    private static LivestockResourceBandCountDto band(String code, long count)
    {
        LivestockResourceBandCountDto dto = new LivestockResourceBandCountDto();
        dto.setBandCode(code);
        dto.setSessionCount(count);
        return dto;
    }

    private static LivestockResourceCategoryItemVo item(
            String code, String name, long count, BigDecimal ratio)
    {
        LivestockResourceCategoryItemVo vo = new LivestockResourceCategoryItemVo();
        vo.setCategoryCode(code);
        vo.setCategoryName(name);
        vo.setCount(count);
        vo.setRatio(ratio);
        return vo;
    }
}
