package com.ruoyi.web.modules.screen.service.impl;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.when;

import java.math.BigDecimal;
import java.util.Collections;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import com.ruoyi.web.modules.industryservice.mapper.BreedingIndustryStatsMapper;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenStatPeriodDto;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenDashboardVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenTownMapMarkerVo;
import com.ruoyi.web.modules.screen.domain.vo.HomeScreenTownMapVo;
import com.ruoyi.web.modules.screen.mapper.HomeScreenStandardMapper;
import com.ruoyi.web.modules.screen.mapper.HomeScreenStatsMapper;

/**
 * DP-SY-UT-010 等编排测试
 */
@ExtendWith(MockitoExtension.class)
@DisplayName("HomeScreenServiceImpl")
class HomeScreenServiceImplTest
{

    @Mock
    private BreedingIndustryStatsMapper breedingIndustryStatsMapper;

    @Mock
    private HomeScreenStatsMapper homeScreenStatsMapper;

    @Mock
    private HomeScreenStandardMapper homeScreenStandardMapper;

    @InjectMocks
    private HomeScreenServiceImpl service;

    @Test
    @DisplayName("DP-SY-UT-010 流通三项与年份无关")
    void ut010_tradeCountsStable()
    {
        stubGrasslandAndReport();
        stubOtherBlocks();
        when(homeScreenStatsMapper.countSupplierForScreen()).thenReturn(3);
        when(homeScreenStatsMapper.countDistributorForScreen()).thenReturn(2);
        when(homeScreenStatsMapper.countTradeMarketForScreen()).thenReturn(1);

        HomeScreenDashboardVo y2025 = service.loadDashboard("2025");
        HomeScreenDashboardVo y2026 = service.loadDashboard("2026");

        assertEquals(3, y2025.getIndustryOverview().getSupplierCount());
        assertEquals(3, y2026.getIndustryOverview().getSupplierCount());
        assertEquals(2, y2025.getIndustryOverview().getDistributorCount());
        assertEquals(2, y2026.getIndustryOverview().getDistributorCount());
        assertEquals(1, y2025.getIndustryOverview().getTradeMarketCount());
        assertEquals(1, y2026.getIndustryOverview().getTradeMarketCount());
    }

    @Test
    @DisplayName("DP-SY-API-001 看板结构完整")
    void dashboardStructure()
    {
        stubGrasslandAndReport();
        stubOtherBlocks();
        HomeScreenDashboardVo vo = service.loadDashboard("2026");
        assertEquals(2026, vo.getStatYear());
        assertNotNull(vo.getStatDate());
        assertNotNull(vo.getIndustryOverview());
        assertNotNull(vo.getInventoryChange());
        assertEquals(4, vo.getAgeStructure().size());
        assertEquals(12, vo.getOutboundMonthly().size());
        assertEquals(12, vo.getInventoryChange().getMonthlyTrend().size());
        assertNotNull(vo.getGrassland());
        assertNotNull(vo.getAppointment());
        assertNotNull(vo.getSubsidy());
        assertNotNull(vo.getAgriClassroom());
        assertNotNull(vo.getTrainingTrend());
    }

    @Test
    @DisplayName("DP-SY-UT-026 地图标注取最近填报年月")
    void ut011_townMapMarkers()
    {
        HomeScreenStatPeriodDto herd = period(2025, 12);
        HomeScreenStatPeriodDto outbound = period(2026, 5);
        HomeScreenTownMapMarkerVo marker = new HomeScreenTownMapMarkerVo();
        marker.setTownDeptId(101L);
        marker.setTownName("巴青乡");
        marker.setYakInventoryCount(100);
        marker.setYakOutboundCount(50);
        when(homeScreenStatsMapper.selectLatestHerdInventoryStatPeriod()).thenReturn(herd);
        when(homeScreenStatsMapper.selectLatestOutboundReportStatPeriod()).thenReturn(outbound);
        when(homeScreenStatsMapper.selectTownMapMarkers(eq(2025), eq(12), eq(2026), eq(5)))
                .thenReturn(Collections.singletonList(marker));

        HomeScreenTownMapVo vo = service.loadTownMapMarkers();
        assertEquals(2025, vo.getHerdStatYear().intValue());
        assertEquals(2026, vo.getOutboundStatYear().intValue());
        assertEquals(1, vo.getMarkers().size());
        assertEquals(100, vo.getMarkers().get(0).getYakInventoryCount().intValue());
        assertEquals(50, vo.getMarkers().get(0).getYakOutboundCount().intValue());
    }

    @Test
    @DisplayName("DP-SY-UT-026b 仅存栏有数据时仍返回乡镇列表")
    void ut026b_townMapHerdOnly()
    {
        when(homeScreenStatsMapper.selectLatestHerdInventoryStatPeriod()).thenReturn(period(2025, 12));
        when(homeScreenStatsMapper.selectLatestOutboundReportStatPeriod()).thenReturn(null);
        when(homeScreenStatsMapper.selectTownMapMarkers(eq(2025), eq(12), eq(null), eq(null)))
                .thenReturn(Collections.emptyList());

        HomeScreenTownMapVo vo = service.loadTownMapMarkers();
        assertEquals(2025, vo.getHerdStatYear().intValue());
        assertEquals(0, vo.getMarkers().size());
    }

    @Test
    @DisplayName("DP-SY-UT-026c 无填报数据时地图为空")
    void ut026c_townMapEmptyWhenNoReport()
    {
        when(homeScreenStatsMapper.selectLatestHerdInventoryStatPeriod()).thenReturn(null);
        when(homeScreenStatsMapper.selectLatestOutboundReportStatPeriod()).thenReturn(null);

        HomeScreenTownMapVo vo = service.loadTownMapMarkers();
        assertEquals(0, vo.getMarkers().size());
    }

    @Test
    @DisplayName("DP-SY-UT-027 产业总览存栏出栏取自最近填报年月")
    void ut027_overviewFromReportTables()
    {
        stubGrasslandAndReport();
        stubOtherBlocks();
        HomeScreenStatPeriodDto herd = period(2025, 12);
        HomeScreenStatPeriodDto outbound = period(2026, 5);
        when(homeScreenStatsMapper.selectLatestHerdInventoryStatPeriod()).thenReturn(herd);
        when(homeScreenStatsMapper.selectLatestOutboundReportStatPeriod()).thenReturn(outbound);
        when(homeScreenStatsMapper.sumHerdInventoryYakTotalByStatYearMonth(2025, 12)).thenReturn(50000);
        when(homeScreenStatsMapper.sumOutboundReportYakCountByStatYearMonth(2026, 5)).thenReturn(3200);

        HomeScreenDashboardVo vo = service.loadDashboard("2024");

        assertEquals(50000, vo.getIndustryOverview().getInventoryTotal());
        assertEquals(3200, vo.getIndustryOverview().getAnnualOutbound());
    }

    @Test
    @DisplayName("DP-SY-UT-028 产业总览农牧户取自最近出栏填报年月")
    void ut028_farmerHouseholdFromReportTable()
    {
        stubGrasslandAndReport();
        stubOtherBlocks();
        when(homeScreenStatsMapper.selectLatestOutboundReportStatPeriod()).thenReturn(period(2026, 3));
        when(homeScreenStatsMapper.sumOutboundReportFarmerHouseholdCountByStatYearMonth(2026, 3)).thenReturn(8988);

        HomeScreenDashboardVo vo = service.loadDashboard("2025");

        assertEquals(8988, vo.getIndustryOverview().getPastureCount());
    }

    private static HomeScreenStatPeriodDto period(int year, int month)
    {
        HomeScreenStatPeriodDto dto = new HomeScreenStatPeriodDto();
        dto.setStatYear(year);
        dto.setStatMonth(month);
        return dto;
    }

    private void stubGrasslandAndReport()
    {
        when(breedingIndustryStatsMapper.countGrassland()).thenReturn(5);
        when(breedingIndustryStatsMapper.sumGrasslandAreaMu()).thenReturn(new BigDecimal("100"));
        when(breedingIndustryStatsMapper.countAvailableGrassland()).thenReturn(3);
        when(breedingIndustryStatsMapper.countInUseGrassland(any())).thenReturn(2);
        when(breedingIndustryStatsMapper.selectDegradationGroupCounts()).thenReturn(Collections.emptyList());
        lenient().when(homeScreenStatsMapper.selectLatestHerdInventoryStatPeriod()).thenReturn(null);
        lenient().when(homeScreenStatsMapper.selectLatestOutboundReportStatPeriod()).thenReturn(null);
        lenient().when(homeScreenStatsMapper.selectHerdInventoryBullCowByYearMonthRange(any(Integer.class), any(Integer.class)))
                .thenReturn(Collections.emptyList());
        lenient().when(homeScreenStatsMapper.selectOutboundReportYakCountByYearMonthRange(any(Integer.class), any(Integer.class)))
                .thenReturn(Collections.emptyList());
    }

    private void stubOtherBlocks()
    {
        when(homeScreenStatsMapper.countSupplierForScreen()).thenReturn(0);
        when(homeScreenStatsMapper.countDistributorForScreen()).thenReturn(0);
        when(homeScreenStatsMapper.countTradeMarketForScreen()).thenReturn(0);
        when(homeScreenStatsMapper.selectAppointmentAnnualByYear(any(Integer.class)))
                .thenReturn(Collections.emptyList());
        when(homeScreenStatsMapper.selectAppointmentMonthlyByYearMonthRange(any(Integer.class), any(Integer.class)))
                .thenReturn(Collections.emptyList());
        when(homeScreenStatsMapper.sumSubsidyAmountByTypeForYear(any(), any()))
                .thenReturn(Collections.emptyList());
        when(homeScreenStatsMapper.countSubsidyGrantInYear(any(), any())).thenReturn(0);
        when(homeScreenStatsMapper.countVideoCoursesPublishedInYear(any(), any())).thenReturn(0);
        when(homeScreenStatsMapper.countTrainingsPublishedInYear(any(), any())).thenReturn(0);
        when(homeScreenStatsMapper.countPublishedTrainingsWithTrainingTimeInYearMonthRange(
                any(Integer.class), any(Integer.class))).thenReturn(0);
        when(homeScreenStatsMapper.selectTrainingTrendByTrainingYearMonthRange(
                any(Integer.class), any(Integer.class))).thenReturn(Collections.emptyList());
        when(homeScreenStatsMapper.selectDistinctOutboundYears()).thenReturn(Collections.emptyList());
        when(homeScreenStatsMapper.selectDistinctAppointmentYears()).thenReturn(Collections.emptyList());
        when(homeScreenStatsMapper.selectDistinctSubsidyYears()).thenReturn(Collections.emptyList());
        when(homeScreenStatsMapper.selectDistinctStandardCreateYears()).thenReturn(Collections.emptyList());
        when(homeScreenStatsMapper.selectDistinctTechPublishYears()).thenReturn(Collections.emptyList());
        when(homeScreenStatsMapper.selectDistinctTrainingYears()).thenReturn(Collections.emptyList());
    }
}
