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

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

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Calendar;
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.epidemic.EpidemicReportTestSamples;
import com.ruoyi.web.modules.epidemic.domain.BizEpidemicReport;
import com.ruoyi.web.modules.epidemic.domain.BizLabDetection;
import com.ruoyi.web.modules.screen.domain.vo.LabDetectionScreenVo;
import com.ruoyi.web.modules.screen.domain.vo.RelieveDurationByTypeVo;
import com.ruoyi.web.modules.screen.domain.vo.RiskLevelStatVo;
import com.ruoyi.web.modules.screen.domain.vo.SampleSourceStatVo;

/**
 * DP-DYFX-UT-003～012、014
 */
@DisplayName("EpidemicRiskScreenSupport")
class EpidemicRiskScreenSupportTest
{

    @Test
    @DisplayName("DP-DYFX-UT-003 按月缺月补 0")
    void ut003_monthlyFillZero()
    {
        BizLabDetection m3 = lab(2026, Calendar.MARCH, 1, 10, 2);
        BizLabDetection m8 = lab(2026, Calendar.AUGUST, 2, 5, 1);
        LabDetectionScreenVo vo = EpidemicRiskScreenSupport.buildLabDetection(
                Arrays.asList(m3, m8), java.time.YearMonth.of(2026, 8));
        assertEquals(12, vo.getMonthly().size());
        assertEquals(2026, vo.getMonthly().get(11).getStatYear());
        assertEquals(8, vo.getMonthly().get(11).getMonth());
        assertEquals(5, vo.getMonthly().get(11).getTestQuantity());
        assertEquals(2025, vo.getMonthly().get(0).getStatYear());
        assertEquals(9, vo.getMonthly().get(0).getMonth());
        assertEquals(0, vo.getMonthly().get(0).getTestQuantity());
        assertEquals(15, vo.getTestQuantityTotal());
        assertEquals(3, vo.getPositiveCountTotal());
    }

    @Test
    @DisplayName("DP-DYFX-UT-004 年度检出率")
    void ut004_positiveRate()
    {
        assertEquals(new BigDecimal("0.1200"), EpidemicRiskScreenSupport.calcPositiveRate(100, 12));
    }

    @Test
    @DisplayName("DP-DYFX-UT-005 检测量 0 检出率为 0")
    void ut005_zeroQuantityRate()
    {
        assertEquals(BigDecimal.ZERO, EpidemicRiskScreenSupport.calcPositiveRate(0, 0));
    }

    @Test
    @DisplayName("DP-DYFX-UT-006 样本来源占比")
    void ut006_sampleSourceRatio()
    {
        List<BizLabDetection> rows = Arrays.asList(
                labSrc(1, 10), labSrc(2, 20), labSrc(3, 30), labSrc(4, 40));
        List<SampleSourceStatVo> stats = EpidemicRiskScreenSupport.buildSampleSourceStats(rows, true);
        assertEquals(4, stats.size());
        assertEquals(new BigDecimal("0.1000"), stats.get(0).getRatio());
        BigDecimal sum = stats.stream().map(SampleSourceStatVo::getRatio).reduce(BigDecimal.ZERO, BigDecimal::add);
        assertEquals(0, sum.compareTo(BigDecimal.ONE));
    }

    @Test
    @DisplayName("DP-DYFX-UT-007 无检测样本来源为 null")
    void ut007_noLabSampleNull()
    {
        assertNull(EpidemicRiskScreenSupport.buildSampleSourceStats(Collections.emptyList(), false));
    }

    @Test
    @DisplayName("DP-DYFX-UT-008 风险等级三类")
    void ut008_riskLevelStats()
    {
        BizEpidemicReport a = report(1);
        BizEpidemicReport b = report(1);
        BizEpidemicReport c = report(2);
        List<RiskLevelStatVo> stats = EpidemicRiskScreenSupport.buildRiskLevelStats(Arrays.asList(a, b, c));
        assertEquals(3, stats.size());
        assertEquals(2, stats.get(0).getCount());
        assertEquals(new BigDecimal("0.6667"), stats.get(0).getRatio());
    }

    @Test
    @DisplayName("DP-DYFX-UT-010 防控中地区去重")
    void ut010_activeAreaDistinct()
    {
        BizEpidemicReport a = EpidemicReportTestSamples.sampleOpen();
        BizEpidemicReport b = EpidemicReportTestSamples.sampleOpen();
        b.setId(2L);
        BizEpidemicReport c = EpidemicReportTestSamples.sampleOpen();
        c.setAffectedLocationTrack("另一地点");
        assertEquals(2, EpidemicRiskScreenSupport.countDistinctLocations(Arrays.asList(a, b, c)));
    }

    @Test
    @DisplayName("DP-DYFX-UT-012 解除时效算术平均")
    void ut012_avgRelieveDays()
    {
        BizEpidemicReport r1 = EpidemicReportTestSamples.sampleOpen();
        r1.setEpidemicType(1);
        r1.setReportDate(EpidemicReportTestSamples.date(2026, Calendar.JANUARY, 1));
        r1.setReleaseDate(EpidemicReportTestSamples.date(2026, Calendar.JANUARY, 11));
        BizEpidemicReport r2 = EpidemicReportTestSamples.sampleOpen();
        r2.setId(3L);
        r2.setEpidemicType(1);
        r2.setReportDate(EpidemicReportTestSamples.date(2026, Calendar.FEBRUARY, 1));
        r2.setReleaseDate(EpidemicReportTestSamples.date(2026, Calendar.FEBRUARY, 21));
        List<RelieveDurationByTypeVo> list =
                EpidemicRiskScreenSupport.buildRelieveDurationByType(Arrays.asList(r1, r2));
        assertEquals(new BigDecimal("15.0"), list.get(0).getAvgRelieveDays());
        assertEquals(2, list.get(0).getRecordCount());
        assertNull(list.get(1).getAvgRelieveDays());
    }

    @Test
    @DisplayName("DP-DYFX-UT-013 relieveDays 自然日差")
    void ut013_relieveDays()
    {
        Long days = EpidemicRiskScreenSupport.relieveDays(
                EpidemicReportTestSamples.date(2026, Calendar.MAY, 1),
                EpidemicReportTestSamples.date(2026, Calendar.MAY, 11));
        assertEquals(Long.valueOf(10L), days);
    }

    @Test
    @DisplayName("DP-DYFX-UT-018 可选年份含当前年")
    void ut018_availableYears()
    {
        List<Integer> years = EpidemicRiskScreenSupport.buildAvailableYears(
                Collections.singletonList("2025"), Collections.emptyList());
        assertTrue(years.contains(Calendar.getInstance().get(Calendar.YEAR)));
        assertTrue(years.contains(2025));
    }

    private static BizLabDetection lab(int year, int month, int source, int tq, int pc)
    {
        BizLabDetection d = new BizLabDetection();
        d.setTestDate(EpidemicReportTestSamples.date(year, month, 15));
        d.setSampleSource(source);
        d.setTestQuantity(tq);
        d.setPositiveCount(pc);
        return d;
    }

    private static BizLabDetection labSrc(int source, int tq)
    {
        BizLabDetection d = lab(2026, Calendar.JANUARY, source, tq, 0);
        return d;
    }

    private static BizEpidemicReport report(int riskLevel)
    {
        BizEpidemicReport r = EpidemicReportTestSamples.sampleOpen();
        r.setRiskLevel(riskLevel);
        return r;
    }
}
