package com.huatek.busi.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.dubbo.config.annotation.Service;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Maps;
import com.huatek.busi.common.CurveType;
import com.huatek.busi.common.DictEnum;
import com.huatek.busi.common.FileTypeEnum;
import com.huatek.busi.common.SiteConstants;
import com.huatek.busi.dto.LabReportBasisDataDto;
import com.huatek.busi.dto.LabReportMarkDto;
import com.huatek.busi.dto.LabReportMarkStatisticDto;
import com.huatek.busi.dto.cable.BusiCableCirculationStatisticsDto;
import com.huatek.busi.entity.LabReportMarkStatistic;
import com.huatek.busi.mapper.LabReportMarkStatisticMapper;
import com.huatek.busi.service.ILabReportMarkStatisticService;
import com.huatek.busi.vo.LabReportMarkStatisticVo;
import com.huatek.busi.vo.LabReportMarkVo;
import com.huatek.busi.vo.cable.BusiCableCirculationIncreaseRateCacheVo;
import com.huatek.busi.vo.echarts.EchartLineDataVo;
import com.huatek.busi.vo.echarts.SeriesItemVo;
import com.huatek.busi.vo.labRulesVo;
import com.huatek.busi.vo.labValueVo;
import com.huatek.frame.base.util.BeanUtils;
import com.huatek.frame.base.util.Constants;
import com.huatek.torch.frame.tools.ConstantUtil;
import com.huatek.torch.frame.tools.ResultUtil;
import com.huatek.torch.sql.dao.impl.BaseDao;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Component
@Service(interfaceClass = ILabReportMarkStatisticService.class)
@Transactional(rollbackFor = Exception.class)
public class LabReportMarkStatisticServiceImpl extends BaseDao<LabReportMarkStatistic, String> implements ILabReportMarkStatisticService {

    private static final String UNDEFINED = "undefined";
    @Resource
    private LabReportMarkStatisticMapper labReportMarkStatisticMapper;

    @Override
    public Map<String, Object> queryList() {
        List<LabReportMarkStatisticDto> list = labReportMarkStatisticMapper.queryList();
        return ResultUtil.put(ConstantUtil.REQUEST_SUCCESS, "BUSINESS.QUERY.SUCCESS", list);
    }

    @Override
    public Map<String, Object> findList(LabReportMarkVo labReportMarkVo) {
        String resultId = this.findId(DictEnum.TEST_RESULT.getKey());
        String unitId = this.findId(DictEnum.IEC_O_UNIT.getKey());
        labReportMarkVo.setResultId(resultId);
        labReportMarkVo.setUnitId(unitId);
        PageHelper.startPage(labReportMarkVo.getPage(), labReportMarkVo.getLimit());
        if (StrUtil.isEmpty(labReportMarkVo.getDeleted())) {
            labReportMarkVo.setDeleted(Constants.DEFAULT_NO);
        }
        if (StrUtil.isEmpty(labReportMarkVo.getStatus())) {
            labReportMarkVo.setStatus(Constants.DEFAULT_YES);
        }
        List<LabReportMarkDto> labReportMarkData = null;
        if (Objects.equals(labReportMarkVo.getEqType(), SiteConstants.ExternalTypeEnum.GIS.getValue()) || Objects.equals(labReportMarkVo.getEqType(), SiteConstants.ExternalTypeEnum.BYQ.getValue())) {
            labReportMarkData = labReportMarkStatisticMapper.list(labReportMarkVo);
        } else if (Objects.equals(labReportMarkVo.getEqType(), SiteConstants.ExternalTypeEnum.BLQ.getValue())) {
            labReportMarkData = labReportMarkStatisticMapper.listBlq(labReportMarkVo);
        } else if (Objects.equals(labReportMarkVo.getEqType(), SiteConstants.ExternalTypeEnum.DL.getValue())) {
            labReportMarkData = labReportMarkStatisticMapper.listDl(labReportMarkVo);
        } else if (Objects.equals(labReportMarkVo.getEqType(), SiteConstants.ExternalTypeEnum.CW.getValue())) {
            labReportMarkData = labReportMarkStatisticMapper.listKgg(labReportMarkVo);
        } else if (Objects.equals(labReportMarkVo.getEqType(), SiteConstants.ExternalTypeEnum.GEN.getValue())) {
            labReportMarkData = labReportMarkStatisticMapper.listGen(labReportMarkVo);
        }
        PageInfo<LabReportMarkDto> page = new PageInfo<>(labReportMarkData);
        return ResultUtil.put(ConstantUtil.REQUEST_SUCCESS, page.getTotal(), "BUSINESS.QUERY.SUCCESS", page.getList());
    }

    private String findId(String key) {
        return labReportMarkStatisticMapper.findId(key);
    }

    @Override
    public Map<String, Object> delete(String ids) {
        if (StrUtil.isEmpty(ids)) {
            return ResultUtil.put(ConstantUtil.REQUEST_FAIL, "BUSINESS.ID.NOTNULL", "");
        }

        try {
            List<String> list = Arrays.asList(ids);
            for (String id : list) {
                this.del(id);
            }
        } catch (Exception e) {
            log.error("删除异常{}", e);
            return ResultUtil.put(ConstantUtil.REQUEST_FAIL, "BUSINESS.DELETE.FAIL", "");
        }
        return ResultUtil.put(ConstantUtil.REQUEST_SUCCESS, "BUSINESS.DELETE.SUCCESS", "");
    }

    @Override
    public int deleteByRIdAndTestDate(String eqType, String refId) {
        if (Objects.equals(eqType, SiteConstants.ExternalTypeEnum.GIS.getValue()) || Objects.equals(eqType, SiteConstants.ExternalTypeEnum.BYQ.getValue())) {
            return labReportMarkStatisticMapper.deleteByRIdAndTestDate(refId);
        } else if (Objects.equals(eqType, SiteConstants.ExternalTypeEnum.BLQ.getValue())) {
            return labReportMarkStatisticMapper.deleteBlqByRIdAndTestDate(refId);
        } else if (Objects.equals(eqType, SiteConstants.ExternalTypeEnum.DL.getValue())) {
            return labReportMarkStatisticMapper.deleteDlByRIdAndTestDate(refId);
        } else if (Objects.equals(eqType, SiteConstants.ExternalTypeEnum.CW.getValue())) {
            return labReportMarkStatisticMapper.deleteKggByRIdAndTestDate(refId);
        } else if (Objects.equals(eqType, SiteConstants.ExternalTypeEnum.GEN.getValue())) {
            return labReportMarkStatisticMapper.deleteGenByRIdAndTestDate(refId);
        }
        return 0;
    }

    @Override
    public int insert(LabReportMarkStatisticVo labReportMarkStatisticVo) {
        LabReportMarkStatistic labReportMarkStatistic = new LabReportMarkStatistic();
        BeanUtils.copyProperties(labReportMarkStatisticVo, labReportMarkStatistic);
        return this.add(labReportMarkStatistic);
    }

    @Override
    public int updateByRefIds(List<String> refIds, String equType) {
        if (Objects.equals(equType, SiteConstants.ExternalTypeEnum.GIS.getValue()) || Objects.equals(equType, SiteConstants.ExternalTypeEnum.BYQ.getValue())) {
            return labReportMarkStatisticMapper.updateByRefIds(refIds);
        } else if (Objects.equals(equType, SiteConstants.ExternalTypeEnum.BLQ.getValue())) {
            return labReportMarkStatisticMapper.updateBlqByRefIds(refIds);
        } else if (Objects.equals(equType, SiteConstants.ExternalTypeEnum.DL.getValue())) {
            return labReportMarkStatisticMapper.updateDlByRefIds(refIds);
        } else if (Objects.equals(equType, SiteConstants.ExternalTypeEnum.CW.getValue())) {
            return labReportMarkStatisticMapper.updateKggByRefIds(refIds);
        } else if (Objects.equals(equType, SiteConstants.ExternalTypeEnum.GEN.getValue())) {
            return labReportMarkStatisticMapper.updateGenByRefIds(refIds);
        }
        return 0;
    }

    @Override
    public Double findMaxValue(String mainTreeId, String key) {
        return labReportMarkStatisticMapper.findMaxValue(mainTreeId, key);
    }

    @Override
    public Double findMinValue(String mainTreeId, String key) {
        return labReportMarkStatisticMapper.findMinValue(mainTreeId, key);
    }

    @Override
    public Double findMaxValueByLTime(String mainTreeId, String key) {
        return labReportMarkStatisticMapper.findMaxValueByLTime(mainTreeId, key);
    }

    @Override
    public Double findMinValueByLTime(String mainTreeId, String key) {
        return labReportMarkStatisticMapper.findMinValueByLTime(mainTreeId, key);
    }

    @Override
    public Double findAverageValue(String mainTreeId, String key) {
        List<labValueVo> list = labReportMarkStatisticMapper.findValue(mainTreeId, key);
        Double times = Double.valueOf(list.size());
        Double sum = list.stream().map(e -> Double.valueOf(e.getCurrentValue())).reduce(Double::sum).get();
        Double result = sum / times;
        return result;
    }

    @Override
    public Double findAverageValueByLTime(String mainTreeId, String key) {
        List<labValueVo> list = labReportMarkStatisticMapper.findValueByLTime(mainTreeId, key);
        Double times = Double.valueOf(list.size());
        Double sum = list.stream().map(e -> Double.valueOf(e.getCurrentValue())).reduce(Double::sum).get();
        Double result = sum / times;
        return result;
    }

    @Override
    public List<LabReportMarkStatistic> findMainTreeId(String mainTreeId) {
        return labReportMarkStatisticMapper.findMainTreeId(mainTreeId);
    }

    @Override
    public labRulesVo findRules(String mainTreeId, String key) {
        return labReportMarkStatisticMapper.findRules(mainTreeId, key);
    }

    @Override
    public List<LabReportMarkStatistic> findAllManualAssessmentData(String mainTreeId) {
        List<LabReportMarkStatistic> result = new ArrayList<>();
        List<LabReportMarkStatistic> list = labReportMarkStatisticMapper.findAllManualAssessmentData(mainTreeId);
        Map<String, List<LabReportMarkStatistic>> collect = list.stream().collect(Collectors.groupingBy(this::key));
        collect.forEach((String key, List<LabReportMarkStatistic> value) ->{
            LocalDateTime localDateTime = value.stream().map(LabReportMarkStatistic::getCreateTime).max(LocalDateTime::compareTo).get();
            List<LabReportMarkStatistic> labReportMarkStatisticList= value.stream().filter(item -> item.getCreateTime().equals(localDateTime)).collect(Collectors.toList());
            result.addAll(labReportMarkStatisticList);
        });

        return result;
    }

    public String key(LabReportMarkStatistic labReportMarkStatistic) {
        return labReportMarkStatistic.getERule() + labReportMarkStatistic.getTestInterval() + labReportMarkStatistic.getTestDate();
    }


    @Override
    public Map<String, Object> getHistoryChart(LabReportMarkVo vo) {
        String unitId = this.findId(DictEnum.IEC_O_UNIT.getKey());
        vo.setFileType(FileTypeEnum.R_TEMPLATE.getKey());
        vo.setUnitId(unitId);
        if (StrUtil.isEmpty(vo.getDeleted())) {
            vo.setDeleted(Constants.DEFAULT_NO);
        }
        EchartLineDataVo echartLineDataVo = getTrendData(vo);
        return ResultUtil.put(ConstantUtil.REQUEST_SUCCESS, "查询成功", echartLineDataVo);
    }

    private EchartLineDataVo getTrendData(LabReportMarkVo vo) {
        CurveType curveType = CurveType.newInstance("打标数据", 1);
        String subTitle = "打标数据";

        EchartLineDataVo result = new EchartLineDataVo(subTitle + "趋势曲线");
        int availableCount = 0;
        // 设置X轴坐标值：升序且不重复；保存每条曲线每个X坐标对应的值在allPointMap里，X轴坐标值相同的点会覆盖
        Map<String, Map<String, Object>> allValPointMap = Maps.newLinkedHashMap();
        Map<String, Map<String, Object>> allAbsRatePointMap = Maps.newLinkedHashMap();
        Map<String, Map<String, Object>> allRelRatePointMap = Maps.newLinkedHashMap();
        Map<String, Map<String, Object>> allDevRatePointMap = Maps.newLinkedHashMap();
        List<LabReportMarkDto> historyDatas = null;
        if (Objects.equals(vo.getEqType(), SiteConstants.ExternalTypeEnum.GIS.getValue()) || Objects.equals(vo.getEqType(), SiteConstants.ExternalTypeEnum.BYQ.getValue())) {
            historyDatas = labReportMarkStatisticMapper.getHistoryData(vo);
        } else if (Objects.equals(vo.getEqType(), SiteConstants.ExternalTypeEnum.BLQ.getValue())) {
            historyDatas = labReportMarkStatisticMapper.getHistoryBlqData(vo);
        } else if (Objects.equals(vo.getEqType(), SiteConstants.ExternalTypeEnum.DL.getValue())) {
            historyDatas = labReportMarkStatisticMapper.getHistoryDlData(vo);
        } else if (Objects.equals(vo.getEqType(), SiteConstants.ExternalTypeEnum.CW.getValue())) {
            historyDatas = labReportMarkStatisticMapper.getHistoryKggData(vo);
        } else if (Objects.equals(vo.getEqType(), SiteConstants.ExternalTypeEnum.GEN.getValue())) {
            historyDatas = labReportMarkStatisticMapper.getHistoryGenData(vo);
        }
        availableCount += historyDatas.size();
        Map<String, Object> valMap = Maps.newHashMapWithExpectedSize(historyDatas.size());
        Map<String, Object> absRateMap = Maps.newHashMapWithExpectedSize(historyDatas.size());
        Map<String, Object> relRateMap = Maps.newHashMapWithExpectedSize(historyDatas.size());
        Map<String, Object> devRateMap = Maps.newHashMapWithExpectedSize(historyDatas.size());
        for (LabReportMarkDto historyData : historyDatas) {
            if (historyData.getCurrentValue() == null || historyData.getCurrentValue().isEmpty()) {
                historyData.setCurrentValue("0");
            }
            if (historyData.getAbsRate() == null || historyData.getAbsRate().isEmpty()) {
                historyData.setAbsRate("0");
            }
            if (historyData.getRelRate() == null || historyData.getRelRate().isEmpty()) {
                historyData.setRelRate("0");
            }
            if (historyData.getDevRate() == null || historyData.getDevRate().isEmpty()) {
                historyData.setDevRate("0");
            }
            // 当前值
            valMap.put(historyData.getFileName(), historyData.getCurrentValue());
            // 绝对增长率
            absRateMap.put(historyData.getFileName(), historyData.getAbsRate());
            // 相对增长率
            relRateMap.put(historyData.getFileName(), historyData.getRelRate());
            // 偏差率
            devRateMap.put(historyData.getFileName(), historyData.getDevRate());
        }
        allValPointMap.put("打标数据", valMap);
        allAbsRatePointMap.put("绝对增长率", absRateMap);
        allRelRatePointMap.put("相对增长率", relRateMap);
        allDevRatePointMap.put("偏差率", devRateMap);
        for (int i = 0; i < historyDatas.size(); i++) {
            String xData = historyDatas.get(i).getFileName();
            result.getXAxisData().add(xData);
        }
        //设置开始日期和结束日期之间的X轴值
//        long days = ChronoUnit.DAYS.between(vo.getStartTime(), vo.getEndTime());
//        if (days >= 0) {
//            Stream.iterate(vo.getStartTime(), d -> d.plusDays(1)).limit(days + 1)
//                    .forEach(day -> result.getXAxisData().add(day.toString()));
//        }
        // 根据X轴进行构造曲线
        setYAxisData(result, curveType, allValPointMap, "打标数据");
        setYAxisData(result, curveType, allAbsRatePointMap, "绝对增长率");
        setYAxisData(result, curveType, allRelRatePointMap, "相对增长率");
        setYAxisData(result, curveType, allDevRatePointMap, "偏差率");
        result.setAvailableCount(availableCount);
        return result;
    }

    static void setYAxisData(EchartLineDataVo result, CurveType curveType, Map<String, Map<String, Object>> allPointMap, String subTitle) {
        String line = subTitle;
        Map<String, Object> linePointMap = allPointMap.get(line);
        List<Object> dataList = result.getXAxisData().stream().map(xAxis -> getVal(linePointMap, xAxis)).collect(Collectors.toList());
        result.getSeries().add(new SeriesItemVo(line, dataList));
    }

    static Object getVal(Map<String, Object> map, String key) {
        if (map == null || map.isEmpty()) {
            return UNDEFINED;
        }
        Object val = map.get(key);
        return val == null ? UNDEFINED : val;
    }

    @Override
    public List<LabReportMarkStatisticDto> getLastImportInfo(String equipmentId,String type) {
        return labReportMarkStatisticMapper.getLastImportInfo(equipmentId,type);
    }
}
