package com.hz.pm.api.dashboard.handle;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.hz.pm.api.common.helper.RegionCacheHelper;
import com.hz.pm.api.common.model.constant.RegionConst;
import com.hz.pm.api.dashboard.enums.CockpitAppcationTypeEnum;
import com.hz.pm.api.dashboard.model.entity.CockpitApplication;
import com.hz.pm.api.dashboard.model.entity.CockpitStats;
import com.hz.pm.api.dashboard.model.vo.CockpitStatsVO;
import com.hz.pm.api.dashboard.model.vo.CockpitStatsVO.*;
import com.hz.pm.api.dashboard.service.ICockpitStatsService;
import com.hz.pm.api.sys.model.dto.RegionDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import static com.hz.pm.api.dashboard.constant.DashboardConstant.CockpitStats.*;

/**
 * @Classname CockpitStatsHandler
 * @Description
 * @Date 2023/10/9 14:11
 * @Author PoffyZhang
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class CockpitStatsHandler {

    private final RegionCacheHelper regionCacheHelper;

    private final ICockpitStatsService cockpitStatsService;

    private static final List<Integer> years = Lists.newArrayList(2021, 2022, 2023, 2024, 2025);

    public CockpitStatsVO convertCockpitStats(CockpitStats cockpitStats, String regionCode, Integer year
            , List<CockpitApplication> appDatas) {
        CockpitStatsVO res = BeanUtil.copyProperties(cockpitStats, CockpitStatsVO.class);

        if (Objects.isNull(cockpitStats)) {
            return res;
        }
        //监测数据
        res.setMonitorData(convertMonitor(cockpitStats, regionCode));
        //专家数据
        res.setExpertData(convertExpertData(cockpitStats));
        //顶部数据
        res.setTopData(convertTopData(cockpitStats));
        //地图数据
        res.setMapProjectData(convertMapProjectsData(cockpitStats, year));
        //项目项目数据
        res.setStatusProjectsData(convertStatusProjectsData(cockpitStats));
        //项目效益 优秀项目
        res.setExcellentData(convertExcellentData(cockpitStats));
        //核减信息
        res.setReduceData(convertReduceData(cockpitStats));
        //产出信息
        res.setProduceData(convertProduceData(cockpitStats));
        //绩效
        res.setPerformanceData(convertPerformanceData(cockpitStats));
        //最佳/重大应用
        res.setAppDatas(convertCockpitApps(appDatas));
        //数据质量分数
        res.setQualityDatas(convertQualityData(year));
        return res;
    }

    private List<QualityData> convertQualityData(Integer year) {
        List<CockpitStats> dataList = cockpitStatsService.list(Wrappers.lambdaQuery(CockpitStats.class)
                .eq(Objects.nonNull(year), CockpitStats::getYear, year)
                .eq(Objects.isNull(year), CockpitStats::getYear, NONE_YEAR)
                .ne(CockpitStats::getRegionCode, TOTAL)
                .orderByAsc(CockpitStats::getRegionCode));

        if (CollUtil.isEmpty(dataList)) {
            return Collections.emptyList();
        }

        return dataList.stream().map(d -> {
            QualityData data = new QualityData();
            data.setRegionCode(d.getRegionCode());
            data.setRegionName(d.getRegionName());
            data.setQuality(d.getDataQuality());
            return data;
        }).collect(Collectors.toList());
    }

    private Map<String, List<CockpitApplication>> convertCockpitApps(List<CockpitApplication> appDatas) {
        Map<String, List<CockpitApplication>> res = Maps.newHashMap();
        res.put(CockpitAppcationTypeEnum.OPTIMAL.getDesc(), CollUtil.isEmpty(appDatas) ? Collections.emptyList() :
                appDatas.stream().filter(a -> Objects.nonNull(a) && Objects.nonNull(a.getType()) &&
                        CockpitAppcationTypeEnum.OPTIMAL.getCode().equals(a.getType())).collect(Collectors.toList()));
        res.put(CockpitAppcationTypeEnum.MAJOR.getDesc(), CollUtil.isEmpty(appDatas) ? Collections.emptyList() :
                appDatas.stream().filter(a -> Objects.nonNull(a) && Objects.nonNull(a.getType()) &&
                        CockpitAppcationTypeEnum.MAJOR.getCode().equals(a.getType())).collect(Collectors.toList()));
        return res;
    }

    private CockpitStatsVO.PerformanceData convertPerformanceData(CockpitStats cockpitStats) {
        CockpitStatsVO.PerformanceData data = BeanUtil.copyProperties(cockpitStats, CockpitStatsVO.PerformanceData.class);
        data.setPerformanceTops(convertTops(cockpitStats));
        return data;
    }

    private List<PerformanceTop> convertTops(CockpitStats cockpitStats) {
        List<PerformanceTop> tops = Lists.newArrayList();
        tops.add(new PerformanceTop("一星", cockpitStats.getPerformanceTop1Score(), cockpitStats.getPerformanceTop1Name()));
        tops.add(new PerformanceTop("二星", cockpitStats.getPerformanceTop2Score(), cockpitStats.getPerformanceTop2Name()));
        tops.add(new PerformanceTop("三星", cockpitStats.getPerformanceTop3Score(), cockpitStats.getPerformanceTop3Name()));
        tops.add(new PerformanceTop("四星", cockpitStats.getPerformanceTop4Score(), cockpitStats.getPerformanceTop4Name()));
        tops.add(new PerformanceTop("五星", cockpitStats.getPerformanceTop5Score(), cockpitStats.getPerformanceTop5Name()));
        return tops;
    }

    private CockpitStatsVO.ProduceData convertProduceData(CockpitStats cockpitStats) {
        return BeanUtil.copyProperties(cockpitStats, CockpitStatsVO.ProduceData.class);
    }

    private CockpitStatsVO.ReduceData convertReduceData(CockpitStats cockpitStats) {
        CockpitStatsVO.ReduceData data = BeanUtil.copyProperties(cockpitStats, CockpitStatsVO.ReduceData.class);
        data.setAmountComparisonCharts(convertAmountComparisonChart(cockpitStats));
        return data;
    }

    private List<AmountComparisonChart> convertAmountComparisonChart(CockpitStats cockpitStats) {
        List<AmountComparisonChart> res = Lists.newArrayList();
        res.add(new AmountComparisonChart("申报", cockpitStats.getDeclaredAmountApprove(), cockpitStats.getApprovalAmountApprove(), cockpitStats.getDifferenceApprove()));
        res.add(new AmountComparisonChart("批复", cockpitStats.getDeclaredAmountApproval(), cockpitStats.getApprovalAmountApproval(), cockpitStats.getDifferenceApproval()));
        res.add(new AmountComparisonChart("合同", cockpitStats.getDeclaredAmountContract(), cockpitStats.getApprovalAmountContract(), cockpitStats.getDifferenceContract()));
        return res;
    }

    private CockpitStatsVO.ExcellentData convertExcellentData(CockpitStats cockpitStats) {
        CockpitStatsVO.ExcellentData data = BeanUtil.copyProperties(cockpitStats, CockpitStatsVO.ExcellentData.class);
        data.setExcellentProjects(Lists.newArrayList());
        return data;
    }

    private CockpitStatsVO.StatusProjectsData convertStatusProjectsData(CockpitStats cockpitStats) {
        return BeanUtil.copyProperties(cockpitStats, CockpitStatsVO.StatusProjectsData.class);
    }

    private List<CockpitStatsVO.MapProjectsData> convertMapProjectsData(CockpitStats cockpitStats, Integer year) {
        List<CockpitStatsVO.MapProjectsData> mapProjectsDatas = Lists.newArrayList();
        List<RegionDTO> regions = regionCacheHelper.listChildren(RegionConst.RC_HZ, RegionConst.RL_CITY);
        regions = regions.stream().filter(r -> r.getRegionLevel() != 2).sorted(Comparator.comparing(RegionDTO::getRegionCode)).collect(Collectors.toList());

        List<CockpitStats> cockpitStatsAll = cockpitStatsService.list(Wrappers.lambdaQuery(CockpitStats.class)
                .eq(Objects.nonNull(year), CockpitStats::getYear, year)
                .eq(Objects.isNull(year), CockpitStats::getYear, NONE_YEAR));
        Map<String, Integer> totalMap = cockpitStatsAll.stream()
                .filter(c -> Objects.nonNull(c.getRegionCode()) && Objects.nonNull(c.getProjectsTotal()))
                .collect(Collectors.toMap(CockpitStats::getRegionCode, CockpitStats::getProjectsTotal));

        for (RegionDTO region : regions) {
            CockpitStatsVO.MapProjectsData mapProjectsData = new CockpitStatsVO.MapProjectsData();
            mapProjectsData.setRegionCode(region.getRegionCode());
            mapProjectsData.setRegionName(region.getRegionName());
            mapProjectsData.setProjectsNum(totalMap.getOrDefault(mapProjectsData.getRegionCode(), 0));
            mapProjectsDatas.add(mapProjectsData);
        }
        return mapProjectsDatas;
    }

    private CockpitStatsVO.TopData convertTopData(CockpitStats cockpitStats) {
        return BeanUtil.copyProperties(cockpitStats, CockpitStatsVO.TopData.class);
    }

    private CockpitStatsVO.Expert convertExpertData(CockpitStats cockpitStats) {
        CockpitStatsVO.Expert expert = BeanUtil.copyProperties(cockpitStats, CockpitStatsVO.Expert.class);
        expert.setExpertRegionData(buildExpertRegionData(cockpitStats));
        return expert;
    }

    private List<CockpitStatsVO.ExpertRegion> buildExpertRegionData(CockpitStats cockpitStats) {
        List<CockpitStatsVO.ExpertRegion> regionData = Lists.newArrayList();
        List<RegionDTO> regions = regionCacheHelper.listChildren(RegionConst.RC_HZ, RegionConst.RL_CITY);
        regions = regions.stream().filter(r -> r.getRegionLevel() != 2).sorted(Comparator.comparing(RegionDTO::getRegionCode)).collect(Collectors.toList());

        List<CockpitStats> cs = cockpitStatsService.list();
        Map<String, Integer> csMap = cs.stream().collect(Collectors.toMap(c -> c.getRegionCode() + c.getYear(), CockpitStats::getExpertTotalNum));
        for (RegionDTO region : regions) {
            CockpitStatsVO.ExpertRegion expertRegion = new CockpitStatsVO.ExpertRegion();
            expertRegion.setRegionCode(region.getRegionCode());
            expertRegion.setRegionName(region.getRegionName());
            expertRegion.setExpertNum(csMap.getOrDefault(region.getRegionCode() + 0, 0));
            regionData.add(expertRegion);
        }
        return regionData;
    }

    private CockpitStatsVO.Monitor convertMonitor(CockpitStats cockpitStats, String regionCode) {
        CockpitStatsVO.Monitor monitor = BeanUtil.copyProperties(cockpitStats, CockpitStatsVO.Monitor.class);
        monitor.setPasswordGradeCharts(buildPasswordGradeCharts(cockpitStats));
        monitor.setSecrecyGradeCharts(buildSecrecyGradeCharts(cockpitStats));
        monitor.setMonitorSafetyInputRate(computeSafetyRate(regionCode));
        return monitor;
    }

    /**
     * 安全投入 比 图
     *
     * @param regionCode
     * @return
     */
    private List<CockpitStatsVO.SafetyInput> computeSafetyRate(String regionCode) {
        List<CockpitStats> cocks = cockpitStatsService.list(Wrappers.lambdaQuery(CockpitStats.class)
                .eq(StringUtils.isNotBlank(regionCode), CockpitStats::getRegionCode, regionCode)
                .eq(StringUtils.isBlank(regionCode), CockpitStats::getRegionCode, TOTAL)
                .in(CockpitStats::getYear, years)
                .orderByAsc(CockpitStats::getYear));
        return cocks.stream().map(c -> {
            CockpitStatsVO.SafetyInput safetyInput = new CockpitStatsVO.SafetyInput();
            safetyInput.setYear(c.getYear());
            safetyInput.setRate(Objects.nonNull(c.getMonitorDeclaredAmount()) && c.getMonitorDeclaredAmount().compareTo(BigDecimal.ZERO) > 0 ?
                    c.getMonitorSafetyInputAmount().multiply(BigDecimal.valueOf(100)).divide(c.getMonitorDeclaredAmount(), 2, RoundingMode.CEILING) : BigDecimal.ZERO);
            return safetyInput;
        }).collect(Collectors.toList());
    }

    private List<SecrecyGradeChart> buildSecrecyGradeCharts(CockpitStats cockpitStats) {
        List<SecrecyGradeChart> chars = Lists.newArrayList();
        chars.add(new SecrecyGradeChart(1, cockpitStats.getMonitorSecrecyGrade1Num()));
        chars.add(new SecrecyGradeChart(2, cockpitStats.getMonitorSecrecyGrade2Num()));
        chars.add(new SecrecyGradeChart(3, cockpitStats.getMonitorSecrecyGrade3Num()));
        chars.add(new SecrecyGradeChart(4, cockpitStats.getMonitorSecrecyGrade4Num()));
        chars.add(new SecrecyGradeChart(5, cockpitStats.getMonitorSecrecyGrade5Num()));
        return chars;
    }

    private List<PasswordGradeChart> buildPasswordGradeCharts(CockpitStats cockpitStats) {
        List<PasswordGradeChart> chars = Lists.newArrayList();
        chars.add(new PasswordGradeChart(1, cockpitStats.getMonitorPasswordGrade1Num()));
        chars.add(new PasswordGradeChart(2, cockpitStats.getMonitorPasswordGrade2Num()));
        chars.add(new PasswordGradeChart(3, cockpitStats.getMonitorPasswordGrade3Num()));
        chars.add(new PasswordGradeChart(4, cockpitStats.getMonitorPasswordGrade4Num()));
        chars.add(new PasswordGradeChart(5, cockpitStats.getMonitorPasswordGrade5Num()));
        return chars;
    }
}
