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

import com.engine.jucailinkq.attendance.attendanceanalysis.cmd.getclockInpoint.biz.AbstractAdjustClockPointAction;
import com.engine.jucailinkq.attendance.attendanceanalysis.dto.clockpoint.ClockPointDTO;
import com.engine.jucailinkq.attendance.attendanceanalysis.dto.clockpoint.ClockPointInfo;
import com.engine.jucailinkq.attendance.enums.ClockPointEnum;
import com.engine.jucailinkq.common.util.DateUtil;
import com.engine.jucailinkq.common.util.Utils;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;

import java.time.ZoneOffset;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 当卡点成对出现时合并对应的班段
 */
@Slf4j
public class MergeApairClockPoint extends AbstractAdjustClockPointAction {
    private String analysisDate;
    @Override
    public List<ClockPointDTO> execute(ClockPointInfo clockPointInfo) {
        List<ClockPointDTO> clcokInPointList = clockPointInfo.getClcokInPointList();
        List<Map<String, Object>> scheduleResult = clockPointInfo.getScheduleResult();
        analysisDate = clockPointInfo.getAnalysisDate();
        List<ClockPointDTO> allClcokInPointList = Utils.converToClockPointBySchedule(scheduleResult,analysisDate);

        clcokInPointList = clcokInPointList.stream().sorted(Comparator.comparing(e-> DateUtil.getTime(e.getClassTime()).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());
        if (clcokInPointList.size() <= 1){
            return clcokInPointList;
        }
        List<ClockPointDTO> adjustClcokInPointList = Lists.newArrayList();
        for (int i=0;i<clcokInPointList.size()-1;i++){
            ClockPointDTO startPointDTO = clcokInPointList.get(i);
            ClockPointDTO endPointDTO = clcokInPointList.get(i+1);

            if (startPointDTO.getPointType() == ClockPointEnum.START && endPointDTO.getPointType() == ClockPointEnum.END){
                int startIndex = getClockPointIndex(startPointDTO,allClcokInPointList);
                int startScheduleIndex = getStartScheduleIndex(startPointDTO.getClassTime(),scheduleResult);
                if (Utils.ifAskforOrEvctionClassSegment(startPointDTO.getClassSegmentType())){
                    startScheduleIndex = getEndScheduleIndex(startPointDTO.getClassTime(),scheduleResult);
                }
                int endIndex = getClockPointIndex(endPointDTO,allClcokInPointList);
                int endScheduleIndex = getEndScheduleIndex(endPointDTO.getClassTime(),scheduleResult);
                if (Utils.ifAskforOrEvctionClassSegment(endPointDTO.getClassSegmentType())){
                    endScheduleIndex = getStartScheduleIndex(endPointDTO.getClassTime(),scheduleResult);
                }
                if (startIndex == endIndex-1){
                    //同属一个班段不用合并
                    i = i+1;
                    continue;
                }

                if (startPointDTO.getTimeType() == ClockPointEnum.EMPTY){
                    //开始漏卡
                    for (int j=startIndex+1;j<endIndex;j++){
                        ClockPointDTO clockPointDTO = allClcokInPointList.get(j);
                        if (!Utils.ifRestClassSegment(clockPointDTO.getClassSegmentType())){
                            if (clockPointDTO.getPointType() == ClockPointEnum.START){
                                clockPointDTO.setTimeType(ClockPointEnum.EMPTY);
                                adjustClcokInPointList.add(clockPointDTO);
                            }
                        }
                    }

                }
                if (startPointDTO.getTimeType() == ClockPointEnum.AFTER){
                    //迟到
                    //打卡时间
                    String startClockTime = startPointDTO.getClockTime().get("signdate")+" "+startPointDTO.getClockTime().get("signtime");
                    //当开始时间上的迟到大于班段上的结束时间时
                    if (DateUtil.getTime(startClockTime).compareTo(DateUtil.getTime(Utils.getjssjTime(scheduleResult.get(startScheduleIndex),analysisDate))) > 0){
                        for (int j=startIndex+1;j<endIndex;j++){
                            ClockPointDTO clockPointDTO = allClcokInPointList.get(j);
                            if (!Utils.ifRestClassSegment(clockPointDTO.getClassSegmentType())){
                                if (clockPointDTO.getPointType() == ClockPointEnum.START && DateUtil.getTime(startClockTime).compareTo(DateUtil.getTime(clockPointDTO.getClassTime())) > 0){
                                    clockPointDTO.setTimeType(ClockPointEnum.AFTER);
                                    clockPointDTO.setClockTime(startPointDTO.getClockTime());
                                    adjustClcokInPointList.add(clockPointDTO);
                                }
                            }
                        }
                    }
                }

                if (endPointDTO.getTimeType() == ClockPointEnum.EMPTY){
                    //结束漏卡
                    for (int j=startIndex+1;j<endIndex;j++){
                        ClockPointDTO clockPointDTO = allClcokInPointList.get(j);
                        if (!Utils.ifRestClassSegment(clockPointDTO.getClassSegmentType())){
                            if (clockPointDTO.getPointType() == ClockPointEnum.END){
                                clockPointDTO.setTimeType(ClockPointEnum.EMPTY);
                                adjustClcokInPointList.add(clockPointDTO);
                            }
                        }
                    }
                }
                if (endPointDTO.getTimeType() == ClockPointEnum.BEFORE){
                    //早退
                    //打卡时间
                    String endClockTime = endPointDTO.getClockTime().get("signdate")+" "+endPointDTO.getClockTime().get("signtime");
                    if (DateUtil.getTime(endClockTime).compareTo(DateUtil.getTime(Utils.getkssjTime(scheduleResult.get(endScheduleIndex),analysisDate))) < 0){
                        for (int j=startIndex+1;j<endIndex;j++){
                            ClockPointDTO clockPointDTO = allClcokInPointList.get(j);
                            if (!Utils.ifRestClassSegment(clockPointDTO.getClassSegmentType())){
                                if (clockPointDTO.getPointType() == ClockPointEnum.END && DateUtil.getTime(endClockTime).compareTo(DateUtil.getTime(clockPointDTO.getClassTime())) < 0){
                                    clockPointDTO.setTimeType(ClockPointEnum.BEFORE);
                                    clockPointDTO.setClockTime(endPointDTO.getClockTime());
                                    adjustClcokInPointList.add(clockPointDTO);
                                }
                            }
                        }
                    }

                }

                i = i+1;
            }

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

    /**
     * 往后递归排班
     * @return
     */
    public int getAfterAccordWithScheduleIndex(String startClockTime,List<Map<String, Object>> scheduleResult,int startScheduleIndex){
        for (int i=startScheduleIndex+1;i<scheduleResult.size();i++){
            String kssj = Utils.getkssjTime(scheduleResult.get(i),analysisDate);
            String jssj = Utils.getjssjTime(scheduleResult.get(i),analysisDate);
            if (DateUtil.getTime(startClockTime).compareTo(DateUtil.getTime(kssj))>=0 &&
                    DateUtil.getTime(startClockTime).compareTo(DateUtil.getTime(jssj)) <=0){
                return i;
            }

        }
        return scheduleResult.size()-1;
    }
    /**
     * 往前递归排班
     * @return
     */
    public int getBeforeAccordWithScheduleIndex(String endClockTime,List<Map<String, Object>> scheduleResult,int endScheduleIndex){
        for (int i=endScheduleIndex-1;i>=0;i--){
            String kssj = Utils.getkssjTime(scheduleResult.get(i),analysisDate);
            String jssj = Utils.getjssjTime(scheduleResult.get(i),analysisDate);
            if (DateUtil.getTime(endClockTime).compareTo(DateUtil.getTime(kssj))>=0 &&
                    DateUtil.getTime(endClockTime).compareTo(DateUtil.getTime(jssj)) <=0){
                return i;
            }

        }
        return 0;
    }

    public int getClockPointIndex(ClockPointDTO clockPointDTO,List<ClockPointDTO> clockPointDTOList){
        for (int i =0;i<clockPointDTOList.size();i++){
            if (clockPointDTO.getPointType() == clockPointDTOList.get(i).getPointType() &&
                    clockPointDTO.getClassTime().equals(clockPointDTOList.get(i).getClassTime())){
                return i;
            }
        }
        return -1;
    }

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