package com.qmth.sop.business.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.sop.business.bean.dto.TBSopPlanDateLogDto;
import com.qmth.sop.business.entity.TBSopInfo;
import com.qmth.sop.business.entity.TBSopPlanDateLog;
import com.qmth.sop.business.mapper.SopScheduleMapper;
import com.qmth.sop.business.service.SopScheduleService;
import com.qmth.sop.business.service.TBSopPlanDateLogService;
import com.qmth.sop.common.contant.SystemConstant;
import com.qmth.sop.common.enums.FlowStatusEnum;
import com.qmth.sop.common.enums.SopAnalyseGroupEnum;
import com.qmth.sop.common.util.DateDisposeUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class SopScheduleServiceImpl extends ServiceImpl<SopScheduleMapper, TBSopInfo> implements SopScheduleService {

    @Resource
    TBSopPlanDateLogService tbSopPlanDateLogService;

    /**
     * * ①准备：扫描前的准备阶段；
     * * ②扫描：扫描仪配置产出物提交，到扫描收尾产出物提交；
     * * ③评卷：阅卷参数提交、评卷收尾；
     * * ④收尾：项目总结提交前；
     * * ⑤已完结：SOP完结。
     */
    @Override
    public Map<String, Map<String, Object>> progress(Long serviceId, SopAnalyseGroupEnum group) {
        List<Map<String, Object>> list = this.baseMapper.progress(serviceId);
        Map<String, Map<String, Object>> result = new HashMap<>();
        if (group.equals(SopAnalyseGroupEnum.POPULATION)) {
            result.put("POPULATION", processData(list, group));
        } else if (group.equals(SopAnalyseGroupEnum.REGION)) {
            list.stream().filter(map -> map.get("region_name") != null).collect(Collectors.groupingBy(map -> map.get("region_name"))).forEach((k, v) -> result.put(k.toString(), processData(v, group)));
        } else if (group.equals(SopAnalyseGroupEnum.SUPPLIER)) {
            list.stream().filter(map -> map.get("name") != null).collect(Collectors.groupingBy(map -> map.get("name"))).forEach((k, v) -> result.put(k.toString(), processData(v, group)));
        }
        return result;
    }

    private Map<String, Object> processData(List<Map<String, Object>> list, SopAnalyseGroupEnum group) {
        Map<String, Object> map = new HashMap<>();
        if (group.equals(SopAnalyseGroupEnum.REGION)) {
            map.put("region_id", list.get(0).get("region_id"));
        } else if (group.equals(SopAnalyseGroupEnum.SUPPLIER)) {
            map.put("supplier_id", list.get(0).get("supplier_id"));
        }
        map.put("prepare", list.stream().filter(map1 -> map1.get("setup") == null || (Integer.parseInt(map1.get("setup").toString()) > 0 && Integer.parseInt(map1.get("setup").toString()) < 5)).count());
        map.put("scan", list.stream().filter(map1 -> map1.get("setup") != null && "5,6,7".indexOf(map1.get("setup").toString()) > 0).count());
        map.put("evaluation", list.stream().filter(map1 -> map1.get("setup") != null && "8,9".indexOf(map1.get("setup").toString()) > 0).count());
        map.put("summary", list.stream().filter(map1 -> map1.get("setup") != null && (Integer.parseInt(map1.get("setup").toString()) == 11 || Integer.parseInt(map1.get("setup").toString()) == 10)).count());
        map.put("finish", list.stream().filter(map1 -> map1.get("setup") != null && Integer.parseInt(map1.get("setup").toString()) == 0).count());
        return map;
    }

    @Override
    public <T> IPage<Map<String, Object>> detail(Page<T> tPage, Long serviceId, Long regionId, Long supplierId) {
        return this.baseMapper.detail(tPage, serviceId, regionId, supplierId);
    }

    @Override
    public Map<String, List<Map<String, Object>>> projectProgress(Long serviceId) {
        Map<String, List<Map<String, Object>>> result = new HashMap<>();
        List<TBSopPlanDateLogDto> tbSopPlanDateLogDtoList = tbSopPlanDateLogService.findSopPlanDateLog(serviceId);
        if (!CollectionUtils.isEmpty(tbSopPlanDateLogDtoList)) {
            Map<Long, Long> endTimeMap = new HashMap<>();//取终止的流程日期
            List<Map<String, Object>> plan = new ArrayList<>(), actualed = new ArrayList<>();
            LinkedMultiValueMap<Long, TBSopPlanDateLogDto> sopPlanDateLogDtoLinkedMultiValueMap = new LinkedMultiValueMap<>();
            for (TBSopPlanDateLogDto t : tbSopPlanDateLogDtoList) {
                sopPlanDateLogDtoLinkedMultiValueMap.add(t.getSopId(), t);
                if (t.getStatus() == FlowStatusEnum.END) {
                    endTimeMap.put(t.getSopId(), t.getFlowUpdateTime());
                }
            }
            Map<String, Integer> daysBetweenPlanCalculat = new LinkedHashMap<>();
            Map<String, Integer> daysBetweenActaledCalculat = new LinkedHashMap<>();
            for (Map.Entry<Long, List<TBSopPlanDateLogDto>> entry : sopPlanDateLogDtoLinkedMultiValueMap.entrySet()) {
                List<TBSopPlanDateLogDto> list = entry.getValue();
                TBSopPlanDateLog planDateLog = list.get(0);//计划
                TBSopPlanDateLog planActaledDateLog = null;
                if (list.size() > 1) {//实际
                    planActaledDateLog = list.get(list.size() - 1);
                }
                if (Objects.nonNull(planActaledDateLog) && endTimeMap.containsKey(planActaledDateLog.getSopId())) {
                    planActaledDateLog.setEndTime(endTimeMap.get(planActaledDateLog.getSopId()));
                }
                if (Objects.nonNull(planDateLog)) {
                    List<String> daysBetweenPlan = DateDisposeUtils.getDaysBetween(planDateLog.getBeginTime(), planDateLog.getEndTime(), SystemConstant.DEFAULT_DATE_YMD_PATTERN);
                    Map<String, Integer> daysBetweenPlanMap = new LinkedHashMap<>();
                    for (int i = 0; i < daysBetweenPlan.size(); i++) {
                        daysBetweenPlanMap.put(daysBetweenPlan.get(i), i + 1);
                    }
                    for (Map.Entry<String, Integer> entryPlan : daysBetweenPlanMap.entrySet()) {
                        if (daysBetweenPlanCalculat.containsKey(entryPlan.getKey())) {
                            daysBetweenPlanCalculat.put(entryPlan.getKey(), daysBetweenPlanCalculat.get(entryPlan.getKey()) + entryPlan.getValue());
                        } else {
                            daysBetweenPlanCalculat.put(entryPlan.getKey(), entryPlan.getValue());
                        }
                    }
                }
                if (Objects.nonNull(planActaledDateLog)) {
                    List<String> daysBetweenActualed = DateDisposeUtils.getDaysBetween(planActaledDateLog.getBeginTime(), planActaledDateLog.getEndTime(), SystemConstant.DEFAULT_DATE_YMD_PATTERN);
                    Map<String, Integer> daysBetweenActualedMap = new LinkedHashMap<>();
                    for (int i = 0; i < daysBetweenActualed.size(); i++) {
                        daysBetweenActualedMap.put(daysBetweenActualed.get(i), i + 1);
                    }
                    for (Map.Entry<String, Integer> entryActualed : daysBetweenActualedMap.entrySet()) {
                        if (daysBetweenActaledCalculat.containsKey(entryActualed.getKey())) {
                            daysBetweenActaledCalculat.put(entryActualed.getKey(), daysBetweenActaledCalculat.get(entryActualed.getKey()) + entryActualed.getValue());
                        } else {
                            daysBetweenActaledCalculat.put(entryActualed.getKey(), entryActualed.getValue());
                        }
                    }
                }
            }
            for (Map.Entry<String, Integer> entryPlan : daysBetweenPlanCalculat.entrySet()) {
                Map<String, Object> map = new HashMap<>();
                map.put("datetime", entryPlan.getKey());
                map.put("count", entryPlan.getValue());
                plan.add(map);
            }
            for (Map.Entry<String, Integer> entryActaled : daysBetweenActaledCalculat.entrySet()) {
                Map<String, Object> map = new HashMap<>();
                map.put("datetime", entryActaled.getKey());
                map.put("count", entryActaled.getValue());
                actualed.add(map);
            }
            result.put("plan", plan);
            result.put("actual", actualed);
        }
        return result;
    }
}
