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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
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.common.exception.ServiceException;
import com.ruoyi.web.modules.industryservice.domain.vo.BreedingIndustryDashboardVo;
import com.ruoyi.web.modules.industryservice.mapper.BreedingIndustryStatsMapper;
import com.ruoyi.web.modules.industryservice.support.BreedingIndustryPastureScope;
import com.ruoyi.web.modules.industryservice.support.BreedingIndustryRules;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenHerdGenderMonthDto;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenHerdGenderSumDto;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenHerdYakStructureSumDto;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenStatPeriodDto;
import com.ruoyi.web.modules.screen.mapper.HomeScreenStatsMapper;
import com.ruoyi.web.modules.screen.support.HomeScreenSupport;

@ExtendWith(MockitoExtension.class)
@DisplayName("BreedingIndustryDashboardServiceImpl")
class BreedingIndustryDashboardServiceImplTest
{
    @Mock
    private BreedingIndustryStatsMapper breedingIndustryStatsMapper;

    @Mock
    private BreedingIndustryPastureScope breedingIndustryPastureScope;

    @Mock
    private HomeScreenStatsMapper homeScreenStatsMapper;

    @InjectMocks
    private BreedingIndustryDashboardServiceImpl service;

    @Test
    @DisplayName("ZCZX-YZCYSJ-UT-002 可见牧场为空仍返回填报口径")
    void ut002_emptyScope()
    {
        stubGrassland();
        stubNoHerdReport(2026);
        when(breedingIndustryPastureScope.resolveAllowedPastureIds()).thenReturn(Collections.emptyList());
        BreedingIndustryDashboardVo vo = service.loadDashboard(false, "2026");
        assertEquals(2026, vo.getStatYear());
        assertEquals(0, vo.getOverview().getInventoryTotal());
        assertEquals(0, vo.getInventoryChange().getBullCount());
        assertEquals(0, vo.getInventoryChange().getCowCount());
        assertEquals(0, vo.getInventoryChange().getUnknownGenderCount());
        assertEquals(0, vo.getInventoryChange().getMonthlyTrend().size());
        assertEquals(3, vo.getYakInventoryStructure().size());
        assertEquals(HomeScreenSupport.YAK_CAT_BULL, vo.getYakInventoryStructure().get(0).getCategoryCode());
    }

    @Test
    @DisplayName("ZCZX-YZCYSJ-UT-028 产业总览与存栏取自所选年最大填报月")
    void ut028_overviewFromYearMaxMonth()
    {
        stubGrassland();
        HomeScreenStatPeriodDto herd = period(2026, 7);
        HomeScreenStatPeriodDto outbound = period(2026, 5);
        HomeScreenStatPeriodDto farmer = period(2026, 6);
        when(homeScreenStatsMapper.selectLatestHerdInventoryStatPeriodByYear(2026)).thenReturn(herd);
        when(homeScreenStatsMapper.selectLatestOutboundReportStatPeriodByYear(2026)).thenReturn(outbound);
        when(homeScreenStatsMapper.selectLatestFarmerHouseholdStatPeriodByYear(2026)).thenReturn(farmer);
        when(homeScreenStatsMapper.sumHerdInventoryYakTotalByStatYearMonth(2026, 7)).thenReturn(50000);
        when(homeScreenStatsMapper.sumOutboundReportYakCountByStatYearMonth(2026, 5)).thenReturn(3200);
        when(homeScreenStatsMapper.sumFarmerHouseholdCountByStatYearMonth(2026, 6)).thenReturn(8988);
        when(homeScreenStatsMapper.sumFarmerHouseholdPastureContractAreaByStatYearMonth(2026, 6))
                .thenReturn(new BigDecimal("12500.50"));
        HomeScreenStatPeriodDto cooperative = period(2026, 6);
        HomeScreenStatPeriodDto familyRanch = period(2026, 6);
        HomeScreenStatPeriodDto largeFarmer = period(2026, 6);
        HomeScreenStatPeriodDto ownership = period(2026, 6);
        when(homeScreenStatsMapper.selectLatestCooperativeDevelopmentStatPeriodByYear(2026)).thenReturn(cooperative);
        when(homeScreenStatsMapper.selectLatestFamilyRanchStatPeriodByYear(2026)).thenReturn(familyRanch);
        when(homeScreenStatsMapper.selectLatestLargeLivestockFarmerStatPeriodByYear(2026)).thenReturn(largeFarmer);
        when(homeScreenStatsMapper.selectLatestLivestockOwnershipHouseholdStatPeriodByYear(2026)).thenReturn(ownership);
        when(homeScreenStatsMapper.countCooperativeDevelopmentByStatYearMonth(2026, 6)).thenReturn(11);
        when(homeScreenStatsMapper.countFamilyRanchByStatYearMonth(2026, 6)).thenReturn(9);
        when(homeScreenStatsMapper.countLargeLivestockFarmerByStatYearMonth(2026, 6)).thenReturn(7);
        when(homeScreenStatsMapper.sumWithLivestockHouseholdCountByStatYearMonth(2026, 6)).thenReturn(6500);
        stubHerdInventoryBlock(herd, 100, 200);
        when(breedingIndustryPastureScope.resolveAllowedPastureIds())
                .thenReturn(Collections.singletonList(1L));
        when(breedingIndustryStatsMapper.countWarningYak(any(), any(), any())).thenReturn(0);

        BreedingIndustryDashboardVo vo = service.loadDashboard(false, "2026");

        assertEquals(50000, vo.getOverview().getInventoryTotal());
        assertEquals(3200, vo.getOverview().getAnnualOutbound());
        assertEquals(8988, vo.getOverview().getPastureCount());
        assertEquals(new BigDecimal("12500.50"), vo.getOverview().getGrasslandAreaMu());
        assertEquals(11, vo.getOverview().getCooperativeCount());
        assertEquals(9, vo.getOverview().getFamilyRanchCount());
        assertEquals(7, vo.getOverview().getLargeLivestockFarmerCount());
        assertEquals(6500, vo.getOverview().getWithLivestockHouseholdCount());
        assertEquals(100, vo.getInventoryChange().getBullCount());
        assertEquals(200, vo.getInventoryChange().getCowCount());
        assertEquals(0, vo.getInventoryChange().getUnknownGenderCount());
        assertEquals(7, vo.getInventoryChange().getMonthlyTrend().size());
        assertEquals(3, vo.getYakInventoryStructure().size());
    }

    @Test
    @DisplayName("ZCZX-YZCYSJ-UT-009 公母牛取自填报；存栏结构与大屏一致")
    void ut009_genderAndYakStructureFromReport()
    {
        stubGrassland();
        HomeScreenStatPeriodDto herd = period(2026, 7);
        when(homeScreenStatsMapper.selectLatestHerdInventoryStatPeriodByYear(2026)).thenReturn(herd);
        when(homeScreenStatsMapper.selectLatestOutboundReportStatPeriodByYear(2026)).thenReturn(null);
        when(homeScreenStatsMapper.selectLatestFarmerHouseholdStatPeriodByYear(2026)).thenReturn(null);
        when(homeScreenStatsMapper.sumHerdInventoryYakTotalByStatYearMonth(2026, 7)).thenReturn(360);
        HomeScreenHerdGenderSumDto gender = new HomeScreenHerdGenderSumDto();
        gender.setBullTotal(120);
        gender.setCowTotal(230);
        gender.setYakTotal(360);
        when(homeScreenStatsMapper.sumHerdInventoryGenderByStatYearMonth(2026, 7)).thenReturn(gender);
        HomeScreenHerdYakStructureSumDto structure = new HomeScreenHerdYakStructureSumDto();
        structure.setBreedingBullCount(50);
        structure.setBullCastratedCount(70);
        structure.setCowYoungCount(80);
        structure.setCowAdultCount(150);
        structure.setInsuredYakCount(10);
        when(homeScreenStatsMapper.sumHerdInventoryYakStructureByStatYearMonth(2026, 7)).thenReturn(structure);
        when(homeScreenStatsMapper.selectHerdInventoryBullCowByMonth(2026))
                .thenReturn(Collections.emptyList());
        when(breedingIndustryPastureScope.resolveAllowedPastureIds())
                .thenReturn(Collections.singletonList(1L));
        when(breedingIndustryStatsMapper.countWarningYak(any(), any(), any())).thenReturn(0);

        BreedingIndustryDashboardVo vo = service.loadDashboard(false, "2026");

        assertEquals(120, vo.getInventoryChange().getBullCount());
        assertEquals(230, vo.getInventoryChange().getCowCount());
        assertEquals(10, vo.getInventoryChange().getUnknownGenderCount());
        assertEquals(0, vo.getInventoryChange().getMonthlyTrend().size());
        assertEquals(HomeScreenSupport.YAK_CAT_BULL, vo.getYakInventoryStructure().get(0).getCategoryCode());
        assertEquals(120, vo.getYakInventoryStructure().get(0).getCount());
        assertEquals(HomeScreenSupport.YAK_CAT_COW, vo.getYakInventoryStructure().get(1).getCategoryCode());
        assertEquals(230, vo.getYakInventoryStructure().get(1).getCount());
        assertEquals(10, vo.getYakInventoryStructure().get(2).getCount());
        assertEquals("种公牛", vo.getYakInventoryStructure().get(0).getDetails().get(0).getDetailLabel());
        assertEquals(50, vo.getYakInventoryStructure().get(0).getDetails().get(0).getCount());
    }

    @Test
    @DisplayName("ZCZX-YZCYSJ-API-019 聚合异常")
    void api019_loadFailed()
    {
        when(breedingIndustryPastureScope.resolveAllowedPastureIds())
                .thenThrow(new RuntimeException("db"));
        ServiceException ex = assertThrows(ServiceException.class, () -> service.loadDashboard(false, "2026"));
        assertEquals(BreedingIndustryRules.MSG_LOAD_FAILED, ex.getMessage());
    }

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

    private void stubNoHerdReport(int year)
    {
        when(homeScreenStatsMapper.selectLatestHerdInventoryStatPeriodByYear(year)).thenReturn(null);
        when(homeScreenStatsMapper.selectLatestOutboundReportStatPeriodByYear(year)).thenReturn(null);
        when(homeScreenStatsMapper.selectLatestFarmerHouseholdStatPeriodByYear(year)).thenReturn(null);
        when(homeScreenStatsMapper.selectHerdInventoryBullCowByMonth(year))
                .thenReturn(Collections.emptyList());
    }

    private void stubHerdInventoryBlock(HomeScreenStatPeriodDto herd, int bull, int cow)
    {
        HomeScreenHerdGenderSumDto gender = new HomeScreenHerdGenderSumDto();
        gender.setBullTotal(bull);
        gender.setCowTotal(cow);
        gender.setYakTotal(bull + cow);
        when(homeScreenStatsMapper.sumHerdInventoryGenderByStatYearMonth(
                eq(herd.getStatYear()), eq(herd.getStatMonth()))).thenReturn(gender);
        when(homeScreenStatsMapper.sumHerdInventoryYakStructureByStatYearMonth(
                eq(herd.getStatYear()), eq(herd.getStatMonth())))
                .thenReturn(new HomeScreenHerdYakStructureSumDto());
        HomeScreenHerdGenderMonthDto row = new HomeScreenHerdGenderMonthDto();
        row.setMonth(herd.getStatMonth());
        row.setBullCount(bull);
        row.setCowCount(cow);
        when(homeScreenStatsMapper.selectHerdInventoryBullCowByMonth(anyInt()))
                .thenReturn(Collections.singletonList(row));
    }

    private void stubGrassland()
    {
        when(breedingIndustryStatsMapper.countGrassland()).thenReturn(3);
        when(breedingIndustryStatsMapper.countAvailableGrassland()).thenReturn(2);
        when(breedingIndustryStatsMapper.countInUseGrassland(any())).thenReturn(1);
        when(breedingIndustryStatsMapper.selectDegradationGroupCounts()).thenReturn(Collections.emptyList());
    }
}
