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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.njcn.db.mybatisplus.handler.DynamicTableNameHandler;
import com.njcn.gather.storage.mapper.SimAndDigNonHarmonicMapper;
import com.njcn.gather.storage.pojo.param.SingleNonHarmParam;
import com.njcn.gather.storage.pojo.param.StorageParam;
import com.njcn.gather.storage.pojo.po.SimAndDigBaseResult;
import com.njcn.gather.storage.pojo.po.SimAndDigNonHarmonicResult;
import com.njcn.gather.storage.pojo.vo.RawDataVO;
import com.njcn.gather.storage.pojo.vo.RawResultDataVO;
import com.njcn.gather.storage.service.SimAndDigNonHarmonicService;
import com.njcn.gather.system.dictionary.pojo.po.DictTree;
import com.njcn.gather.system.dictionary.service.IDictTreeService;
import com.njcn.gather.util.StorageUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 *
 */
@Service
@RequiredArgsConstructor
public class SimAndDigNonHarmonicServiceImpl extends ServiceImpl<SimAndDigNonHarmonicMapper, SimAndDigNonHarmonicResult> implements SimAndDigNonHarmonicService {

    private final IDictTreeService dictTreeService;

    @Override
    public List<SimAndDigBaseResult> listSimAndDigBaseResult(String scriptId, List<Integer> sort, String deviceId, String chnNum, String code) {
        String prefix = "ad_non_harmonic_result_";
        DynamicTableNameHandler.setTableName(prefix + code);

        MPJLambdaWrapper<SimAndDigNonHarmonicResult> wrapper = new MPJLambdaWrapper<>();
        String monitorId = deviceId + "_" + chnNum;
        if ("-1".equals(chnNum)) {
            monitorId = deviceId;
        }
        wrapper.like(SimAndDigNonHarmonicResult::getDevMonitorId, monitorId)
                .eq(ObjectUtil.isNotNull(scriptId), SimAndDigNonHarmonicResult::getScriptId, scriptId)
                .in(CollUtil.isNotEmpty(sort), SimAndDigNonHarmonicResult::getSort, sort);
        List<SimAndDigNonHarmonicResult> list = this.getBaseMapper().selectJoinList(SimAndDigNonHarmonicResult.class, wrapper);
        DynamicTableNameHandler.remove();
        return BeanUtil.copyToList(list, SimAndDigBaseResult.class);
    }

    @Override
    public Map<String, List<RawDataVO>> listNonHarmData(StorageParam param) {
        String prefix = "ad_non_harmonic_";
        DynamicTableNameHandler.setTableName(prefix + param.getCode());
        MPJLambdaWrapper<SimAndDigNonHarmonicResult> wrapper = new MPJLambdaWrapper<>();
        wrapper.like(SimAndDigNonHarmonicResult::getDevMonitorId, param.getDevId() + "_" + param.getDevNum())
                .eq(ObjectUtil.isNotNull(param.getScriptId()), SimAndDigNonHarmonicResult::getScriptId, param.getScriptId())
                .in(ObjectUtil.isNotEmpty(param.getIndex()), SimAndDigNonHarmonicResult::getSort, param.getIndex());
        List<SimAndDigNonHarmonicResult> SimAndDigHarmonicResults = this.getBaseMapper().selectJoinList(SimAndDigNonHarmonicResult.class, wrapper);
        Map<String, List<RawDataVO>> info = new LinkedHashMap<>(2);
        Map<String, List<SimAndDigNonHarmonicResult>> adTypeMap = SimAndDigHarmonicResults.stream().collect(Collectors.groupingBy(SimAndDigNonHarmonicResult::getAdType));
        List<DictTree> dictTreeById = dictTreeService.getDictTreeById(new ArrayList<>(adTypeMap.keySet()));
        Map<String, DictTree> dictTreeByName = dictTreeById.stream().collect(Collectors.toMap(DictTree::getId, Function.identity()));
        adTypeMap.forEach((key, value) -> {
            if (dictTreeByName.containsKey(key)) {
                DictTree dictTree = dictTreeByName.get(key);
                List<RawDataVO> rawDataVOS = new ArrayList<>();
                for (SimAndDigNonHarmonicResult result : value) {
                    RawDataVO dataVO = new RawDataVO();
                    dataVO.setUnit(dictTree.getCode().equals("MAG")?"%": StorageUtil.unit(dictTree.getCode()));
                    dataVO.setTime(result.getTimeId().format(DateTimeFormatter.ofPattern(DatePattern.ISO8601_PATTERN)));
                    dataVO.setDataA(StrUtil.isNotBlank(result.getAValue()) ? new BigDecimal(result.getAValue()).toPlainString() : null);
                    dataVO.setDataB(StrUtil.isNotBlank(result.getBValue()) ? new BigDecimal(result.getBValue()).toPlainString() : null);
                    dataVO.setDataC(StrUtil.isNotBlank(result.getCValue()) ? new BigDecimal(result.getCValue()).toPlainString() : null);
                    dataVO.setDataT(StrUtil.isNotBlank(result.getTValue()) ? new BigDecimal(result.getTValue()).toPlainString() : null);
                    rawDataVOS.add(dataVO);
                }
                info.put(dictTree.getName(), rawDataVOS);
            }
        });
        DynamicTableNameHandler.remove();
        return info;
    }

    @Override
    public Map<String, List<RawResultDataVO>> listNonHarmResultData(StorageParam param) {
        String prefix = "ad_non_harmonic_result_";
        DynamicTableNameHandler.setTableName(prefix + param.getCode());
        MPJLambdaWrapper<SimAndDigNonHarmonicResult> wrapper = new MPJLambdaWrapper<>();
        wrapper.like(SimAndDigNonHarmonicResult::getDevMonitorId, param.getDevId() + "_" + param.getDevNum())
                .eq(ObjectUtil.isNotNull(param.getScriptId()), SimAndDigNonHarmonicResult::getScriptId, param.getScriptId())
                .in(ObjectUtil.isNotEmpty(param.getIndex()), SimAndDigNonHarmonicResult::getSort, param.getIndex());

        List<SimAndDigNonHarmonicResult> SimAndDigHarmonicResults = this.getBaseMapper().selectJoinList(SimAndDigNonHarmonicResult.class, wrapper);

        Map<String, List<RawResultDataVO>> info = new LinkedHashMap<>(2);
        Map<String, SimAndDigNonHarmonicResult> adTypeMap = SimAndDigHarmonicResults.stream()
                                                    .collect(Collectors.toMap(SimAndDigNonHarmonicResult::getAdType, Function.identity(), (a, b) -> a, LinkedHashMap::new));
        List<DictTree> dictTreeById = dictTreeService.getDictTreeById(new ArrayList<>(adTypeMap.keySet()));
        Map<String, DictTree> dictTreeByName = dictTreeById.stream().collect(Collectors.toMap(DictTree::getId, Function.identity()));
        adTypeMap.forEach((key, result) -> {
            if (dictTreeByName.containsKey(key)) {
                DictTree treeName = dictTreeByName.get(key);
                RawResultDataVO dataVO = new RawResultDataVO();
                dataVO.setIsData(result.getResultFlag());
                dataVO.setUnit(StorageUtil.unit(treeName.getCode()));
                RawResultDataVO.DetectionData a = JSON.parseObject(result.getAValue(), RawResultDataVO.DetectionData.class);
                RawResultDataVO.DetectionData b = JSON.parseObject(result.getBValue(), RawResultDataVO.DetectionData.class);
                RawResultDataVO.DetectionData c = JSON.parseObject(result.getCValue(), RawResultDataVO.DetectionData.class);
                RawResultDataVO.DetectionData t = JSON.parseObject(result.getTValue(), RawResultDataVO.DetectionData.class);
                dataVO.setDataA(a);
                dataVO.setDataB(b);
                dataVO.setDataC(c);
                dataVO.setDataT(t);
                if (ObjectUtil.isNotNull(t)) {
                    dataVO.setRadius(t.getRadius());
                } else {
                    if (ObjectUtil.isNotNull(b)) {
                        dataVO.setRadius(b.getRadius());
                    }
                }
                info.put(treeName.getName(), Arrays.asList(dataVO));
            }
        });
        DynamicTableNameHandler.remove();
        return info;
    }

    @Override
    public SimAndDigNonHarmonicResult getSingleSimAndDigBaseResult(SingleNonHarmParam singleNonHarmParam) {
        if (ObjectUtil.isNotNull(singleNonHarmParam)) {
            String prefix = "ad_non_harmonic_result_";
            DynamicTableNameHandler.setTableName(prefix + singleNonHarmParam.getPlanCode());
            MPJLambdaWrapper<SimAndDigNonHarmonicResult> wrapper = new MPJLambdaWrapper<>();
            wrapper.like(SimAndDigNonHarmonicResult::getDevMonitorId, singleNonHarmParam.getDevId() + "_" + singleNonHarmParam.getChannelNo())
                    .eq(SimAndDigNonHarmonicResult::getSort, singleNonHarmParam.getSort())
                    .eq(SimAndDigNonHarmonicResult::getAdType, singleNonHarmParam.getAdType());
            List<SimAndDigNonHarmonicResult> SimAndDigHarmonicResults = this.getBaseMapper().selectJoinList(SimAndDigNonHarmonicResult.class, wrapper);
            if (CollectionUtil.isNotEmpty(SimAndDigHarmonicResults)) {
                return SimAndDigHarmonicResults.get(0);
            }
        }
        return null;
    }

    @Override
    public List<SimAndDigNonHarmonicResult> listSimAndDigBaseResult(String scriptId, String code, String devId) {
        String prefix = "ad_non_harmonic_result_" + code;
        DynamicTableNameHandler.setTableName(prefix);
        MPJLambdaWrapper<SimAndDigNonHarmonicResult> wrapper = new MPJLambdaWrapper<>();
        wrapper.selectAll(SimAndDigNonHarmonicResult.class)
                .selectAs(DictTree::getCode, SimAndDigNonHarmonicResult::getAdType)
                .leftJoin(DictTree.class, DictTree::getId, SimAndDigNonHarmonicResult::getAdType)
                .eq(SimAndDigNonHarmonicResult::getScriptId, scriptId)
                .likeRight(SimAndDigNonHarmonicResult::getDevMonitorId, devId);
        List<SimAndDigNonHarmonicResult> results = this.getBaseMapper().selectJoinList(SimAndDigNonHarmonicResult.class, wrapper);
        DynamicTableNameHandler.remove();
        return results;
    }

    @Override
    public List<SimAndDigNonHarmonicResult> queryByCondition(SingleNonHarmParam param) {
        String prefix = "ad_non_harmonic_result_";
        DynamicTableNameHandler.setTableName(prefix + param.getPlanCode());
        MPJLambdaWrapper<SimAndDigNonHarmonicResult> wrapper = new MPJLambdaWrapper<>();
        wrapper.like(SimAndDigNonHarmonicResult::getDevMonitorId, param.getDevId() + "_" + param.getChannelNo())
                .in(SimAndDigNonHarmonicResult::getSort, param.getSortList())
                .in(SimAndDigNonHarmonicResult::getAdType, param.getValueTypeList());
        List<SimAndDigNonHarmonicResult> adNonHarmonicResults = this.getBaseMapper().selectJoinList(SimAndDigNonHarmonicResult.class, wrapper);
        DynamicTableNameHandler.remove();
        return adNonHarmonicResults;
    }

    @Override
    public List<SimAndDigNonHarmonicResult> queryBySortListWithAdTypeCode(SingleNonHarmParam param) {
        String prefix = "ad_non_harmonic_result_";
        DynamicTableNameHandler.setTableName(prefix + param.getPlanCode());
        MPJLambdaWrapper<SimAndDigNonHarmonicResult> wrapper = new MPJLambdaWrapper<>();
        wrapper.selectAll(SimAndDigNonHarmonicResult.class)
                .selectAs(DictTree::getCode, SimAndDigNonHarmonicResult::getAdType)
                .leftJoin(DictTree.class, DictTree::getId, SimAndDigNonHarmonicResult::getAdType)
                .like(SimAndDigNonHarmonicResult::getDevMonitorId, param.getDevId() + "_" + param.getChannelNo())
                .in(SimAndDigNonHarmonicResult::getSort, param.getSortList());
        List<SimAndDigNonHarmonicResult> adNonHarmonicResults = this.getBaseMapper().selectJoinList(SimAndDigNonHarmonicResult.class, wrapper);
        DynamicTableNameHandler.remove();
        return adNonHarmonicResults;
    }


    @Override
    public List<SimAndDigNonHarmonicResult> listAllSimAndDigRawData(String scriptId, String code, String devId) {
        String prefix = "ad_non_harmonic_" + code;
        DynamicTableNameHandler.setTableName(prefix);
        MPJLambdaWrapper<SimAndDigNonHarmonicResult> wrapper = new MPJLambdaWrapper<>();
        wrapper.selectAll(SimAndDigNonHarmonicResult.class)
                .selectAs(DictTree::getCode, SimAndDigNonHarmonicResult::getAdType)
                .leftJoin(DictTree.class, DictTree::getId, SimAndDigNonHarmonicResult::getAdType)
                .eq(SimAndDigNonHarmonicResult::getScriptId, scriptId)
                .likeRight(SimAndDigNonHarmonicResult::getDevMonitorId, devId);
        List<SimAndDigNonHarmonicResult> results = this.getBaseMapper().selectJoinList(SimAndDigNonHarmonicResult.class, wrapper);
        DynamicTableNameHandler.remove();
        return results;
    }

    @Override
    public Map<String, Integer> maxSortByDevIds(String code, String scriptId, List<String> devIds) {
        Map<String, Integer> result = new HashMap<>();
        if (CollUtil.isEmpty(devIds)) {
            return result;
        }
        DynamicTableNameHandler.setTableName("ad_non_harmonic_result_" + code);
        try {
            LambdaQueryWrapper<SimAndDigNonHarmonicResult> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(SimAndDigNonHarmonicResult::getDevMonitorId, SimAndDigNonHarmonicResult::getSort)
                    .eq(SimAndDigNonHarmonicResult::getScriptId, scriptId)
                    .and(w -> {
                        for (String devId : devIds) {
                            w.or().likeRight(SimAndDigNonHarmonicResult::getDevMonitorId, devId + "_");
                        }
                    });
            this.list(wrapper).forEach(row -> {
                String devId = row.getDevMonitorId().split("_")[0];
                result.merge(devId, row.getSort(), Math::max);
            });
            return result;
        } finally {
            DynamicTableNameHandler.remove();
        }
    }

    @Override
    public List<SimAndDigNonHarmonicResult> listByDevIdsAndSorts(String code, String scriptId, List<String> devIds, List<Integer> sorts) {
        if (CollUtil.isEmpty(devIds) || CollUtil.isEmpty(sorts)) {
            return Collections.emptyList();
        }
        DynamicTableNameHandler.setTableName("ad_non_harmonic_result_" + code);
        try {
            LambdaQueryWrapper<SimAndDigNonHarmonicResult> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SimAndDigNonHarmonicResult::getScriptId, scriptId)
                    .in(SimAndDigNonHarmonicResult::getSort, sorts)
                    .and(w -> {
                        for (String devId : devIds) {
                            w.or().likeRight(SimAndDigNonHarmonicResult::getDevMonitorId, devId + "_");
                        }
                    });
            return this.list(wrapper);
        } finally {
            DynamicTableNameHandler.remove();
        }
    }

    @Override
    public Map<String, List<Integer>> resultFlagsByDevIdsAndSorts(String code, String scriptId, List<String> devIds, List<Integer> sorts) {
        Map<String, List<Integer>> result = new HashMap<>();
        if (CollUtil.isEmpty(devIds) || StrUtil.isBlank(code)) {
            return result;
        }
        if (sorts != null && CollUtil.isEmpty(sorts)) {
            return result;
        }
        DynamicTableNameHandler.setTableName("ad_non_harmonic_result_" + code);
        try {
            LambdaQueryWrapper<SimAndDigNonHarmonicResult> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(SimAndDigNonHarmonicResult::getDevMonitorId,
                            SimAndDigNonHarmonicResult::getResultFlag)
                    .eq(StrUtil.isNotBlank(scriptId), SimAndDigNonHarmonicResult::getScriptId, scriptId)
                    .in(CollUtil.isNotEmpty(sorts), SimAndDigNonHarmonicResult::getSort, sorts)
                    .and(w -> {
                        for (String devId : devIds) {
                            w.or().likeRight(SimAndDigNonHarmonicResult::getDevMonitorId, devId + "_");
                        }
                    });
            this.list(wrapper).forEach(row -> {
                String devId = resolveDevId(row.getDevMonitorId(), devIds);
                if (StrUtil.isNotBlank(devId) && row.getResultFlag() != null) {
                    result.computeIfAbsent(devId, key -> new ArrayList<>()).add(row.getResultFlag());
                }
            });
            return result;
        } finally {
            DynamicTableNameHandler.remove();
        }
    }

    private String resolveDevId(String devMonitorId, List<String> devIds) {
        if (StrUtil.isBlank(devMonitorId)) {
            return null;
        }
        for (String devId : devIds) {
            if (StrUtil.isNotBlank(devId) && devMonitorId.startsWith(devId + "_")) {
                return devId;
            }
        }
        return null;
    }

}
