package com.hotwj.platform.workbench.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hotwj.platform.workbench.domain.entity.HotHiddenDangerDailyStats;
import com.hotwj.platform.workbench.domain.vo.CompanyRiskCountVo;
import com.hotwj.platform.workbench.domain.vo.HiddenDangerCountVo;
import com.hotwj.platform.workbench.mapper.GovWorkbenchMapper;
import com.hotwj.platform.workbench.mapper.HotHiddenDangerDailyStatsMapper;
import com.hotwj.platform.workbench.mapper.HotTrainingDailyStatsMapper;
import com.hotwj.platform.workbench.service.IHotHiddenDangerDailyStatsService;
import com.hotwj.platform.workbench.strategy.impl.VehicleAnnualInspectRiskHandler;
import com.hotwj.platform.workbench.strategy.impl.VehicleMaintenanceRiskHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 政府端隐患日统计Service业务层处理
 *
 * @author shihongwei
 * @date 2026-02-25
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class HotHiddenDangerDailyStatsServiceImpl extends ServiceImpl<HotHiddenDangerDailyStatsMapper, HotHiddenDangerDailyStats> implements IHotHiddenDangerDailyStatsService {

    private final HotHiddenDangerDailyStatsMapper dailyStatsMapper;
    private final GovWorkbenchMapper govWorkbenchMapper;
    private final VehicleAnnualInspectRiskHandler vehicleAnnualInspectRiskHandler;
    private final VehicleMaintenanceRiskHandler vehicleMaintenanceRiskHandler;
    private final HotTrainingDailyStatsMapper trainingDailyStatsMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void generateDailyStats() {
        // 统计“昨天”的数据：定时任务在每日凌晨执行，口径为上一日00:00:00~23:59:59
        LocalDate statDate = LocalDate.now().minusDays(1);
        log.info("开始生成日统计数据（隐患、培训），统计日期: {}", statDate);

        int hiddenCompanyCount = generateHiddenDangerDailyStats(statDate);
        int trainingAffectedRows = generateTrainingDailyStats(statDate);
        log.info("日统计数据生成完成（隐患、培训），隐患统计企业数: {}, 培训统计写入行数: {}", hiddenCompanyCount, trainingAffectedRows);
    }

    private int generateHiddenDangerDailyStats(LocalDate statDate) {
        // 1. 获取所有简单隐患统计 (SQL直接聚合)
        // 包含: 营业执照, 道路经营许可证, 上岗资格证, 行驶证, 运输证, 驾驶员身份证, 驾驶证, 从业资格证, 违规
        List<CompanyRiskCountVo> simpleRisks = govWorkbenchMapper.selectSimpleRiskCountsGroupedByCompany(null);

        // 获取当天已存在的统计数据，用于更新
        List<HotHiddenDangerDailyStats> existingStats = dailyStatsMapper.selectList(
                new LambdaQueryWrapper<HotHiddenDangerDailyStats>()
                        .eq(HotHiddenDangerDailyStats::getStatsDate, statDate)
        );
        Map<Long, HotHiddenDangerDailyStats> existingStatsMap = existingStats.stream()
                .collect(Collectors.toMap(HotHiddenDangerDailyStats::getCompanyId, s -> s));

        Map<Long, HotHiddenDangerDailyStats> statsMap = new HashMap<>();

        // 2. 处理简单隐患
        for (CompanyRiskCountVo vo : simpleRisks) {
            HotHiddenDangerDailyStats stats = statsMap.computeIfAbsent(vo.getCompanyId(), k -> {
                // 如果已存在，则使用现有对象（保留ID），否则新建
                HotHiddenDangerDailyStats s = existingStatsMap.getOrDefault(k, new HotHiddenDangerDailyStats());
                s.setCompanyId(k);
                // 重置统计数据
                s.setEnterpriseRisk(0);
                s.setVehicleRisk(0);
                s.setPersonnelRisk(0);
                s.setStatsDate(statDate);
                if (s.getRegionCode() == null) {
                    s.setRegionCode(vo.getRegionCode());
                }
                return s;
            });

            // 补充RegionCode (如果之前是null，现在有了)
            if (stats.getRegionCode() == null && vo.getRegionCode() != null) {
                stats.setRegionCode(vo.getRegionCode());
            }

            int count = vo.getCount() == null ? 0 : vo.getCount();
            if ("enterprise".equals(vo.getCategory())) {
                stats.setEnterpriseRisk(stats.getEnterpriseRisk() + count);
            } else if ("vehicle".equals(vo.getCategory())) {
                stats.setVehicleRisk(stats.getVehicleRisk() + count);
            } else if ("personnel".equals(vo.getCategory())) {
                stats.setPersonnelRisk(stats.getPersonnelRisk() + count);
            }
        }

        // 3. 处理复杂车辆隐患 (年审检测) - Java内存计算
        // 传入null表示查询所有辖区
        Map<Long, Integer> annualInspectRisks = vehicleAnnualInspectRiskHandler.countByCompany(null);
        mergeVehicleRisks(statsMap, annualInspectRisks, statDate, existingStatsMap);

        // 4. 处理复杂车辆隐患 (二级维护) - Java内存计算
        Map<Long, Integer> maintenanceRisks = vehicleMaintenanceRiskHandler.countByCompany(null);
        mergeVehicleRisks(statsMap, maintenanceRisks, statDate, existingStatsMap);

        // 5. 补充缺失的RegionCode (针对只有复杂隐患的企业)
        Set<Long> missingRegionCompanies = statsMap.values().stream()
                .filter(s -> s.getRegionCode() == null)
                .map(HotHiddenDangerDailyStats::getCompanyId)
                .collect(Collectors.toSet());

        if (!missingRegionCompanies.isEmpty()) {
            // 分批查询防止ID过多
            List<Long> allIds = new ArrayList<>(missingRegionCompanies);
            int batchSize = 1000;
            for (int i = 0; i < allIds.size(); i += batchSize) {
                List<Long> batchIds = allIds.subList(i, Math.min(i + batchSize, allIds.size()));
                List<CompanyRiskCountVo> regions = govWorkbenchMapper.selectCompanyRegionCodes(batchIds);
                for (CompanyRiskCountVo r : regions) {
                    HotHiddenDangerDailyStats stats = statsMap.get(r.getCompanyId());
                    if (stats != null) {
                        stats.setRegionCode(r.getRegionCode());
                    }
                }
            }
        }

        // 6. 计算总数并保存
        if (!statsMap.isEmpty()) {
            List<HotHiddenDangerDailyStats> list = new ArrayList<>(statsMap.values());
            for (HotHiddenDangerDailyStats stats : list) {
                stats.setTotalRisk(stats.getEnterpriseRisk() + stats.getVehicleRisk() + stats.getPersonnelRisk());
            }

            // 批量保存或更新
            this.saveOrUpdateBatch(list);

            // 删除不再存在的企业统计 (即今天之前有隐患但现在没有隐患的企业)
            // 从 existingStatsMap 中移除 statsMap 中有的 key，剩下的就是需要删除的
            Set<Long> currentCompanyIds = statsMap.keySet();
            List<Long> idsToDelete = existingStatsMap.values().stream()
                    .filter(s -> !currentCompanyIds.contains(s.getCompanyId()))
                    .map(HotHiddenDangerDailyStats::getId)
                    .collect(Collectors.toList());

            if (!idsToDelete.isEmpty()) {
                dailyStatsMapper.deleteBatchIds(idsToDelete);
            }
        } else {
            // 如果昨天（指定天）没有任何隐患数据，但数据库里有记录，则全部删除
            dailyStatsMapper.delete(new LambdaQueryWrapper<HotHiddenDangerDailyStats>()
                    .eq(HotHiddenDangerDailyStats::getStatsDate, statDate));
        }

        log.info("隐患日统计数据生成完成，共处理 {} 家企业的数据", statsMap.size());
        return statsMap.size();
    }

    private int generateTrainingDailyStats(LocalDate statDate) {
        // 统计口径：statDate 的 00:00:00 ~ 23:59:59
        Date dayEnd = java.util.Date.from(statDate.atTime(java.time.LocalTime.MAX).atZone(java.time.ZoneId.systemDefault()).toInstant());
        Date statsDate = java.util.Date.from(statDate.atStartOfDay(java.time.ZoneId.systemDefault()).toInstant());
        int affected = trainingDailyStatsMapper.upsertDailyStats(statsDate, dayEnd);
        return affected;
    }

    private void mergeVehicleRisks(Map<Long, HotHiddenDangerDailyStats> statsMap, Map<Long, Integer> risks, LocalDate today, Map<Long, HotHiddenDangerDailyStats> existingStatsMap) {
        for (Map.Entry<Long, Integer> entry : risks.entrySet()) {
            Long companyId = entry.getKey();
            Integer count = entry.getValue();
            if (count == null || count == 0) continue;

            HotHiddenDangerDailyStats stats = statsMap.computeIfAbsent(companyId, k -> {
                HotHiddenDangerDailyStats s = existingStatsMap.getOrDefault(k, new HotHiddenDangerDailyStats());
                s.setCompanyId(k);
                // RegionCode暂时为空，如果只有复杂隐患而没有简单隐患，可能拿不到RegionCode
                // 这种情况下，可能需要单独查询Company信息。但概率较低且不影响核心统计（按ID查）
                // 可以在这里TODO: 查询Company获取RegionCode
                if (s.getId() == null) { // 如果是新对象，才重置
                    s.setEnterpriseRisk(0);
                    s.setVehicleRisk(0);
                    s.setPersonnelRisk(0);
                }
                // 注意：如果s来自existingStatsMap且已经在statsMap中，说明在上面循环中已经重置过了
                // 如果s来自existingStatsMap但不在statsMap中（即只有复杂隐患），则需要在这里重置
                // 简单起见，这里再次确保初始化，但要小心不要覆盖上面循环累加的值
                // 由于computeIfAbsent只在key不存在时执行，所以进入这里的都是statsMap中没有的
                // 因此如果是从existingStatsMap拿出来的，说明它之前没有被简单隐患循环处理过
                // 所以可以安全地重置为0
                if (existingStatsMap.containsKey(k)) {
                     s.setEnterpriseRisk(0);
                     s.setVehicleRisk(0);
                     s.setPersonnelRisk(0);
                }
                
                s.setStatsDate(today);
                return s;
            });

            stats.setVehicleRisk(stats.getVehicleRisk() + count);
        }
    }

    @Override
    public List<HiddenDangerCountVo> getCompanyDailyStats(Long companyId, String startDate, String endDate) {
        List<HotHiddenDangerDailyStats> statsList = dailyStatsMapper.selectStatsByCompanyAndDateRange(companyId, startDate, endDate);
        return statsList.stream().map(s -> {
            HiddenDangerCountVo vo = new HiddenDangerCountVo();
            vo.setDate(s.getStatsDate().toString());
            vo.setCount(s.getTotalRisk().longValue());
            // 如果需要分类详情，HiddenDangerCountVo目前只有count。
            // 如果前端需要分类，可能需要修改HiddenDangerCountVo或使用新的VO。
            // 根据需求描述："返回给前端的就是柱状图数据... 隐患数量"，似乎只需要总数。
            // 但用户也提到 "每日的隐患数量（企业、车辆、人员）"，可能需要展示详情？
            // 暂时只返回总数，如果需要详情可以扩展。
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public List<HiddenDangerCountVo> getRegionDailyStats(String regionCode, String startDate, String endDate) {
        List<HotHiddenDangerDailyStats> statsList = dailyStatsMapper.selectStatsByDateRange(regionCode, startDate, endDate);
        return statsList.stream().map(s -> {
            HiddenDangerCountVo vo = new HiddenDangerCountVo();
            vo.setDate(s.getStatsDate().toString());
            vo.setCount(s.getTotalRisk().longValue());
            return vo;
        }).collect(Collectors.toList());
    }
}
