package com.njcn.gather.storage.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.njcn.db.mybatisplus.handler.DynamicTableNameHandler;
import com.njcn.db.mybatisplus.service.impl.ReplenishMybatisServiceImpl;
import com.njcn.gather.storage.mapper.DetectionDataDealMapper;
import com.njcn.gather.storage.pojo.po.*;
import com.njcn.gather.storage.service.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 接收检测的原始数据以及计算后的结果
 *
 * @author chendaofei
 */
@Service
@RequiredArgsConstructor
public class DetectionDataServiceImpl extends ReplenishMybatisServiceImpl<DetectionDataDealMapper, SimAndDigHarmonicResult> implements DetectionDataDealService {

    private final SimAndDigNonHarmonicService simAndDigNonHarmonicService;
    private final SimAndDigHarmonicService simAndDigHarmonicService;
    private final ContrastNonHarmonicService contrastNonHarmonicService;
    private final ContrastHarmonicService contrastHarmonicService;
    private final DetectionDataDealMapper detectionDataDealMapper;


    @Override
    @Transactional
    public Boolean acceptNonHarmonic(List<? extends BaseResult> nonHarmonicResultList, String code) {
        if (CollUtil.isNotEmpty(nonHarmonicResultList)) {
            String adNonTable = "ad_non_harmonic_";
            DynamicTableNameHandler.setTableName(adNonTable + code);

            if (nonHarmonicResultList.get(0) instanceof SimAndDigNonHarmonicResult) {
                List<SimAndDigNonHarmonicResult> simAndDigNonHarmonicResults = BeanUtil.copyToList(nonHarmonicResultList, SimAndDigNonHarmonicResult.class);
                List<String> monitorIds = simAndDigNonHarmonicResults.stream().map(SimAndDigNonHarmonicResult::getDevMonitorId).distinct().collect(Collectors.toList());
                if (CollUtil.isNotEmpty(monitorIds)) {
                    simAndDigNonHarmonicService.remove(new LambdaQueryWrapper<SimAndDigNonHarmonicResult>().in(SimAndDigNonHarmonicResult::getDevMonitorId, monitorIds)
                            .eq(SimAndDigNonHarmonicResult::getScriptId, simAndDigNonHarmonicResults.get(0).getScriptId())
                            .eq(SimAndDigNonHarmonicResult::getSort, simAndDigNonHarmonicResults.get(0).getSort()));
                    simAndDigNonHarmonicService.saveBatch(simAndDigNonHarmonicResults, 100);
                }
            }

            if (nonHarmonicResultList.get(0) instanceof ContrastNonHarmonicResult) {
                List<ContrastNonHarmonicResult> contrastNonHarmonicResults = BeanUtil.copyToList(nonHarmonicResultList, ContrastNonHarmonicResult.class);
                contrastNonHarmonicService.saveBatch(contrastNonHarmonicResults);
            }

            DynamicTableNameHandler.remove();
            return true;
        }
        return false;
    }

    @Override
    @Transactional
    public Boolean acceptHarmonic(List<? extends BaseResult> harmonicResultList, String code) {
        if (CollUtil.isNotEmpty(harmonicResultList)) {
            String adTable = "ad_harmonic_";
            DynamicTableNameHandler.setTableName(adTable + code);

            if (harmonicResultList.get(0) instanceof SimAndDigHarmonicResult) {
                List<SimAndDigHarmonicResult> simAndDigHarmonicResultList = BeanUtil.copyToList(harmonicResultList, SimAndDigHarmonicResult.class);
                List<String> monitorIds = simAndDigHarmonicResultList.stream().map(SimAndDigHarmonicResult::getDevMonitorId).distinct().collect(Collectors.toList());
                if (CollUtil.isNotEmpty(monitorIds)) {
                    simAndDigHarmonicService.remove(new LambdaQueryWrapper<SimAndDigHarmonicResult>().in(SimAndDigHarmonicResult::getDevMonitorId, monitorIds)
                            .eq(SimAndDigHarmonicResult::getScriptId, simAndDigHarmonicResultList.get(0).getScriptId())
                            .eq(SimAndDigHarmonicResult::getSort, simAndDigHarmonicResultList.get(0).getSort()));
                    simAndDigHarmonicService.saveBatch(simAndDigHarmonicResultList);
                }
            }

            if (harmonicResultList.get(0) instanceof ContrastHarmonicResult) {
                List<ContrastHarmonicResult> contrastHarmonicResultList = BeanUtil.copyToList(harmonicResultList, ContrastHarmonicResult.class);
                contrastHarmonicService.saveBatch(contrastHarmonicResultList);
            }

            DynamicTableNameHandler.remove();
            return true;
        }
        return false;
    }

    @Override
    @Transactional
    public Boolean acceptNonHarmonicResult(List<? extends BaseResult> nonHarmonicResultList, String code) {
        if (CollUtil.isNotEmpty(nonHarmonicResultList)) {
            String adNonTableResult = "ad_non_harmonic_result_";
            DynamicTableNameHandler.setTableName(adNonTableResult + code);
            if (nonHarmonicResultList.get(0) instanceof SimAndDigNonHarmonicResult) {
                List<SimAndDigNonHarmonicResult> simAndDigNonHarmonicResultList = BeanUtil.copyToList(nonHarmonicResultList, SimAndDigNonHarmonicResult.class);
                List<String> monitorIds = simAndDigNonHarmonicResultList.stream().map(SimAndDigNonHarmonicResult::getDevMonitorId).distinct().collect(Collectors.toList());
                if (CollUtil.isNotEmpty(monitorIds)) {
                    simAndDigNonHarmonicService.remove(new LambdaQueryWrapper<SimAndDigNonHarmonicResult>().in(SimAndDigNonHarmonicResult::getDevMonitorId, monitorIds)
                            .eq(SimAndDigNonHarmonicResult::getScriptId, simAndDigNonHarmonicResultList.get(0).getScriptId())
                            .eq(SimAndDigNonHarmonicResult::getSort, simAndDigNonHarmonicResultList.get(0).getSort()));
                    simAndDigNonHarmonicService.saveBatch(simAndDigNonHarmonicResultList, 100);
                }
            }
            if (nonHarmonicResultList.get(0) instanceof ContrastNonHarmonicResult) {
                List<ContrastNonHarmonicResult> contrastNonHarmonicResultList = BeanUtil.copyToList(nonHarmonicResultList, ContrastNonHarmonicResult.class);
                ContrastNonHarmonicResult contrastNonHarmonicResult = contrastNonHarmonicResultList.get(0);
                contrastNonHarmonicService.remove(new LambdaQueryWrapper<ContrastNonHarmonicResult>().in(ContrastNonHarmonicResult::getDevMonitorId, contrastNonHarmonicResult.getDevMonitorId())
                        .eq(ContrastNonHarmonicResult::getNum, contrastNonHarmonicResult.getNum())
                        .eq(ContrastNonHarmonicResult::getAdType, contrastNonHarmonicResult.getAdType())
                        .eq(ContrastNonHarmonicResult::getDataType, contrastNonHarmonicResult.getDataType())
                        .eq(ObjectUtil.isNotNull(contrastNonHarmonicResult.getWaveNum()), ContrastNonHarmonicResult::getWaveNum, contrastNonHarmonicResult.getWaveNum())
                        .isNull(ObjectUtil.isNull(contrastNonHarmonicResult.getWaveNum()), ContrastNonHarmonicResult::getWaveNum));
                contrastNonHarmonicService.saveBatch(contrastNonHarmonicResultList);
            }
            DynamicTableNameHandler.remove();
        }
        return true;
    }

    @Override
    @Transactional
    public Boolean acceptHarmonicResult(List<? extends BaseResult> harmonicResultList, String code) {
        if (CollUtil.isNotEmpty(harmonicResultList)) {
            String adTableResult = "ad_harmonic_result_";
            DynamicTableNameHandler.setTableName(adTableResult + code);
            if (harmonicResultList.get(0) instanceof SimAndDigHarmonicResult) {
                List<SimAndDigHarmonicResult> simAndDigHarmonicResultList = BeanUtil.copyToList(harmonicResultList, SimAndDigHarmonicResult.class);
                List<String> monitorIds = simAndDigHarmonicResultList.stream().map(SimAndDigHarmonicResult::getDevMonitorId).distinct().collect(Collectors.toList());
                if (CollUtil.isNotEmpty(monitorIds)) {
                    simAndDigHarmonicService.remove(new LambdaQueryWrapper<SimAndDigHarmonicResult>().in(SimAndDigHarmonicResult::getDevMonitorId, monitorIds)
                            .eq(SimAndDigHarmonicResult::getScriptId, simAndDigHarmonicResultList.get(0).getScriptId())
                            .eq(SimAndDigHarmonicResult::getSort, simAndDigHarmonicResultList.get(0).getSort()));
                    simAndDigHarmonicService.saveBatch(simAndDigHarmonicResultList, 100);
                }
            }

            if (harmonicResultList.get(0) instanceof ContrastHarmonicResult) {
                List<ContrastHarmonicResult> contrastHarmonicResultList = BeanUtil.copyToList(harmonicResultList, ContrastHarmonicResult.class);
                ContrastHarmonicResult contrastHarmonicResult = contrastHarmonicResultList.get(0);
                contrastHarmonicService.remove(new LambdaQueryWrapper<ContrastHarmonicResult>().eq(ContrastHarmonicResult::getDevMonitorId, contrastHarmonicResult.getDevMonitorId())
                        .eq(ContrastHarmonicResult::getNum, contrastHarmonicResult.getNum())
                        .eq(ContrastHarmonicResult::getAdType, contrastHarmonicResult.getAdType())
                        .eq(ContrastHarmonicResult::getDataType, contrastHarmonicResult.getDataType())
                        .eq(ObjectUtil.isNotNull(contrastHarmonicResult.getWaveNum()), ContrastHarmonicResult::getWaveNum, contrastHarmonicResult.getWaveNum())
                        .isNull(ObjectUtil.isNull(contrastHarmonicResult.getWaveNum()), ContrastHarmonicResult::getWaveNum));
                contrastHarmonicService.saveBatch(contrastHarmonicResultList);
            }
            DynamicTableNameHandler.remove();
            return true;
        }
        return false;
    }

    @Override
    public Map<String, Integer> devResult(boolean isContrast, List<String> ids, List<String> adType, String code) {
        Map<String, Integer> map = new HashMap<>(2);
        List<BaseResult> noHarm = new ArrayList<>();
        List<BaseResult> harm = new ArrayList<>();
        if (isContrast) {
            DynamicTableNameHandler.setTableName("ad_non_harmonic_result_" + code);
            LambdaQueryWrapper<ContrastNonHarmonicResult> wrapper1 = new LambdaQueryWrapper<ContrastNonHarmonicResult>()
                    .in(CollUtil.isNotEmpty(adType), ContrastNonHarmonicResult::getAdType, adType);
            wrapper1.and(w -> {
                for (String id : ids) {
                    w.or().like(ContrastNonHarmonicResult::getDevMonitorId, id);
                }
            });

            List<ContrastNonHarmonicResult> nonHarmonicResultList = contrastNonHarmonicService.list(wrapper1);
            Map<String, List<ContrastNonHarmonicResult>> chnMap1 = nonHarmonicResultList.stream().collect(Collectors.groupingBy(x -> x.getDevMonitorId().split("_")[1], Collectors.toList()));
            chnMap1.forEach((chn, vList) -> {
                ContrastNonHarmonicResult contrastNonHarmonicResult = vList.stream().max(Comparator.comparing(ContrastNonHarmonicResult::getNum)).get();
                List<ContrastNonHarmonicResult> maxList = vList.stream().filter(x -> x.getNum() == contrastNonHarmonicResult.getNum()).collect(Collectors.toList());
                noHarm.addAll(maxList);
            });
            DynamicTableNameHandler.remove();

            DynamicTableNameHandler.setTableName("ad_harmonic_result_" + code);
            LambdaQueryWrapper<ContrastHarmonicResult> wrapper2 = new LambdaQueryWrapper<ContrastHarmonicResult>()
                    .in(CollUtil.isNotEmpty(adType), ContrastHarmonicResult::getAdType, adType);
            wrapper2.and(w -> {
                for (String id : ids) {
                    w.like(ContrastHarmonicResult::getDevMonitorId, id);
                }
            });

            List<ContrastHarmonicResult> harmonicResultList = contrastHarmonicService.list(wrapper2);
            Map<String, List<ContrastHarmonicResult>> chnMap2 = harmonicResultList.stream().collect(Collectors.groupingBy(x -> x.getDevMonitorId().split("_")[1], Collectors.toList()));
            chnMap2.forEach((chn, vList) -> {
                ContrastHarmonicResult contrastHarmonicResult = vList.stream().max(Comparator.comparing(ContrastHarmonicResult::getNum)).get();
                List<ContrastHarmonicResult> maxList = vList.stream().filter(x -> x.getNum() == contrastHarmonicResult.getNum()).collect(Collectors.toList());
                harm.addAll(maxList);
            });
            DynamicTableNameHandler.remove();
        } else {
            List<Integer> disabledScriptDtlIndexs = detectionDataDealMapper.listDisabledScriptDtlIndexs(ids.get(0));

            DynamicTableNameHandler.setTableName("ad_non_harmonic_result_" + code);
            LambdaQueryWrapper<SimAndDigNonHarmonicResult> wrapper1 = new LambdaQueryWrapper<SimAndDigNonHarmonicResult>()
                    .notIn(CollUtil.isNotEmpty(disabledScriptDtlIndexs), SimAndDigNonHarmonicResult::getSort, disabledScriptDtlIndexs)
                    .in(CollUtil.isNotEmpty(adType), SimAndDigNonHarmonicResult::getAdType, adType);
            for (String id : ids) {
                wrapper1.like(SimAndDigNonHarmonicResult::getDevMonitorId, id);
            }
            noHarm.addAll(simAndDigNonHarmonicService.list(wrapper1));
            DynamicTableNameHandler.remove();

            DynamicTableNameHandler.setTableName("ad_harmonic_result_" + code);
            LambdaQueryWrapper<SimAndDigHarmonicResult> wrapper2 = new LambdaQueryWrapper<SimAndDigHarmonicResult>()
                    .notIn(CollUtil.isNotEmpty(disabledScriptDtlIndexs), SimAndDigHarmonicResult::getSort, disabledScriptDtlIndexs)
                    .in(CollUtil.isNotEmpty(adType), SimAndDigHarmonicResult::getAdType, adType);
            for (String id : ids) {
                wrapper2.like(SimAndDigHarmonicResult::getDevMonitorId, id);
            }
            harm.addAll(this.list(wrapper2));
            DynamicTableNameHandler.remove();
        }

        Map<String, List<Integer>> noHarmMap = noHarm.stream().collect(Collectors.groupingBy(x -> x.getDevMonitorId().split("_")[0],
                Collectors.mapping(BaseResult::getResultFlag, Collectors.toList())));
        Map<String, List<Integer>> harmMap = harm.stream().collect(Collectors.groupingBy(x -> x.getDevMonitorId().split("_")[0],
                Collectors.mapping(BaseResult::getResultFlag, Collectors.toList())));
        for (String id : ids) {
            String s = id.split("_")[0];
            List<Integer> resultFlags = new ArrayList<>();
            if (noHarmMap.containsKey(s)) {
                resultFlags.addAll(noHarmMap.get(s));
            }
            if (harmMap.containsKey(s)) {
                resultFlags.addAll(harmMap.get(s));
            }
            map.put(id, isResultFlag(resultFlags));
        }
        return map;
    }

    @Override
    public Integer getMonitorResult(String monitorId, List<String> adTypes, String dataSource, Integer num, Integer waveNum, String code) {
        DynamicTableNameHandler.setTableName("ad_non_harmonic_result_" + code);
        LambdaQueryWrapper<ContrastNonHarmonicResult> wrapper1 = new LambdaQueryWrapper<ContrastNonHarmonicResult>()
                .like(ContrastNonHarmonicResult::getDevMonitorId, monitorId)
                .in(CollUtil.isNotEmpty(adTypes), ContrastNonHarmonicResult::getAdType, adTypes)
                .eq(ContrastNonHarmonicResult::getDataType, dataSource)
                .eq(ContrastNonHarmonicResult::getNum, num);
        if (ObjectUtil.isNotEmpty(waveNum)) {
            List<Integer> waveNumList = Stream.iterate(1, i -> i + 1).limit(waveNum).collect(Collectors.toList());
            wrapper1.in(ContrastNonHarmonicResult::getWaveNum, waveNumList);
        }

        List<ContrastNonHarmonicResult> nonHarmonicResultList = contrastNonHarmonicService.list(wrapper1);
        DynamicTableNameHandler.remove();

        DynamicTableNameHandler.setTableName("ad_harmonic_result_" + code);
        LambdaQueryWrapper<ContrastHarmonicResult> wrapper2 = new LambdaQueryWrapper<ContrastHarmonicResult>()
                .like(ContrastHarmonicResult::getDevMonitorId, monitorId)
                .in(CollUtil.isNotEmpty(adTypes), ContrastHarmonicResult::getAdType, adTypes)
                .eq(ContrastHarmonicResult::getDataType, dataSource)
                .eq(ContrastHarmonicResult::getNum, num)
                .eq(ObjectUtil.isNotEmpty(waveNum), ContrastHarmonicResult::getWaveNum, waveNum);

        List<ContrastHarmonicResult> harmonicResultList = contrastHarmonicService.list(wrapper2);
        DynamicTableNameHandler.remove();

        List<Integer> resultFlagList = nonHarmonicResultList.stream().map(ContrastNonHarmonicResult::getResultFlag).collect(Collectors.toList());
        resultFlagList.addAll(harmonicResultList.stream().map(ContrastHarmonicResult::getResultFlag).collect(Collectors.toList()));

        return isResultFlag(resultFlagList);
    }

    @Override
    public Map<Integer, Integer> getWaveNumResultMap(String monitorId, List<String> adTypes, Integer num, String code) {
        DynamicTableNameHandler.setTableName("ad_non_harmonic_result_" + code);
        LambdaQueryWrapper<ContrastNonHarmonicResult> wrapper1 = new LambdaQueryWrapper<ContrastNonHarmonicResult>()
                .like(ContrastNonHarmonicResult::getDevMonitorId, monitorId)
                .in(CollUtil.isNotEmpty(adTypes), ContrastNonHarmonicResult::getAdType, adTypes)
                .isNotNull(ContrastNonHarmonicResult::getWaveNum)
                .eq(ContrastNonHarmonicResult::getNum, num);

        List<ContrastNonHarmonicResult> nonHarmonicResultList = contrastNonHarmonicService.list(wrapper1);
        DynamicTableNameHandler.remove();

        DynamicTableNameHandler.setTableName("ad_harmonic_result_" + code);
        LambdaQueryWrapper<ContrastHarmonicResult> wrapper2 = new LambdaQueryWrapper<ContrastHarmonicResult>()
                .like(ContrastHarmonicResult::getDevMonitorId, monitorId)
                .in(CollUtil.isNotEmpty(adTypes), ContrastHarmonicResult::getAdType, adTypes)
                .isNotNull(ContrastHarmonicResult::getWaveNum)
                .eq(ContrastHarmonicResult::getNum, num);

        List<ContrastHarmonicResult> harmonicResultList = contrastHarmonicService.list(wrapper2);
        DynamicTableNameHandler.remove();

        TreeMap<Integer, List<ContrastNonHarmonicResult>> waveMap1 = nonHarmonicResultList.stream().collect(Collectors.groupingBy(ContrastNonHarmonicResult::getWaveNum, TreeMap::new, Collectors.toList()));
        TreeMap<Integer, List<ContrastHarmonicResult>> waveMap2 = harmonicResultList.stream().collect(Collectors.groupingBy(ContrastHarmonicResult::getWaveNum, TreeMap::new, Collectors.toList()));

        Map<Integer, List<Integer>> waveResultMap = new HashMap<>();
        waveMap1.forEach((waveNum, vList) -> {
            List<Integer> resultFlagList = waveResultMap.getOrDefault(waveNum, new ArrayList<>());
            resultFlagList.addAll(vList.stream().map(ContrastNonHarmonicResult::getResultFlag).collect(Collectors.toList()));
            waveResultMap.put(waveNum, resultFlagList);
        });
        waveMap2.forEach((waveNum, vList) -> {
            List<Integer> resultFlagList = waveResultMap.getOrDefault(waveNum, new ArrayList<>());
            resultFlagList.addAll(vList.stream().map(ContrastHarmonicResult::getResultFlag).collect(Collectors.toList()));
            waveResultMap.put(waveNum, resultFlagList);
        });

        Map<Integer, Integer> result = new TreeMap<>();
        waveResultMap.forEach((waveNum, resultFlagList) -> {
            Integer resultFlag = isResultFlag(resultFlagList);
            result.put(waveNum, resultFlag);
        });

        return result;
    }

    public static Integer isResultFlag(List<Integer> resultFlags) {
        // 检测结果（0:不符合 1:符合 2:/[未检测无结果])
        //脚本结果是 1.符合 2.不符合  4.未检测无结果 5.不参与误差比较
        resultFlags = resultFlags.stream().filter(x -> 4 != x && 5 != x).distinct().collect(Collectors.toList());
        if (CollUtil.isNotEmpty(resultFlags)) {
            if (resultFlags.contains(2)) {
                return 0;
            } else {
                switch (resultFlags.get(0)) {
                    case 1:
                        return 1;
                    case 2:
                        return 0;

                }
            }
        }
        return 1;
    }
}
