package cn.cecep.talroad.data.analyse.task.missing.impl;

import cn.cecep.talroad.data.anomaly.task.entity.ProblemRatioDTO;
import cn.cecep.talroad.domain.AmProblemFi;
import cn.cecep.talroad.domain.MAmProblemFiRatio;
import cn.cecep.talroad.enums.ProblemTypeEnum;
import cn.cecep.talroad.mapper.AmProblemFiMapper;
import cn.cecep.talroad.mapper.MAmProblemFiRatioMapper;
import cn.cecep.talroad.util.DateUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class MAmProblemFiRatioService {

  @Autowired private MAmProblemFiRatioMapper mAmProblemFiRatioMapper;

  @Autowired private AmProblemFiMapper amProblemFiMapper;

  public boolean mainProcess() {
    List<String> problemType = Lists.newArrayList();
    String startTime = DateUtil.getTime(DateUtil.getLastMont());
    String endTime = DateUtil.getTime(DateUtil.now());
    problemType.add(ProblemTypeEnum.OVER_STAND.getCode());
    problemType.add(ProblemTypeEnum.WARN.getCode());
    // 企业id
    List<String> factoriesIds =
        amProblemFiMapper.selectAmProblemFiFactoriesIdsByDate(
            Timestamp.valueOf(startTime), Timestamp.valueOf(endTime), problemType);
    // 根据企业id修改比例
    toModifyRatio(startTime, endTime, factoriesIds, problemType);
    return true;
  }

  private void toModifyRatio(
      String startTime, String endTime, List<String> factoriesIds, List<String> problemType) {
    List<List<String>> idsPage = Lists.partition(factoriesIds, 10);
    // 根据分页后的企业修改对应污染物预警比例
    idsPage.stream()
        .parallel()
        .forEach(
            id -> {
              List<ProblemRatioDTO> problemRatioDTOList = Lists.newArrayList();
              // todo根据企业id
              // 查询所有的设备报警信息
              List<AmProblemFi> amProblemFis =
                  amProblemFiMapper.selectAmProblemFiByFactoriesIds(
                      factoriesIds,
                      Timestamp.valueOf(startTime),
                      Timestamp.valueOf(endTime),
                      problemType);

              if (!CollUtil.isEmpty(amProblemFis)) {
                this.problemRatioDTOListByAmProblemFis(amProblemFis, problemRatioDTOList);
                // 对比queryMamProblemFiRatioListByFactoriesIds和problemRatioDTOList
                this.modifyProblemFiRatio(problemRatioDTOList);
              }
            });
  }

  private void problemRatioDTOListByAmProblemFis(
      List<AmProblemFi> amProblemFis, List<ProblemRatioDTO> problemRatioDTOList) {
    Map<String, List<AmProblemFi>> factoriesMap = groupByFactoryId(amProblemFis);
    factoriesMap.forEach(
        (factoriesId, amProblemFiList) -> {
          Map<String, List<AmProblemFi>> stationMap = groupByStationId(amProblemFiList);
          stationMap.forEach(
              (stationId, amProblemFiList1) -> {
                Map<String, List<AmProblemFi>> extraMap = groupByExtra(amProblemFiList1);
                extraMap.forEach(
                    (ex, amProblems) -> {
                      Map<String, List<AmProblemFi>> collect = groupByProblemType(amProblems);
                      ProblemRatioDTO problemRatioDTO = new ProblemRatioDTO();
                      problemRatioDTO.setFactoryId(factoriesId);
                      problemRatioDTO.setStationId(stationId);
                      problemRatioDTO.setPollId(this.getPollId(ex));
                      collect.forEach(
                          (type, p) -> {
                            if (Objects.equals(type, ProblemTypeEnum.OVER_STAND.getCode())) {
                              problemRatioDTO.setAlarmNumber(p.size());
                            }
                            if (Objects.equals(type, ProblemTypeEnum.WARN.getCode())) {
                              problemRatioDTO.setWarnNumber(p.size());
                            }
                          });
                      problemRatioDTOList.add(problemRatioDTO);
                    });
              });
        });
  }

  private Map<String, List<AmProblemFi>> groupByFactoryId(List<AmProblemFi> amProblemFis) {
    return amProblemFis.stream().collect(Collectors.groupingBy(AmProblemFi::getFactoryId));
  }

  private Map<String, List<AmProblemFi>> groupByStationId(List<AmProblemFi> amProblemFiList) {
    return amProblemFiList.stream()
        .collect(Collectors.groupingBy(a -> Optional.ofNullable(a.getStationId()).orElse("0")));
  }

  private Map<String, List<AmProblemFi>> groupByExtra(List<AmProblemFi> amProblemFiList1) {
    return amProblemFiList1.stream()
        .collect(Collectors.groupingBy(a -> Optional.ofNullable(a.getExtra()).orElse("0")));
  }

  private Map<String, List<AmProblemFi>> groupByProblemType(List<AmProblemFi> amProblems) {
    return amProblems.stream()
        .collect(Collectors.groupingBy(a -> Optional.ofNullable(a.getProblemType()).orElse("0")));
  }

  private void modifyProblemFiRatio(List<ProblemRatioDTO> problemRatioDTOList) {
    if (CollUtil.isEmpty(problemRatioDTOList)) {
      return;
    }
    List<MAmProblemFiRatio> updateList = new ArrayList<>();
    List<MAmProblemFiRatio> newList = new ArrayList<>();
    List<MAmProblemFiRatio> mAmProblemFiRatioList =
        mAmProblemFiRatioMapper.queryMamProblemFiRatioListByProblemRatioDTOList(
            problemRatioDTOList);
    for (ProblemRatioDTO problemRatioDTO : problemRatioDTOList) {
      boolean isNew = true;
      for (MAmProblemFiRatio mAmProblemFiRatio : mAmProblemFiRatioList) {
        if (Objects.equals(problemRatioDTO.getFactoryId(), mAmProblemFiRatio.getFactoryId())
            && Objects.equals(problemRatioDTO.getStationId(), mAmProblemFiRatio.getStationId())
            && Objects.equals(problemRatioDTO.getPollId(), mAmProblemFiRatio.getPollId())) {
          isNew = false;
          String problemRatio = mAmProblemFiRatio.getProblemRatio();
          this.countRatio(problemRatioDTO, problemRatio);
          mAmProblemFiRatio.setUpdateTime(new Date());
          updateList.add(mAmProblemFiRatio);
        }
      }
      if (isNew) {
        MAmProblemFiRatio mAmProblemFiRatio = new MAmProblemFiRatio();
        mAmProblemFiRatio.setFactoryId(problemRatioDTO.getFactoryId());
        mAmProblemFiRatio.setStationId(problemRatioDTO.getStationId());
        mAmProblemFiRatio.setPollId(problemRatioDTO.getPollId());
        mAmProblemFiRatio.setProblemRatio("80");
        mAmProblemFiRatio.setCreateTime(new Date());
        mAmProblemFiRatio.setUpdateTime(new Date());
        newList.add(mAmProblemFiRatio);
      }
    }
    if (!CollUtil.isEmpty(newList)) {
      List<MAmProblemFiRatio> mAmProblemFiRatios =
          BeanUtil.copyToList(newList, MAmProblemFiRatio.class);
      mAmProblemFiRatioMapper.batchInsert(mAmProblemFiRatios);
    }
    if (!CollUtil.isEmpty(updateList)) {
      mAmProblemFiRatioMapper.batchUpdate(updateList);
    }
  }

  private String countRatio(ProblemRatioDTO problemRatioDTO, String problemRatio) {
    int ratio = Integer.parseInt(problemRatio);
    if (ratio < 95 && ratio != 95) {
      Integer warnNumber = problemRatioDTO.getWarnNumber();
      Integer alarmNumber = problemRatioDTO.getAlarmNumber();
      if (warnNumber > 300 && alarmNumber < (warnNumber * 0.1)) {
        ratio += 5;
      }
    }
    return ratio + "";
  }

  private String getPollId(String ex) {
    Map<String, Object> extra = null;
    try {
      extra = JSON.parseObject(ex, new TypeReference<Map<String, Object>>() {});
    } catch (Exception e) {
      log.info("解析extra异常", e);
    }
    String pollutantCode = extra != null ? (String) extra.get("pollutantCode") : null;
    return pollutantCode;
  }

  public boolean mainProcessByTest() {
    ArrayList<String> strings = new ArrayList<>();
    strings.add("14");
    strings.add("16");
    List<String> problemType = Lists.newArrayList();
    problemType.add(ProblemTypeEnum.OVER_STAND.getCode());
    problemType.add(ProblemTypeEnum.WARN.getCode());
    toModifyRatio("2023-06-21 00:00:00", "2023-06-21 23:00:00", strings, problemType);
    return true;
  }
}
