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

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.modules.industryservice.domain.vo.BreedingIndustryAgeBandVo;
import com.ruoyi.web.modules.industryservice.domain.vo.BreedingIndustryDashboardVo;
import com.ruoyi.web.modules.industryservice.domain.vo.BreedingIndustryDegradationStatVo;
import com.ruoyi.web.modules.industryservice.domain.vo.BreedingIndustryGrasslandVo;
import com.ruoyi.web.modules.industryservice.domain.vo.BreedingIndustryInventoryChangeVo;
import com.ruoyi.web.modules.industryservice.domain.vo.BreedingIndustryOverviewVo;
import com.ruoyi.web.modules.industryservice.mapper.BreedingIndustryStatsMapper;
import com.ruoyi.web.modules.industryservice.service.IBreedingIndustryDashboardService;
import com.ruoyi.web.modules.industryservice.support.BreedingIndustryCalculator;
import com.ruoyi.web.modules.industryservice.support.BreedingIndustryDashboardSupport;
import com.ruoyi.web.modules.industryservice.support.BreedingIndustryPastureScope;
import com.ruoyi.web.modules.industryservice.support.BreedingIndustryRules;
import com.ruoyi.web.modules.industryservice.support.GrasslandRules;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenHerdCowAgeSumDto;
import com.ruoyi.web.modules.screen.domain.dto.HomeScreenHerdGenderSumDto;
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;

@Service
public class BreedingIndustryDashboardServiceImpl implements IBreedingIndustryDashboardService
{
    private static final DateTimeFormatter STAT_DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    private static final String[] DEGRADATION_LABELS = {
            "", "未退化", "轻度", "中度", "重度", "极重度"
    };

    @Autowired
    private BreedingIndustryStatsMapper breedingIndustryStatsMapper;

    @Autowired
    private BreedingIndustryPastureScope breedingIndustryPastureScope;

    @Autowired
    private HomeScreenStatsMapper homeScreenStatsMapper;

    @Override
    public BreedingIndustryDashboardVo loadDashboard(boolean forceRefresh)
    {
        try
        {
            LocalDate statDate = LocalDate.now(ZoneId.of(BreedingIndustryRules.ZONE_SHANGHAI));
            List<Long> allowedPastureIds = breedingIndustryPastureScope.resolveAllowedPastureIds();
            BreedingIndustryDashboardVo dashboard = new BreedingIndustryDashboardVo();
            dashboard.setStatDate(statDate.format(STAT_DATE_FMT));
            dashboard.setStatYear(statDate.getYear());

            BreedingIndustryOverviewVo overview = new BreedingIndustryOverviewVo();
            fillGrasslandOverview(overview);
            fillOverviewFromHerdReports(overview);
            dashboard.setOverview(overview);

            HomeScreenStatPeriodDto latestHerd = homeScreenStatsMapper.selectLatestHerdInventoryStatPeriod();
            YearMonth anchor = HomeScreenSupport.currentYearMonth();
            int startYm = HomeScreenSupport.yearMonthKey(anchor.minusMonths(11));
            int endYm = HomeScreenSupport.yearMonthKey(anchor);

            BreedingIndustryInventoryChangeVo inventoryChange = new BreedingIndustryInventoryChangeVo();
            List<BreedingIndustryAgeBandVo> ageStructure;
            if (latestHerd == null)
            {
                inventoryChange.setBullCount(0);
                inventoryChange.setCowCount(0);
                inventoryChange.setUnknownGenderCount(0);
                ageStructure = BreedingIndustryDashboardSupport.toAgeStructure(
                        HomeScreenSupport.buildCowAgeStructureFromHerdReport(null));
            }
            else
            {
                HomeScreenHerdGenderSumDto genderSum = homeScreenStatsMapper.sumHerdInventoryGenderByStatYearMonth(
                        latestHerd.getStatYear(), latestHerd.getStatMonth());
                inventoryChange.setBullCount(
                        genderSum != null && genderSum.getBullTotal() != null ? genderSum.getBullTotal() : 0);
                inventoryChange.setCowCount(
                        genderSum != null && genderSum.getCowTotal() != null ? genderSum.getCowTotal() : 0);
                inventoryChange.setUnknownGenderCount(0);
                HomeScreenHerdCowAgeSumDto cowAge = homeScreenStatsMapper.sumHerdInventoryCowAgeByStatYearMonth(
                        latestHerd.getStatYear(), latestHerd.getStatMonth());
                ageStructure = BreedingIndustryDashboardSupport.toAgeStructure(
                        HomeScreenSupport.buildCowAgeStructureFromHerdReport(cowAge));
            }
            inventoryChange.setMonthlyTrend(BreedingIndustryDashboardSupport.toMonthlyTrend(
                    HomeScreenSupport.buildRolling12MonthBullCowTrend(
                            homeScreenStatsMapper.selectHerdInventoryBullCowByYearMonthRange(startYm, endYm),
                            anchor)));

            if (allowedPastureIds.isEmpty())
            {
                overview.setWarningYakCount(0);
            }
            else
            {
                Date yearStart = toDate(statDate.withDayOfYear(1));
                Date statDateEnd = toDateEndOfDay(statDate);
                overview.setWarningYakCount(
                        breedingIndustryStatsMapper.countWarningYak(allowedPastureIds, yearStart, statDateEnd));
            }

            dashboard.setInventoryChange(inventoryChange);
            dashboard.setAgeStructure(ageStructure);
            dashboard.setGrassland(buildGrasslandVo(overview.getGrasslandCount()));
            return dashboard;
        }
        catch (Exception ex)
        {
            throw new ServiceException(BreedingIndustryRules.MSG_LOAD_FAILED);
        }
    }

    private void fillOverviewFromHerdReports(BreedingIndustryOverviewVo overview)
    {
        HomeScreenStatPeriodDto latestHerd = homeScreenStatsMapper.selectLatestHerdInventoryStatPeriod();
        HomeScreenStatPeriodDto latestOutbound = homeScreenStatsMapper.selectLatestOutboundReportStatPeriod();
        overview.setInventoryTotal(sumHerdYakAtPeriod(latestHerd));
        overview.setAnnualOutbound(sumOutboundYakAtPeriod(latestOutbound));
        overview.setPastureCount(sumFarmerHouseholdAtPeriod(latestOutbound));
    }

    private int sumHerdYakAtPeriod(HomeScreenStatPeriodDto period)
    {
        if (period == null || period.getStatYear() == null || period.getStatMonth() == null)
        {
            return 0;
        }
        return homeScreenStatsMapper.sumHerdInventoryYakTotalByStatYearMonth(
                period.getStatYear(), period.getStatMonth());
    }

    private int sumOutboundYakAtPeriod(HomeScreenStatPeriodDto period)
    {
        if (period == null || period.getStatYear() == null || period.getStatMonth() == null)
        {
            return 0;
        }
        return homeScreenStatsMapper.sumOutboundReportYakCountByStatYearMonth(
                period.getStatYear(), period.getStatMonth());
    }

    private int sumFarmerHouseholdAtPeriod(HomeScreenStatPeriodDto period)
    {
        if (period == null || period.getStatYear() == null || period.getStatMonth() == null)
        {
            return 0;
        }
        return homeScreenStatsMapper.sumOutboundReportFarmerHouseholdCountByStatYearMonth(
                period.getStatYear(), period.getStatMonth());
    }

    private void fillGrasslandOverview(BreedingIndustryOverviewVo overview)
    {
        int grasslandCount = breedingIndustryStatsMapper.countGrassland();
        overview.setGrasslandCount(grasslandCount);
        BigDecimal area = breedingIndustryStatsMapper.sumGrasslandAreaMu();
        overview.setGrasslandAreaMu(area != null ? area.setScale(2, RoundingMode.HALF_UP) : BigDecimal.ZERO);
    }

    private BreedingIndustryGrasslandVo buildGrasslandVo(int grasslandTotal)
    {
        LocalDate statDate = LocalDate.now(ZoneId.of(BreedingIndustryRules.ZONE_SHANGHAI));
        BreedingIndustryGrasslandVo vo = new BreedingIndustryGrasslandVo();
        vo.setAvailableCount(breedingIndustryStatsMapper.countAvailableGrassland());
        vo.setInUseCount(breedingIndustryStatsMapper.countInUseGrassland(toDate(statDate)));
        vo.setDegradationStats(buildDegradationStats(grasslandTotal));
        return vo;
    }

    private List<BreedingIndustryDegradationStatVo> buildDegradationStats(int grasslandTotal)
    {
        List<BreedingIndustryDegradationStatVo> grouped = breedingIndustryStatsMapper.selectDegradationGroupCounts();
        Map<Integer, Integer> countByLevel = new HashMap<>();
        if (grouped != null)
        {
            for (BreedingIndustryDegradationStatVo row : grouped)
            {
                countByLevel.put(row.getDegradationLevel(), row.getCount());
            }
        }
        List<BreedingIndustryDegradationStatVo> result = new ArrayList<>();
        for (int level = GrasslandRules.DEGRADATION_NONE; level <= GrasslandRules.DEGRADATION_EXTREME; level++)
        {
            int count = countByLevel.getOrDefault(level, 0);
            BreedingIndustryDegradationStatVo stat = new BreedingIndustryDegradationStatVo();
            stat.setDegradationLevel(level);
            stat.setDegradationLabel(DEGRADATION_LABELS[level]);
            stat.setCount(count);
            stat.setRatio(BreedingIndustryCalculator.ratioPercent(count, grasslandTotal));
            result.add(stat);
        }
        return result;
    }

    private static Date toDate(LocalDate localDate)
    {
        return Date.from(localDate.atStartOfDay(ZoneId.of(BreedingIndustryRules.ZONE_SHANGHAI)).toInstant());
    }

    private static Date toDateEndOfDay(LocalDate localDate)
    {
        return Date.from(localDate.atTime(23, 59, 59)
                .atZone(ZoneId.of(BreedingIndustryRules.ZONE_SHANGHAI)).toInstant());
    }
}
