package com.ningdatech.carapi.analysis.manage;

import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.carapi.analysis.entity.WarnAnalysisCar;
import com.ningdatech.carapi.analysis.entity.WarnAnalysisCompany;
import com.ningdatech.carapi.analysis.entity.vo.CompanyWarnStatisticsVo;
import com.ningdatech.carapi.analysis.service.IWarnAnalysisCarService;
import com.ningdatech.carapi.analysis.service.IWarnAnalysisCompanyService;
import com.ningdatech.carapi.common.model.DataChartVo;
import com.ningdatech.carapi.common.model.MapDataVO;
import com.ningdatech.carapi.safe.entity.NdInsureInfo;
import com.ningdatech.carapi.safe.service.INdInsureInfoService;
import com.ningdatech.carapi.sys.entity.dto.CompanyDTO;
import com.ningdatech.carapi.sys.entity.dto.RegionDTO;
import com.ningdatech.carapi.sys.helper.CompaniesCacheHelper;
import com.ningdatech.carapi.sys.helper.RegionsCacheHelper;
import com.ningdatech.carapi.sys.service.CompanyService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;

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

/**
 * <p>
 * DataViewController
 * </p>
 *
 * @author WendyYang
 * @since 15:34 2022/10/25
 */
@Component
@AllArgsConstructor
public class AnalysisEvalDataViewManage {

    private final INdInsureInfoService insureInfoService;
    private final IWarnAnalysisCompanyService companyWarnAnalysisService;
    private final IWarnAnalysisCarService carWarnAnalysisService;

    private final RegionsCacheHelper regionsCacheHelper;
    private final CompaniesCacheHelper companiesCacheHelper;
    private final CompanyService companyService;

    public List<DataChartVo> insuranceOrgStatistics(Long regionId) {
        List<Long> childIds = regionsCacheHelper.listChildRegionId(regionId);
        QueryWrapper<NdInsureInfo> query = Wrappers.query();
        query.select("count(distinct car_plate) as `count`, insure_company as groupKey");
        query.in("region_id", childIds);
        query.groupBy("insure_company");
        List<Map<String, Object>> maps = insureInfoService.listMaps(query);
        if (maps.isEmpty()) {
            return Collections.emptyList();
        }
        int total = CollUtils.sum(maps, (ToIntFunction<Map<String, Object>>) w -> Long.valueOf(w.get("count").toString()).intValue());
        return maps.stream().map(w -> {
            DataChartVo vo = new DataChartVo();
            vo.setLabel(w.get("groupKey").toString());
            vo.setValue(Long.valueOf(w.get("count").toString()).intValue());
            String percent = BigDecimal.valueOf(vo.getValue() * 100)
                    .divide(BigDecimal.valueOf(total), 2, RoundingMode.HALF_UP)
                    .stripTrailingZeros().toPlainString();
            vo.setPercent(percent);
            return vo;
        }).collect(Collectors.toList());
    }

    public List<CompanyWarnStatisticsVo> companyWarnStatistics(Long regionId) {
        List<Long> regionIds = regionsCacheHelper.listChildRegionId(regionId);
        QueryWrapper<WarnAnalysisCompany> query = Wrappers.query();
        query.select("company_id companyId, danger_level dangerLevel");
        query.in("region_id", regionIds);
        List<Map<String, Object>> analysisCompanies = companyWarnAnalysisService.listMaps(query);
        if (analysisCompanies.size() == 0) {
            return Collections.emptyList();
        }
        List<CompanyWarnStatisticsVo> result = new ArrayList<>();
        analysisCompanies.forEach(w -> {
            CompanyDTO company = companiesCacheHelper.getById(MapUtil.getLong(w, "companyId"));
            if (Objects.isNull(company)) {
                return;
            }
            CompanyWarnStatisticsVo vo = CompanyWarnStatisticsVo.builder()
                    .companyAddress(company.getAddress())
                    .companyName(company.getName())
                    .dangerLevel(MapUtil.getInt(w, "dangerLevel"))
                    .longitude(company.getLongitude())
                    .latitude(company.getLatitude())
                    .build();
            result.add(vo);
        });
        return result;
    }

    public List<MapDataVO> carWarnStatistics(Long regionId) {
        List<Long> regionIds = regionsCacheHelper.listChildRegionId(regionId);
        QueryWrapper<WarnAnalysisCar> query = Wrappers.query();
        query.select("count(1) `count`, region_id regionId");
        query.in("region_id", regionIds);
        query.groupBy("region_id");
        List<Map<String, Object>> carAnalysis = carWarnAnalysisService.listMaps(query);
        if (carAnalysis.size() == 0) {
            return Collections.emptyList();
        }
        Map<RegionDTO, List<Long>> childrenMap = regionsCacheHelper.getChildrenMap(regionId, true);
        List<MapDataVO> result = new ArrayList<>();
        childrenMap.forEach((k, v) -> {
            MapDataVO mapData = MapDataVO.builder()
                    .regionName(k.getRegionName())
                    .regionCode(k.getRegionCode())
                    .regionId(k.getId())
                    .value(0)
                    .build();
            carAnalysis.removeIf(w -> {
                Long currRegionId = MapUtil.getLong(w, "regionId");
                if (v.contains(currRegionId)) {
                    mapData.setValue(MapUtil.getInt(w, "count") + mapData.getValue());
                    return true;
                }
                return false;
            });
            result.add(mapData);
        });
        return result;
    }

    private <T> QueryWrapper<T> buildCountQueryGroupByRegion(List<Long> regionIds, Integer dangerLevel) {
        QueryWrapper<T> query = Wrappers.query();
        query.select("count(1) as `count`, region_id as regionId");
        query.in("region_id", regionIds);
        query.eq(Objects.nonNull(dangerLevel),"danger_level", dangerLevel);
        query.groupBy("region_id");
        return query;
    }

    public List<DataChartVo> companyWarnStatisticsByLevel(Long regionId, Integer dangerLevel) {
        List<DataChartVo> result = new ArrayList<>();
        List<Long> regionIds = regionsCacheHelper.listChildRegionId(regionId);
        QueryWrapper<WarnAnalysisCompany> query = buildCountQueryGroupByRegion(regionIds, dangerLevel);
        List<Map<String, Object>> analysisCompanies = companyWarnAnalysisService.listMaps(query);
        Map<RegionDTO, List<Long>> childrenMap = regionsCacheHelper.getChildrenMap(regionId, true);
        // 如果是区县一级的,只返回区县一级的名字和数量
        if (childrenMap.size() == 0) {
            RegionDTO regionDto = regionsCacheHelper.getByRegionId(regionId);
            String regionName = regionDto.getRegionName();
            DataChartVo vo = new DataChartVo(regionName, 0);
            analysisCompanies.forEach(w -> {
                vo.setValue(vo.getValue() + MapUtil.getInt(w, "count"));
            });
            result.add(vo);
            return result;
        } else {
            childrenMap.forEach((k, v) -> {
                DataChartVo vo = new DataChartVo(k.getRegionName(), 0);
                analysisCompanies.forEach(w -> {
                    Long currRegionId = MapUtil.getLong(w, "regionId");
                    if (v.contains(currRegionId)) {
                        vo.setValue(vo.getValue() + MapUtil.getInt(w, "count"));
                    }
                });
                result.add(vo);
            });
            return result;
        }
    }

    public List<DataChartVo> carWarnStatisticsByLevel(Long regionId, Integer dangerLevel) {
        List<DataChartVo> result = new ArrayList<>();
        List<Long> regionIds = regionsCacheHelper.listChildRegionId(regionId);
        QueryWrapper<WarnAnalysisCar> query = buildCountQueryGroupByRegion(regionIds, dangerLevel);
        List<Map<String, Object>> analysisCompanies = carWarnAnalysisService.listMaps(query);
        Map<RegionDTO, List<Long>> childrenMap = regionsCacheHelper.getChildrenMap(regionId, true);
        childrenMap.forEach((k, v) -> {
            DataChartVo vo = new DataChartVo(k.getRegionName(), 0);
            analysisCompanies.forEach(w -> {
                Long currRegionId = MapUtil.getLong(w, "regionId");
                if (v.contains(currRegionId)) {
                    vo.setValue(vo.getValue() + MapUtil.getInt(w, "count"));
                }
            });
            result.add(vo);
        });
        return result;
    }

}
