package com.engine.attendance.attendanceanalysis.cmd.getclockInpoint;

import com.engine.attendance.attendanceanalysis.dto.ClockPointDTO;
import com.engine.attendance.enums.ClassSegmentTypeEnum;
import com.engine.attendance.enums.ClockPointEnum;
import com.engine.common.biz.AbstractCommonCommand;
import com.engine.common.entity.BizLogContext;
import com.engine.common.util.DateUtil;
import com.engine.common.util.Utils;
import com.engine.core.interceptor.CommandContext;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 在连续的工作、加班时间段只准首尾打卡的情况下
 * 加班和工作时段连着时，需根据打卡情况变动规则
 *
 */
@Slf4j
public class AdjustByWorkOverTimeCmd extends AbstractCommonCommand<Map<String, Object>> {

    public AdjustByWorkOverTimeCmd(Map<String, Object> params) {
        this.params = params;
    }

    @Override
    public BizLogContext getLogContext() {
        return null;
    }

    @Override
    public Map<String, Object> execute(CommandContext commandContext) {
        Map<String,Object> resultMap = Maps.newHashMap();
        List<ClockPointDTO> clcokInPointList = (List<ClockPointDTO>)params.get("clcokInPointList");
        List<Map<String, Object>> scheduleResult = (List<Map<String, Object>>)params.get("scheduleResult");
        scheduleResult = scheduleResult.stream().filter(e -> !ClassSegmentTypeEnum.ASK_FOR_LEAVE.getKey().equals(e.get("bdlx")) && !ClassSegmentTypeEnum.EVECTION.getKey().equals(e.get("bdlx"))).collect(Collectors.toList());
        String analysisDate = params.get("analysisDate").toString();
        List<Map<String, Object>> askForLeaveAndEvctionScheduleList = (List<Map<String, Object>>)params.get("askForLeaveAndEvctionScheduleList");
        List<ClockPointDTO> adjustClcokInPointList = Lists.newArrayList();
        for (int i=0;i<clcokInPointList.size();i++){
            ClockPointDTO clockPointDTO = clcokInPointList.get(i);
            //班次时间
            String classTime = clockPointDTO.getClassTime();
            String classSegmentType = clockPointDTO.getClassSegmentType();

            //当为加班卡点时
            if (Utils.ifOverTimeClassSegment(classSegmentType)){
                int scheduleIndex = getScheduleIndex(classTime,scheduleResult,analysisDate);
                if (clockPointDTO.getPointType() == ClockPointEnum.END){
                    int adjustScheduleIndex = getBeforeAccordWithScheduleIndex(clcokInPointList,scheduleIndex,scheduleResult,clockPointDTO.getClockTime(),analysisDate);
                    if (adjustScheduleIndex<scheduleIndex){
                        //将原先的打卡调整为该班段的结束打卡卡点
                        Map<String, Object> adjustScheduleMap = scheduleResult.get(adjustScheduleIndex);
                        String jssj = Utils.getjssjTime(adjustScheduleMap,analysisDate);
                        //原先卡点不计异常
                        clockPointDTO.setRecord(false);
                        ClockPointDTO adjustClockPointDTO = ClockPointDTO.builder().classTime(jssj).pointType(ClockPointEnum.END).timeType(clockPointDTO.getTimeType())
                                .classSegmentType(adjustScheduleMap.get("bdlx").toString()).clockTime(clockPointDTO.getClockTime()).record(true).build();
                        adjustClcokInPointList.add(adjustClockPointDTO);
                    }
                }else if (clockPointDTO.getPointType() == ClockPointEnum.START){
                    //上班卡
                    int adjustScheduleIndex = getAfterAccordWithScheduleIndex(clcokInPointList,scheduleIndex,scheduleResult,clockPointDTO.getClockTime(),analysisDate);
                    if (adjustScheduleIndex>scheduleIndex){
                        //将原先的打卡调整为该班段的结束打卡卡点
                        Map<String, Object> adjustScheduleMap = scheduleResult.get(adjustScheduleIndex);
                        String kssj = Utils.getkssjTime(adjustScheduleMap,analysisDate);
                        //原先卡点不计异常
                        clockPointDTO.setRecord(false);
                        ClockPointDTO adjustClockPointDTO = ClockPointDTO.builder().classTime(kssj).pointType(ClockPointEnum.START).timeType(clockPointDTO.getTimeType())
                                .classSegmentType(adjustScheduleMap.get("bdlx").toString()).clockTime(clockPointDTO.getClockTime()).record(true).build();
                        adjustClcokInPointList.add(adjustClockPointDTO);
                    }

                }

            }

        }
        adjustClcokInPointList.addAll(clcokInPointList);
        log.info("AdjustByWorkOverTimeCmd : [{}]",adjustClcokInPointList);
        resultMap.put("clcokInPointList",adjustClcokInPointList);
        return resultMap;
    }

    /**
     * 往前递归排班
     * @param scheduleIndex
     * @param scheduleResult
     * @param clockTimeMap 打卡集合
     * @return
     */
    public int getBeforeAccordWithScheduleIndex(List<ClockPointDTO> clcokInPointList,int scheduleIndex,List<Map<String, Object>> scheduleResult,Map<String, Object> clockTimeMap,String analysisDate){
        if (scheduleIndex == 0){
            return scheduleIndex;
        }
        Map<String, Object> scheduleMap = scheduleResult.get(scheduleIndex);
        Map<String, Object> beforeScheduleMap = scheduleResult.get(scheduleIndex-1);
        String dtkssj = Utils.getkssjTime(scheduleMap,analysisDate);
        String beforeDtjssj = Utils.getjssjTime(beforeScheduleMap,analysisDate);
        ClockPointDTO nowclockPointDTO = null;
        for (ClockPointDTO clockPointDTO :clcokInPointList){
            if (clockPointDTO.getClassTime().equals(dtkssj)){
                nowclockPointDTO = clockPointDTO;
            }
        }

        String beforeClassSegment = beforeScheduleMap.get("bdlx").toString();
        String clockTime = clockTimeMap == null?"" : clockTimeMap.get("signdate")+" "+clockTimeMap.get("signtime");



        if (Utils.ifRestClassSegment(beforeClassSegment) || DateUtil.getTime(beforeDtjssj).compareTo(DateUtil.getTime(dtkssj)) != 0 || scheduleMap.get("bdlx").equals(ClassSegmentTypeEnum.WORK_TIME.getKey()) ||
                (nowclockPointDTO != null && nowclockPointDTO.getTimeType() != ClockPointEnum.EMPTY)){
            //前一个班段为休息班段、与前一个班段不连续时、当前班次为工作时段，不作处理直接返回
            return scheduleIndex;
        }
        if (clockTimeMap == null || DateUtil.getTime(clockTime).compareTo(DateUtil.getTime(dtkssj)) <0){
            //当前加班为漏卡或者打卡时间小于加班开始时间进行往前递归
            scheduleIndex--;
            return getBeforeAccordWithScheduleIndex(clcokInPointList,scheduleIndex,scheduleResult,clockTimeMap,analysisDate);

        }else {
            return scheduleIndex;
        }

    }

    /**
     * 往后递归排班
     * @param scheduleIndex
     * @param scheduleResult
     * @param clockTimeMap 打卡集合
     * @return
     */
    public int getAfterAccordWithScheduleIndex(List<ClockPointDTO> clcokInPointList,int scheduleIndex,List<Map<String, Object>> scheduleResult,Map<String, Object> clockTimeMap,String analysisDate){
        if (scheduleIndex == scheduleResult.size()-1){
            return scheduleIndex;
        }
        Map<String, Object> scheduleMap = scheduleResult.get(scheduleIndex);
        Map<String, Object> afterScheduleMap = scheduleResult.get(scheduleIndex+1);
        String dtjssj = Utils.getjssjTime(scheduleMap,analysisDate);
        String afterDtkssj = Utils.getkssjTime(afterScheduleMap,analysisDate);
        String afterClassSegment = afterScheduleMap.get("bdlx").toString();
        String clockTime = clockTimeMap == null?"" : clockTimeMap.get("signdate")+" "+clockTimeMap.get("signtime");
        ClockPointDTO nowclockPointDTO = null;
        for (ClockPointDTO clockPointDTO :clcokInPointList){
            if (clockPointDTO.getClassTime().equals(dtjssj)){
                nowclockPointDTO = clockPointDTO;
            }
        }

        if (Utils.ifRestClassSegment(afterClassSegment) || DateUtil.getTime(afterDtkssj).compareTo(DateUtil.getTime(dtjssj)) != 0 || scheduleMap.get("bdlx").equals(ClassSegmentTypeEnum.WORK_TIME.getKey()) ||
                (nowclockPointDTO != null && nowclockPointDTO.getTimeType() != ClockPointEnum.EMPTY)){
            //后一个班段为休息班段、与后一个上班段不连续时、当前班次为工作时段，不作处理直接返回
            return scheduleIndex;
        }
        if (clockTimeMap == null || DateUtil.getTime(clockTime).compareTo(DateUtil.getTime(dtjssj)) >0){
            //当前加班为漏卡或者打卡时间小于加班开始时间进行往前递归
            scheduleIndex++;
            return getAfterAccordWithScheduleIndex(clcokInPointList,scheduleIndex,scheduleResult,clockTimeMap,analysisDate);

        }else {
            return scheduleIndex;
        }
    }

    public int getScheduleIndex(String time,List<Map<String, Object>> scheduleResult,String analysisDate){
        for (int i =0;i<scheduleResult.size();i++){
            String dtkssj = Utils.getkssjTime(scheduleResult.get(i),analysisDate);
            String dtjssj = Utils.getjssjTime(scheduleResult.get(i),analysisDate);
            if (dtkssj.equals(time) || dtjssj.equals(time)){
                return i;
            }
        }
        return -1;
    }


}
