package com.njcn.event.service.majornetwork.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.device.biz.enums.DeviceResponseEnum;
import com.njcn.device.pq.api.GeneralDeviceInfoClient;
import com.njcn.device.pq.api.LineFeignClient;
import com.njcn.device.pq.pojo.dto.GeneralDeviceDTO;
import com.njcn.device.pq.pojo.param.DeviceInfoParam;
import com.njcn.device.pq.pojo.vo.AreaLineInfoVO;
import com.njcn.event.pojo.po.EventDetail;
import com.njcn.event.pojo.po.RmpEventDetailPO;
import com.njcn.event.pojo.vo.AreaAnalysisVO;
import com.njcn.event.pojo.vo.VoltageToleranceCurveVO;
import com.njcn.event.pojo.vo.VoltageToleranceCurveVO.VoltageToleranceCurveDataList;
import com.njcn.event.service.majornetwork.AreaAnalysisService;
import com.njcn.event.common.service.EventDetailService;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.enums.DicDataEnum;
import com.njcn.system.enums.DicDataTypeEnum;
import com.njcn.system.pojo.po.DictData;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;


/**
 * pqs-event
 *
 * @author cdf
 * @date 2022/6/24
 */
@Service
@RequiredArgsConstructor
public class AreaAnalysisServiceImpl implements AreaAnalysisService {
    private final GeneralDeviceInfoClient generalDeviceInfoClient;

    private final DicDataFeignClient dicDataFeignClient;

    private final LineFeignClient lineFeignClient;

    private final EventDetailService eventDetailService;
    @Override
    public AreaAnalysisVO getEventReason(DeviceInfoParam.BusinessParam deviceInfoParam) {

        //获取暂降字典信息
        DictData voltageData = dicDataFeignClient.getDicDataByCode(DicDataEnum.VOLTAGE_DIP.getCode()).getData();
        DictData shortInterruptionsData = dicDataFeignClient.getDicDataByCode(DicDataEnum.SHORT_INTERRUPTIONS.getCode()).getData();

        if(ObjectUtil.isNull(voltageData)||ObjectUtil.isNull(shortInterruptionsData)){
            throw new BusinessException(DeviceResponseEnum.DIC_GET_EMPTY);
        }
        AreaAnalysisVO areaAnalysisVO = new AreaAnalysisVO();
        List<DictData> dicReasonList = dicDataFeignClient.getDicDataByTypeName(DicDataTypeEnum.EVENT_REASON.getName()).getData();
        List<DictData> dicTypeList = dicDataFeignClient.getDicDataByTypeName(DicDataTypeEnum.EVENT_TYPE.getName()).getData();
        // 获取指定部门下的监测点集合
        List<GeneralDeviceDTO> generalDeviceDTOList = generalDeviceInfoClient.getPracticalAllDeviceInfo(deviceInfoParam).getData();
        List<String> lineIds = getAllLineIdList(generalDeviceDTOList);

        //查询数据
      //  List<AreaAnalysisVO.Children> reasonList = assData(dicReasonList, lineIds, deviceInfoParam.getSearchBeginTime(), deviceInfoParam.getSearchEndTime(), "event_reason");
        List<RmpEventDetailPO> info = eventDetailService.list(new QueryWrapper<RmpEventDetailPO>()
                .select("advance_reason,advance_type,count(event_id) as count")
                .in("measurement_point_id", lineIds)
                .in("event_type", Stream.of(voltageData.getId(),shortInterruptionsData.getId()).collect(Collectors.toList()))

//                .eq("event_type", voltageData.getId())
                .in("advance_reason", dicReasonList.stream().map(DictData::getId).collect(Collectors.toList()))
                .in("advance_type", dicTypeList.stream().map(DictData::getId).collect(Collectors.toList()))
                .ge(StrUtil.isNotBlank(deviceInfoParam.getSearchBeginTime()),"start_time" ,DateUtil.beginOfDay(DateUtil.parse(deviceInfoParam.getSearchBeginTime())))
                .le(StrUtil.isNotBlank(deviceInfoParam.getSearchEndTime()), "start_time", DateUtil.endOfDay(DateUtil.parse(deviceInfoParam.getSearchEndTime())))
                .groupBy("measurement_point_id,advance_reason,advance_type")
        );
        List<AreaAnalysisVO.Children> reasonList = assDataPQ(info, dicReasonList);


        //暂降类型特殊处理
        DictData dictData = dicReasonList.stream().filter(item->DicDataEnum.SHORT_TROUBLE.getCode().equals(item.getCode())).findFirst().get();
        //相间
        List<String> dicIdsXi = dicTypeList.stream().filter(item->
                ObjectUtil.equals(DicDataEnum.INTERPHASE_AB.getCode(),item.getCode())||
                ObjectUtil.equals(DicDataEnum.INTERPHASE_BC.getCode(),item.getCode())||
                ObjectUtil.equals(DicDataEnum.INTERPHASE_AC.getCode(),item.getCode())
        ).map(DictData::getId).collect(Collectors.toList());
        //接地
        List<String> dicIdsOne = dicTypeList.stream().filter(item->
                ObjectUtil.equals(DicDataEnum.PHASE_A.getCode(),item.getCode())||
                ObjectUtil.equals(DicDataEnum.PHASE_B.getCode(),item.getCode())||
                ObjectUtil.equals(DicDataEnum.PHASE_C.getCode(),item.getCode())
        ).map(DictData::getId).collect(Collectors.toList());
        //三相接地
        List<String> dicIdsThree = dicTypeList.stream().filter(item->ObjectUtil.equals(DicDataEnum.GROUND_ABC.getCode(),item.getCode())).map(DictData::getId).collect(Collectors.toList());
        //其他
        List<String> dicIdsOther = dicTypeList.stream().filter(item->ObjectUtil.equals(DicDataEnum.TYPE_REST.getCode(),item.getCode())).map(DictData::getId).collect(Collectors.toList());
        //两相接地
        List<String> dicIdsDouble = dicTypeList.stream().filter(item->
                ObjectUtil.equals(DicDataEnum.GROUND_AB.getCode(),item.getCode())||
                ObjectUtil.equals(DicDataEnum.GROUND_BC.getCode(),item.getCode())||
                ObjectUtil.equals(DicDataEnum.GROUND_AC.getCode(),item.getCode())
        ).map(DictData::getId).collect(Collectors.toList());

        Map<String, List<String>> stringListMap = new HashMap<>();
        stringListMap.put("单相接地",dicIdsOne);
        stringListMap.put("两相接地",dicIdsDouble);
        stringListMap.put("三相短路",dicIdsThree);
        stringListMap.put("相间故障",dicIdsXi);
        stringListMap.put("未知",dicIdsOther);

//        List<AreaAnalysisVO.Children> typeList = assReason(stringListMap,lineIds,deviceInfoParam.getSearchBeginTime(), deviceInfoParam.getSearchEndTime(),dictData.getId());
        List<AreaAnalysisVO.Children> typeList = assReasonPQ(stringListMap, info, dictData.getId());

        areaAnalysisVO.setReason(reasonList);
        areaAnalysisVO.setType(typeList);
        return areaAnalysisVO;
    }

    /**
     * 获取电压容忍度曲线兼容性统计
     *
     * @param deviceInfoParam 查询参数
     * @return 电压容忍度曲线兼容性统计
     */
    @Override
    public VoltageToleranceCurveVO getVoltageToleranceCurve(DeviceInfoParam.BusinessParam deviceInfoParam) {
        // 获取指定部门下的监测点集合
        if(CollUtil.isEmpty(deviceInfoParam.getScale())&&(CollUtil.isEmpty(deviceInfoParam.getLoadType()))){
            return VoltageToleranceCurveVO.empty();
        }
        List<GeneralDeviceDTO> generalDeviceDTOList = generalDeviceInfoClient.getPracticalAllDeviceInfo(deviceInfoParam).getData();
        if (CollUtil.isEmpty(generalDeviceDTOList)) {
            return VoltageToleranceCurveVO.empty();
        }

        List<String> lineIds = getAllLineIdList(generalDeviceDTOList);
        if (CollUtil.isEmpty(lineIds)) {
            return VoltageToleranceCurveVO.empty();
        }

        List<AreaLineInfoVO> getBaseLineAreaInfo = lineFeignClient.getBaseLineAreaInfo(lineIds).getData();
        if (CollUtil.isEmpty(getBaseLineAreaInfo)) {
            return VoltageToleranceCurveVO.empty();
        }

        Map<String, AreaLineInfoVO> areaLineInfoVOMap =
                getBaseLineAreaInfo.parallelStream().collect(Collectors.toConcurrentMap(AreaLineInfoVO::getLineId,
                        Function.identity()));

//        List<EventDetail> eventDetailList = pqsEventDetailQuery.selectList(Arrays.asList("time","line_id", "persist_time", "event_value"),
//                lineIdOr(lineIds), timeAnd(beginOfDay(deviceInfoParam.getSearchBeginTime()),
//                        endOfDay(deviceInfoParam.getSearchEndTime())));

        //数据暂降查询
        List<RmpEventDetailPO> infoPo = eventDetailService.list(new LambdaQueryWrapper<RmpEventDetailPO>()
                .in(RmpEventDetailPO::getMeasurementPointId, lineIds)
                .ge(StrUtil.isNotBlank(deviceInfoParam.getSearchBeginTime()), RmpEventDetailPO::getStartTime,DateUtil.beginOfDay(DateUtil.parse(deviceInfoParam.getSearchBeginTime())))
                .le(StrUtil.isNotBlank(deviceInfoParam.getSearchEndTime()), RmpEventDetailPO::getStartTime, DateUtil.endOfDay(DateUtil.parse(deviceInfoParam.getSearchEndTime())))
        );
        List<EventDetail> eventDetailList= BeanUtil.copyToList(infoPo,EventDetail.class);
        if (CollUtil.isEmpty(eventDetailList)) {
            return VoltageToleranceCurveVO.empty();
        }

        List<VoltageToleranceCurveDataList> curveDataList = eventDetailList.parallelStream()
                .map(dto -> {
                    AreaLineInfoVO info = areaLineInfoVOMap.get(dto.getLineId());

                    VoltageToleranceCurveDataList voltageToleranceCurve = new VoltageToleranceCurveDataList();
                    voltageToleranceCurve.setLineId(dto.getLineId());
                    voltageToleranceCurve.setLineName(info.getLineName());
                    voltageToleranceCurve.setEventId(dto.getEventId());
                    voltageToleranceCurve.setPersistTime(dto.getDuration());
                    voltageToleranceCurve.setEventValue(dto.getFeatureAmplitude());
                    voltageToleranceCurve.setTime(dto.getStartTime());
                    voltageToleranceCurve.setGdName(info.getGdName());
                    voltageToleranceCurve.setSubName(info.getSubName());
                    return voltageToleranceCurve;
                })
                //.sorted(VoltageToleranceCurveDataList.sortAscTime())
                .collect(Collectors.toCollection(() -> Collections.synchronizedList(new ArrayList<>())));

        return VoltageToleranceCurveVO.buildVO(eventDetailList.size(), curveDataList);
    }

    /**
     * 获取全部的LineID
     *
     * @param generalDeviceDTOList Device
     * @return lineIds
     */
    private List<String> getAllLineIdList(List<GeneralDeviceDTO> generalDeviceDTOList) {
        return generalDeviceDTOList.stream().flatMap(dto -> dto.getLineIndexes().stream()).collect(Collectors.toList());
    }

    private List<AreaAnalysisVO.Children> assDataPQ(List<RmpEventDetailPO> info,List<DictData> dicReasonList) {
        List<AreaAnalysisVO.Children> reasonList = new ArrayList<>();
        Map<String, List<RmpEventDetailPO>> reasonMap = info.stream().collect(Collectors.groupingBy(RmpEventDetailPO::getAdvanceReason));
        AreaAnalysisVO.Children allType ;
        Integer allCount = 0;
        for (DictData dictData : dicReasonList) {
            allType = new AreaAnalysisVO.Children();
            if(reasonMap.containsKey(dictData.getId())){
                Integer sum = reasonMap.get(dictData.getId()).stream().mapToInt(RmpEventDetailPO::getCount).sum();
                allCount+=sum;
                allType.setValue(sum);
            }else{
                allType.setValue(0);
            }
            allType.setName(dictData.getName());
            reasonList.add(allType);
        }
        AreaAnalysisVO.Children zj = new AreaAnalysisVO.Children();
        zj.setName("总计");
        zj.setValue(allCount);
        reasonList.add(zj);
/*
        List<AreaAnalysisVO.Children> reasonList = new ArrayList<>();
        //根据暂降原因分组
        Map<String, String> reasonMap = dicReasonList.stream().collect(Collectors.toMap(DictData::getId,DictData::getName));
        //将数据进行分组
        Map<String, Long> infoMap = info.stream().collect(Collectors.groupingBy(
                x->{
                    return reasonMap.get(x.getAdvanceReason());
                }, Collectors.counting()));

        //排除不存在的字典数据集合
        List<DictData> notDicData = dicReasonList.stream().filter(r -> !infoMap.containsKey(r.getName()))
                .collect(Collectors.toList());
        AreaAnalysisVO.Children allType ;
        if(CollUtil.isNotEmpty(notDicData)){
            for (DictData notDicDatum : notDicData) {
                allType = new AreaAnalysisVO.Children();
                allType.setName(notDicDatum.getName());
                allType.setValue(0);
                reasonList.add(allType);
            }
        }
        Integer allCount = 0;
        for (String s : infoMap.keySet()) {
            allType = new AreaAnalysisVO.Children();
            allType.setName(s);
            int count = Math.toIntExact(infoMap.get(s));
            allType.setValue(count);
            allCount += count;
            reasonList.add(allType);
        }
        AreaAnalysisVO.Children zj = new AreaAnalysisVO.Children();
        zj.setName("总计");
        zj.setValue(allCount);
        reasonList.add(zj);*/
        return reasonList;
    }

    private List<AreaAnalysisVO.Children> assReasonPQ(Map<String, List<String>> stringListMap, List<RmpEventDetailPO> info, String typeId){
        List<AreaAnalysisVO.Children> reasonList = new ArrayList<>();
        Integer allCount = 0;
        for (Map.Entry<String, List<String>> stringListEntry : stringListMap.entrySet()) {
            List<String> value = stringListEntry.getValue();
            Integer count = info.stream().filter(x -> value.contains(x.getAdvanceType())).mapToInt(RmpEventDetailPO::getCount).sum();
            AreaAnalysisVO.Children  allType = new AreaAnalysisVO.Children();
            allType.setName(stringListEntry.getKey());
            allType.setValue(count);
            allCount += count;
            reasonList.add(allType);
        }

        AreaAnalysisVO.Children allType = new AreaAnalysisVO.Children();
        allType.setName("总计");
        allType.setValue(allCount);
        reasonList.add(allType);
        return reasonList;
    }

   /* private List<AreaAnalysisVO.Children> assData(List<DictData> dicList, List<String> lineIds, String startTime, String endTime, String type) {
        List<AreaAnalysisVO.Children> reasonList = new ArrayList<>();
        Integer allCount = 0;
        for (DictData reason : dicList) {
            // 暂降原因类型次数
            Integer count = pqsEventDetailQuery.selectCount(Collections.singletonList(type),
                    lineIdOr(lineIds), timeAndType(beginOfDay(startTime),
                            endOfDay(endTime), type, reason.getId()));

            AreaAnalysisVO.Children children = new AreaAnalysisVO.Children();
            children.setName(reason.getName());
            children.setValue(count);
            allCount += count;
            reasonList.add(children);
        }
        AreaAnalysisVO.Children allType = new AreaAnalysisVO.Children();
        allType.setName("总计");
        allType.setValue(allCount);
        reasonList.add(allType);
        return reasonList;
    }

    private List<AreaAnalysisVO.Children> assReason(Map<String, List<String>> stringListMap, List<String> lineIds, String startTime, String endTime, String typeId){
        List<AreaAnalysisVO.Children> reasonList = new ArrayList<>();
        Integer allCount = 0;
        for (Map.Entry<String, List<String>> stringListEntry : stringListMap.entrySet()) {
            // 暂降原因类型次数
            List<List<Clause>> clauseList = new ArrayList<>();
            List<Clause> clauses = new ArrayList<>();
            for (String id : stringListEntry.getValue()) {
                clauses.add(eq("event_reason", id));
            }
            clauseList.add(lineIdOr(lineIds));
            clauseList.add(clauses);

            Integer count = pqsEventDetailQuery.selectCountUp(Collections.singletonList("event_type"), clauseList
                    , timeAndType(beginOfDay(startTime),
                            endOfDay(endTime), "event_reason", typeId));

            AreaAnalysisVO.Children children = new AreaAnalysisVO.Children();
            children.setName(stringListEntry.getKey());
            children.setValue(count);
            allCount += count;
            reasonList.add(children);

        }

        AreaAnalysisVO.Children allType = new AreaAnalysisVO.Children();
        allType.setName("总计");
        allType.setValue(allCount);
        reasonList.add(allType);
        return reasonList;
    }*/
}
