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

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hotwj.platform.common.mapper.PublicMapper;
import com.hotwj.platform.resourceManagement.govEnterpriseUnit.domain.vo.HotGovEnterpriseUnitVo;
import com.hotwj.platform.resourceManagement.govEnterpriseUnit.service.IHotGovEnterpriseUnitService;
import com.hotwj.platform.securityManagement.trainingParticipant.domain.HotTrainingParticipant;
import com.hotwj.platform.workbench.domain.entity.HotHiddenDangerDailyStats;
import com.hotwj.platform.workbench.domain.enums.GovHiddenDangerType;
import com.hotwj.platform.workbench.domain.vo.*;
import com.hotwj.platform.workbench.mapper.GovWorkbenchMapper;
import com.hotwj.platform.workbench.mapper.HotHiddenDangerDailyStatsMapper;
import com.hotwj.platform.workbench.service.IGovWorkbenchService;
import com.hotwj.platform.workbench.service.IHotHiddenDangerDailyStatsService;
import com.hotwj.platform.workbench.strategy.IGovRiskHandler;
import com.hotwj.platform.workbench.strategy.impl.VehicleAnnualInspectRiskHandler;
import com.hotwj.platform.workbench.strategy.impl.VehicleMaintenanceRiskHandler;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.stereotype.Service;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 政府端工作台Service业务层处理
 *
 * @author shihongwei
 */
@RequiredArgsConstructor
@Service
public class GovWorkbenchServiceImpl implements IGovWorkbenchService {

    private final IHotGovEnterpriseUnitService hotGovEnterpriseUnitService;
    private final GovWorkbenchMapper govWorkbenchMapper;
    private final HotHiddenDangerDailyStatsMapper dailyStatsMapper;
    private final PublicMapper publicMapper;
    private final List<IGovRiskHandler> riskHandlers;
    private final IHotHiddenDangerDailyStatsService dailyStatsService;
    private final VehicleAnnualInspectRiskHandler vehicleAnnualInspectRiskHandler;
    private final VehicleMaintenanceRiskHandler vehicleMaintenanceRiskHandler;

    @Override
    public GovHomeStatisticsVo getHomeStatistics() {
        String districtCode = getDistrictCode();

        GovHomeStatisticsVo vo = new GovHomeStatisticsVo();
        vo.setEnterpriseCount(govWorkbenchMapper.selectEnterpriseCount(districtCode));
        vo.setVehicleCount(govWorkbenchMapper.selectVehicleCount(districtCode));
        vo.setDriverCount(govWorkbenchMapper.selectDriverCount(districtCode));

        GovHiddenDangerSummaryVo hiddenDangerSummary = buildHiddenDangerSummary(districtCode, null);
        vo.setHiddenDangerCount(hiddenDangerSummary.getTotalCount());

        // 翻译区划名称
        String regionName = publicMapper.selectRegionFullNameByCode(districtCode);
        vo.setJurisdictionName(regionName);

        // 获取辖区企业列表
        vo.setEnterpriseList(govWorkbenchMapper.selectEnterpriseList(districtCode, null));

        return vo;
    }

    @Override
    public GovHiddenDangerSummaryVo getHiddenDangerSummary(String regionCode) {
        String districtCode = getDistrictCode();
        if (StringUtils.isNotBlank(regionCode)) {
            // 如果传入了区域代码，进行权限校验 (确保传入的区域代码是当前用户辖区的子集或相等)
            if (!regionCode.startsWith(districtCode)) {
                throw new ServiceException("无权查询该区域数据");
            }
            districtCode = regionCode;
        }

        // 处理行政区划代码，支持省级和市级查询 (去掉末尾的00)
        // 例如：510000 -> 51, 510100 -> 5101
        if (districtCode.endsWith("0000")) {
            districtCode = districtCode.substring(0, 2);
        } else if (districtCode.endsWith("00")) {
            districtCode = districtCode.substring(0, 4);
        }

        return buildHiddenDangerSummary(districtCode, null);
    }

    @Override
    public GovHiddenDangerSummaryVo getCompanyHiddenDangerSummary(Long companyId) {
        return buildHiddenDangerSummary(getDistrictCode(), companyId);
    }

    private GovHiddenDangerSummaryVo buildHiddenDangerSummary(String districtCode, Long companyId) {
        Map<String, IGovRiskHandler> handlerMap = riskHandlers.stream()
                .collect(Collectors.toMap(IGovRiskHandler::getType, h -> h));

        GovHiddenDangerSummaryVo summary = new GovHiddenDangerSummaryVo();
        List<GovHiddenDangerGroupVo> groups = new ArrayList<>();
        long totalCount = 0;

        // 按大项分组
        Map<String, List<GovHiddenDangerType>> groupMap = new HashMap<>();
        for (GovHiddenDangerType type : GovHiddenDangerType.values()) {
            groupMap.computeIfAbsent(type.getGroupKey(), k -> new ArrayList<>()).add(type);
        }

        // 遍历所有大项 (按固定顺序: enterprise, vehicle, personnel)
        String[] groupKeys = {"enterprise", "vehicle", "personnel"};
        for (String groupKey : groupKeys) {
            List<GovHiddenDangerType> types = groupMap.get(groupKey);
            if (types == null) continue;

            GovHiddenDangerGroupVo groupVo = new GovHiddenDangerGroupVo();
            groupVo.setKey(groupKey);
            // 从第一个type获取label
            groupVo.setLabel(types.get(0).getGroupLabel());

            List<GovHiddenDangerItemVo> items = new ArrayList<>();
            long groupTotal = 0;

            for (GovHiddenDangerType type : types) {
                GovHiddenDangerItemVo itemVo = new GovHiddenDangerItemVo();
                itemVo.setKey(type.getKey());
                itemVo.setLabel(type.getLabel());

                IGovRiskHandler handler = handlerMap.get(type.getKey());
                long count = 0;
                if (handler != null) {
                    count = handler.count(districtCode, companyId);
                }
                itemVo.setCount(count);
                items.add(itemVo);
                groupTotal += count;
            }
            groupVo.setItems(items);
            groupVo.setCount(groupTotal);
            groups.add(groupVo);
            totalCount += groupTotal;

            // 设置分类统计总数
            if ("enterprise".equals(groupKey)) {
                summary.setEnterpriseCount(groupTotal);
            } else if ("vehicle".equals(groupKey)) {
                summary.setVehicleCount(groupTotal);
            } else if ("personnel".equals(groupKey)) {
                summary.setPersonnelCount(groupTotal);
            }
        }

        summary.setGroups(groups);
        summary.setTotalCount(totalCount);
        return summary;
    }

    @Override
    public TableDataInfo<GovHiddenDangerDetailVo> getHiddenDangerList(String type, Long companyId, PageQuery pageQuery) {
        // 1. 转为 Map
        Map<String, IGovRiskHandler> handlerMap = riskHandlers.stream()
                .collect(Collectors.toMap(IGovRiskHandler::getType, h -> h));

        // 2. 获取处理器
        IGovRiskHandler handler = handlerMap.get(type);
        if (handler == null) {
            return TableDataInfo.build(new ArrayList<>());
        }

        // 3. 执行查询
        return handler.list(getDistrictCode(), companyId, pageQuery);
    }

    @Override
    public List<HiddenDangerCountVo> getHiddenDangerCountByMonth(Long companyId, String startDate, String endDate) {
        String districtCode = getDistrictCode();
        // 1. 如果没有传入日期，默认查询最近一个月（30天）
        LocalDate end = StringUtils.isBlank(endDate) ? LocalDate.now() : LocalDate.parse(endDate);
        LocalDate start = StringUtils.isBlank(startDate) ? end.minusDays(29) : LocalDate.parse(startDate);

        // 2. 查询数据库数据 (从日统计表查询)
        List<HiddenDangerCountVo> dbData;
        if (companyId != null) {
            dbData = dailyStatsService.getCompanyDailyStats(companyId, start.toString(), end.toString());
        } else {
            dbData = dailyStatsService.getRegionDailyStats(districtCode, start.toString(), end.toString());
        }

        Map<String, Long> dataMap = dbData.stream()
                .collect(Collectors.toMap(HiddenDangerCountVo::getDate, HiddenDangerCountVo::getCount, (k1, k2) -> k1 + k2));

        // 3. 补全日期区间
        List<HiddenDangerCountVo> result = new ArrayList<>();
        for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) {
            String dateStr = date.toString();
            HiddenDangerCountVo vo = new HiddenDangerCountVo();
            vo.setDate(dateStr);
            vo.setCount(dataMap.getOrDefault(dateStr, 0L));
            result.add(vo);
        }

        return result;
    }

    @Override
    public GovCompanyRiskTableDataInfo getCompanyRiskList(String companyName, PageQuery pageQuery) {
        String districtCode = getDistrictCode();

        // 1. 获取所有企业风险 (Map<CompanyId, Stats>)
        Map<Long, GovCompanyRiskStatsVo> statsMap = calculateAllRisksMap(districtCode);

        // 2. 计算辖区总隐患数
        long totalJurisdictionRisk = statsMap.values().stream().mapToLong(GovCompanyRiskStatsVo::getTotalRisk).sum();

        // 3. 获取符合条件的企业列表
        List<GovHomeStatisticsVo.EnterpriseInfo> enterprises = govWorkbenchMapper.selectEnterpriseList(districtCode, companyName);

        // 4. 组装结果列表
        List<GovCompanyRiskStatsVo> resultList = new ArrayList<>();
        for (GovHomeStatisticsVo.EnterpriseInfo ent : enterprises) {
            GovCompanyRiskStatsVo stats = statsMap.get(ent.getId());
            if (stats == null) {
                // 企业无隐患记录，补零
                stats = new GovCompanyRiskStatsVo();
                stats.setCompanyId(ent.getId());
                stats.setCompanyName(ent.getCompanyName());
                stats.setEnterpriseRisk(0);
                stats.setVehicleRisk(0);
                stats.setPersonnelRisk(0);
                stats.setTotalRisk(0);
            } else {
                stats.setCompanyName(ent.getCompanyName());
            }
            resultList.add(stats);
        }

        // 5. 排序 (按总隐患数倒序)
        resultList.sort((a, b) -> b.getTotalRisk().compareTo(a.getTotalRisk()));

        // 6. 分页
        int total = resultList.size();
        int pageNum = pageQuery.getPageNum();
        int pageSize = pageQuery.getPageSize();
        int start = (pageNum - 1) * pageSize;
        int end = Math.min(start + pageSize, total);

        List<GovCompanyRiskStatsVo> pageList;
        if (start > total) {
            pageList = new ArrayList<>();
        } else {
            pageList = resultList.subList(start, end);
        }

        GovCompanyRiskTableDataInfo result = new GovCompanyRiskTableDataInfo();
        result.setRows(pageList);
        result.setTotal(total);
        result.setCode(200);
        result.setMsg("查询成功");
        result.setTotalRiskCount(totalJurisdictionRisk);

        return result;
    }

    @Override
    public List<GovCompanyRiskStatsVo> getTopRiskCompanies(int limit) {
        String districtCode = getDistrictCode();

        // 1. 获取所有企业风险
        Map<Long, GovCompanyRiskStatsVo> statsMap = calculateAllRisksMap(districtCode);

        // 2. 获取辖区所有企业名称 (不传名称过滤)
        List<GovHomeStatisticsVo.EnterpriseInfo> enterprises = govWorkbenchMapper.selectEnterpriseList(districtCode, null);
        Map<Long, String> companyNames = enterprises.stream()
                .collect(Collectors.toMap(GovHomeStatisticsVo.EnterpriseInfo::getId, GovHomeStatisticsVo.EnterpriseInfo::getCompanyName));

        List<GovCompanyRiskStatsVo> resultList = new ArrayList<>();
        for (GovCompanyRiskStatsVo stats : statsMap.values()) {
            String name = companyNames.get(stats.getCompanyId());
            if (name != null) {
                stats.setCompanyName(name);
                resultList.add(stats);
            }
        }

        // 3. 排序取TOP
        return resultList.stream()
                .sorted((a, b) -> b.getTotalRisk().compareTo(a.getTotalRisk()))
                .limit(limit)
                .collect(Collectors.toList());
    }

    private Map<Long, GovCompanyRiskStatsVo> calculateAllRisksMap(String districtCode) {
        // 1. 获取简单隐患
        List<CompanyRiskCountVo> simpleRisks = govWorkbenchMapper.selectSimpleRiskCountsGroupedByCompany(districtCode);

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

        // 2. 聚合简单隐患
        for (CompanyRiskCountVo vo : simpleRisks) {
            GovCompanyRiskStatsVo stats = getOrCreateStats(statsMap, vo.getCompanyId());

            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. 聚合复杂车辆隐患
        Map<Long, Integer> annualInspectRisks = vehicleAnnualInspectRiskHandler.countByCompany(districtCode);
        mergeRealTimeVehicleRisks(statsMap, annualInspectRisks);

        Map<Long, Integer> maintenanceRisks = vehicleMaintenanceRiskHandler.countByCompany(districtCode);
        mergeRealTimeVehicleRisks(statsMap, maintenanceRisks);

        // 4. 计算总数
        for (GovCompanyRiskStatsVo stats : statsMap.values()) {
            stats.setTotalRisk(stats.getEnterpriseRisk() + stats.getVehicleRisk() + stats.getPersonnelRisk());
        }

        return statsMap;
    }

    private GovCompanyRiskStatsVo getOrCreateStats(Map<Long, GovCompanyRiskStatsVo> statsMap, Long companyId) {
        return statsMap.computeIfAbsent(companyId, k -> {
            GovCompanyRiskStatsVo s = new GovCompanyRiskStatsVo();
            s.setCompanyId(k);
            s.setEnterpriseRisk(0);
            s.setVehicleRisk(0);
            s.setPersonnelRisk(0);
            s.setTotalRisk(0);
            return s;
        });
    }

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

            GovCompanyRiskStatsVo stats = getOrCreateStats(statsMap, companyId);
            stats.setVehicleRisk(stats.getVehicleRisk() + count);
        }
    }

    @Override
    public List<GovTrainingStatsVo> getTrainingStats(String type, String beginTime, String endTime) {
        String districtCode = getDistrictCode();
        List<GovTrainingStatsVo> result = new ArrayList<>();

        LocalDate today = LocalDate.now();
        LocalDate start;
        LocalDate end;

        if (StringUtils.isNotBlank(beginTime) && StringUtils.isNotBlank(endTime)) {
            start = LocalDate.parse(beginTime);
            end = LocalDate.parse(endTime);
        } else if ("month".equals(type)) {
            // 上个自然月
            start = today.minusMonths(1).with(TemporalAdjusters.firstDayOfMonth());
            end = today.minusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
        } else {
            // 上周一到周日
            LocalDate oneWeekAgo = today.minusWeeks(1);
            start = oneWeekAgo.with(DayOfWeek.MONDAY);
            end = oneWeekAgo.with(DayOfWeek.SUNDAY);
        }

        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String endDateStr = end.format(fmt) + " 23:59:59";

        List<HotTrainingParticipant> participants = govWorkbenchMapper.selectTrainingParticipants(districtCode, endDateStr);

        long days = ChronoUnit.DAYS.between(start, end) + 1;
        for (int i = 0; i < days; i++) {
            LocalDate currentDate = start.plusDays(i);
            String date = currentDate.format(fmt);
            GovTrainingStatsVo vo = new GovTrainingStatsVo();
            vo.setDate(date);

            if ("month".equals(type)) {
                vo.setLabel(currentDate.format(DateTimeFormatter.ofPattern("MM-dd")));
            } else {
//                vo.setLabel(currentDate.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.CHINA));
                vo.setLabel(currentDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            }

            // 当天的结束时间
            Date dayEnd = Date.from(currentDate.atTime(LocalTime.MAX).atZone(ZoneId.systemDefault()).toInstant());

            long total = 0;
            long completed = 0;

            for (HotTrainingParticipant p : participants) {
                // 1. 检查是否在当天或之前已创建/分配
                if (p.getCreateTime() != null && !p.getCreateTime().after(dayEnd)) {
                    total++;

                    // 2. 检查是否在当天或之前已完成
                    if (p.getIsCompleted() != null && p.getIsCompleted() == 1L &&
                            p.getCompleteTime() != null && !p.getCompleteTime().after(dayEnd)) {
                        completed++;
                    }
                }
            }

            vo.setCompleted(completed);
            vo.setIncomplete(total - completed);
            result.add(vo);
        }

        return result;
    }

    @Override
    public List<GovAccidentStatsVo> getAccidentLevelStats() {
        String districtCode = getDistrictCode();
        List<GovAccidentStatsVo> dbList = govWorkbenchMapper.selectAccidentLevelStats(districtCode);

        // Define the fixed levels and their order
        List<String> fixedLevels = Arrays.asList("轻微事故", "一般事故", "重大事故", "特大事故");

        // Convert DB results to a map for easy lookup
        Map<String, Long> countMap = dbList.stream()
                .collect(Collectors.toMap(GovAccidentStatsVo::getLevelName, GovAccidentStatsVo::getCount));

        // Build the final result list with all 4 levels, preserving order
        List<GovAccidentStatsVo> result = new ArrayList<>();
        for (String level : fixedLevels) {
            GovAccidentStatsVo vo = new GovAccidentStatsVo();
            vo.setLevelName(level);
            vo.setCount(countMap.getOrDefault(level, 0L));
            result.add(vo);
        }

        return result;
    }

    /**
     * 获取最近有数据的统计日期（今天或昨天）
     */
    private String getLatestStatsDate(String districtCode) {
        LocalDate today = LocalDate.now();
        // 检查今日是否有数据
        Long count = dailyStatsMapper.selectCount(new LambdaQueryWrapper<HotHiddenDangerDailyStats>()
                .eq(HotHiddenDangerDailyStats::getStatsDate, today)
                .apply("region_code LIKE CONCAT({0}, '%')", districtCode));

        if (count != null && count > 0) {
            return today.toString();
        }
        // 如果今日无数据，尝试昨天
        return today.minusDays(1).toString();
    }

    /**
     * 获取当前登录用户的行政区划代码
     */
    private String getDistrictCode() {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("未登录");
        }
        // 假设 gov_enterprise_unit 表存储了政府用户的区划信息，或者直接从 user 表获取
        // 这里简化处理，直接从关联的 gov_enterprise_unit 获取
        Long unitId = loginUser.getCompanyId(); // 假设 deptId 对应 unitId
        if (unitId == null) {
            throw new ServiceException("未关联政府单位");
        }
        HotGovEnterpriseUnitVo unit = hotGovEnterpriseUnitService.queryById(unitId);
        if (unit == null || StringUtils.isBlank(unit.getDistrictCode())) {
            throw new ServiceException("未配置行政区划");
        }
        String code = unit.getDistrictCode();
        if (code.endsWith("0000")) {
            return code.substring(0, 2);
        } else if (code.endsWith("00")) {
            return code.substring(0, 4);
        }
        return code;
    }
}
