package com.engine.attendance.attendanceanalysis.cmd;

import com.engine.common.biz.AbstractCommonCommand;
import com.engine.common.entity.BizLogContext;
import com.engine.common.util.DateUtil;
import com.engine.core.interceptor.CommandContext;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import weaver.general.Util;

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

@Slf4j
public class GetClockInTimeItemCmd extends AbstractCommonCommand<Map<String,Object>> {
    public GetClockInTimeItemCmd(Map<String, Object> params){
        this.params=params;
    }
    @Override
    public BizLogContext getLogContext() {
        return null;
    }

    @Override
    public Map<String, Object> execute(CommandContext commandContext) {
        //打卡日期
        String needGetDate = Util.null2String(params.get("date"));
        //打卡数据
        Map<String, List<Map<String,Object>>> clockInTimeCollect = (Map<String, List<Map<String,Object>>>)params.get("clockInTimeCollect");
        //班次数据
        Map<String, List<Map<String,Object>>> schedulingResultCollect = (Map<String, List<Map<String,Object>>>)params.get("schedulingResultCollect");

        Map<String, Object> resultMap = Maps.newHashMap();
        List<Map<String, Object>> resultList = Lists.newArrayList();
        resultMap.put("resultList",resultList);

        //当天打卡日期集合
        List<Map<String,Object>> needGetDateList = clockInTimeCollect.get(needGetDate);
        //当天班次
        List<Map<String,Object>> needGetDateScheduling = schedulingResultCollect.get(needGetDate);

        //前一天的打卡集合
        List<Map<String,Object>> beforeNeedGetDateList = clockInTimeCollect.get(DateUtil.beforeDay(needGetDate,1));
        //前一天班次
        List<Map<String,Object>> beforeNeedGetDateScheduling = schedulingResultCollect.get(DateUtil.beforeDay(needGetDate,1));

        //后一天的打卡集合
        List<Map<String,Object>> afterNeedGetDateList = clockInTimeCollect.get(DateUtil.AfterDay(needGetDate,1));
        //后一天班次
        List<Map<String,Object>> afterNeedGetDateScheduling = schedulingResultCollect.get(DateUtil.AfterDay(needGetDate,1));


        if (needGetDateList == null || needGetDateScheduling== null){
            return resultMap;
        }else if (beforeNeedGetDateList == null && afterNeedGetDateList == null ){
            resultList = needGetDateList;
        }else if (beforeNeedGetDateList != null && afterNeedGetDateList == null){//前一天有打卡数据，后一天没有打卡数据
            if (beforeNeedGetDateScheduling == null){
                resultMap.put("resultList",needGetDateList);
                return resultMap;
            }
            resultList=computeStartTime(beforeNeedGetDateScheduling,beforeNeedGetDateList,needGetDateScheduling,needGetDateList,needGetDate);
        }else if (beforeNeedGetDateList == null && afterNeedGetDateList != null){  //前一天没有打卡数据，后一天有打卡数据
            if (afterNeedGetDateScheduling == null){
                resultMap.put("resultList",needGetDateList);
                return resultMap;
            }
            resultList=computeEndTime(afterNeedGetDateScheduling,afterNeedGetDateList,needGetDateScheduling,needGetDateList,needGetDate);
        }else if (beforeNeedGetDateList !=null && afterNeedGetDateList != null){
            //前后一天都有打卡数据
            if (beforeNeedGetDateScheduling == null && afterNeedGetDateScheduling ==null){
                resultList = needGetDateList;
            }else if (beforeNeedGetDateScheduling != null && afterNeedGetDateScheduling ==null){
                resultList=computeStartTime(beforeNeedGetDateScheduling,beforeNeedGetDateList,needGetDateScheduling,needGetDateList,needGetDate);
            }else if (beforeNeedGetDateScheduling == null && afterNeedGetDateScheduling != null){
                resultList=computeEndTime(afterNeedGetDateScheduling,afterNeedGetDateList,needGetDateScheduling,needGetDateList,needGetDate);
            }else if (beforeNeedGetDateScheduling != null &&  afterNeedGetDateScheduling != null){
                resultList=computeStartTime(beforeNeedGetDateScheduling,beforeNeedGetDateList,needGetDateScheduling,needGetDateList,needGetDate);
                resultList=computeEndTime(afterNeedGetDateScheduling,afterNeedGetDateList,needGetDateScheduling,resultList,needGetDate);

            }

        }
        resultList = resultList.stream().sorted(Comparator.comparing(e->DateUtil.getTime(e.get("signdate")+" "+e.get("signtime")).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());

        log.info("needGetDate : [{}],resultList : [{}]",needGetDate,resultList);
        resultMap.put("resultList",resultList);
        return resultMap;
    }


    /**
     *
     * 计算当天的开始工作时间
     * @param beforeNeedGetDateScheduling 前一天班次
     * @param beforeNeedGetDateList 前一天打卡数据集合
     * @param needGetDateScheduling 当天班次
     * @param needGetDateList 当天打卡数据集合
     * @return
     */
    public List<Map<String,Object>> computeStartTime(List<Map<String,Object>> beforeNeedGetDateScheduling,List<Map<String,Object>> beforeNeedGetDateList,
                                                     List<Map<String,Object>> needGetDateScheduling,List<Map<String,Object>> needGetDateList,String needGetDate){
        //前一天是否跨天 1:跨天
        String beforesfkt = Util.null2String(beforeNeedGetDateScheduling.get(0).get("sfkt"));
        //当天是否跨天 1：跨天
        String nowsfkt = Util.null2String(needGetDateScheduling.get(0).get("sfkt"));
        if ("1".equals(beforesfkt) && !"1".equals(nowsfkt)){
            //前一天跨天，当天没有跨天
            //昨天的最晚打卡数据在今天，今天剔除昨天的打卡数据
            needGetDateList = computeStartTimeRemove(beforeNeedGetDateScheduling,needGetDateList,needGetDate);

        }else if (!"1".equals(beforesfkt) && "1".equals(nowsfkt)){
            //前一天没有跨天，当天跨天
            //今天的最早打卡数据在昨天，今天的打卡数据里添加昨天的打卡数据
            needGetDateList = computeStartTimeAdd(beforeNeedGetDateScheduling,beforeNeedGetDateList,needGetDateScheduling,needGetDateList,needGetDate);

        }else if ("1".equals(beforesfkt) && "1".equals(nowsfkt)){
            //前一天跨天，当天也跨天

            /** 前一天 */
            beforeNeedGetDateScheduling =  beforeNeedGetDateScheduling.stream().filter(e -> "1".equals(Util.null2String(e.get("jsdk")))).collect(Collectors.toList());
            Map<String,Object> lastDataMap = beforeNeedGetDateScheduling.get(beforeNeedGetDateScheduling.size()-1);
            String beforekssj = needGetDate +" "+Util.null2String(lastDataMap.get("dtkssj"));
            String beforejssj = needGetDate +" "+Util.null2String(lastDataMap.get("dtjssj"));


            /** 当天 */
            needGetDateScheduling =  needGetDateScheduling.stream().filter(e -> "1".equals(Util.null2String(e.get("ksdk")))).collect(Collectors.toList());
            Map<String,Object> firstDataMap = needGetDateScheduling.get(0);
            //判断最早日期是否跨天
            String nowkssj = needGetDate +" "+Util.null2String(firstDataMap.get("dtkssj"));
            String nowjssj = needGetDate +" "+Util.null2String(firstDataMap.get("dtjssj"));


            if (DateUtil.getTime(beforekssj).compareTo(DateUtil.getTime(beforejssj)) > 0 &&
                    DateUtil.getTime(nowkssj).compareTo(DateUtil.getTime(nowjssj)) > 0){
                //前一天的最晚打卡时间在今天，今天的最早打卡时间在昨天
                /** 目前没有这种情况，会造成数据混乱，无法判定时间归属哪一天。逻辑待定**/


            }else if (DateUtil.getTime(beforekssj).compareTo(DateUtil.getTime(beforejssj)) <= 0 &&
                    DateUtil.getTime(nowkssj).compareTo(DateUtil.getTime(nowjssj)) > 0){
                //今天的最早打卡数据在昨天
                needGetDateList = computeStartTimeAdd(beforeNeedGetDateScheduling,beforeNeedGetDateList,needGetDateScheduling,needGetDateList,needGetDate);
            }else if (DateUtil.getTime(beforekssj).compareTo(DateUtil.getTime(beforejssj)) > 0 && DateUtil.getTime(nowkssj).compareTo(DateUtil.getTime(nowjssj)) <= 0){
                //昨天的最晚打卡数据在今天
                needGetDateList = computeStartTimeRemove(beforeNeedGetDateScheduling,needGetDateList,needGetDate);
            }

        }
        return needGetDateList;
    }


    /***
     * 计算当天的结束工作时间
     * @param afterNeedGetDateScheduling 后一天排班班次
     * @param afterNeedGetDateList 后一天打卡数据
     * @param needGetDateScheduling 今天班次
     * @param needGetDateList 今天打卡数据
     * @param needGetDate 当天日期
     * @return
     */
    public List<Map<String,Object>> computeEndTime(List<Map<String,Object>> afterNeedGetDateScheduling,List<Map<String,Object>> afterNeedGetDateList,
                                                   List<Map<String,Object>> needGetDateScheduling,List<Map<String,Object>> needGetDateList,String needGetDate){
        //后一天是否跨天 1:跨天
        String aftersfkt = Util.null2String(afterNeedGetDateScheduling.get(0).get("sfkt"));
        //当天是否跨天 1：跨天
        String nowsfkt = Util.null2String(needGetDateScheduling.get(0).get("sfkt"));
        if ("1".equals(aftersfkt) && !"1".equals(nowsfkt)){
            //后一天跨天，当天没有跨天
            //后一天的最早开始时间在今天
            needGetDateList = computeEndTimeRemove(afterNeedGetDateScheduling,needGetDateScheduling,needGetDateList,needGetDate);

        }else if (!"1".equals(aftersfkt) && "1".equals(nowsfkt)){
            //后没有跨天，当天跨天
            //今天的最晚打卡数据在后一天，添加今天里面后一天的打卡数据
            needGetDateList = computeEndTimeAdd(afterNeedGetDateList,needGetDateScheduling,needGetDateList,needGetDate);

        }else if ("1".equals(aftersfkt) && "1".equals(nowsfkt)){
            //前后2天都跨天
            /** 当天 **/
            needGetDateScheduling = needGetDateScheduling.stream().filter(e -> "1".equals(Util.null2String(e.get("jsdk")))).collect(Collectors.toList());
            Map<String,Object> endNeedGetDateSchedule = needGetDateScheduling.get(needGetDateScheduling.size()-1);
            //判断最晚打卡时间是否跨天
            String nowkssj = needGetDate +" "+Util.null2String(endNeedGetDateSchedule.get("dtkssj"));
            String nowjssj = needGetDate +" "+Util.null2String(endNeedGetDateSchedule.get("dtjssj"));


            /** 后天 **/
            afterNeedGetDateScheduling =  afterNeedGetDateScheduling.stream().filter(e -> "1".equals(Util.null2String(e.get("ksdk")))).collect(Collectors.toList());
            Map<String,Object> firstDataMap = afterNeedGetDateScheduling.get(0);
            String afterkssj = needGetDate +" "+Util.null2String(firstDataMap.get("dtkssj"));
            String afterjssj = needGetDate +" "+Util.null2String(firstDataMap.get("dtjssj"));


            if (DateUtil.getTime(afterkssj).compareTo(DateUtil.getTime(afterjssj)) > 0 &&
                    DateUtil.getTime(nowkssj).compareTo(DateUtil.getTime(nowjssj)) > 0){
                //前一天的最晚打卡时间在今天，今天的最早打卡时间在昨天
                /** 目前没有这种情况，会造成数据混乱，无法判定时间归属哪一天。逻辑待定**/

            }else if (DateUtil.getTime(afterkssj).compareTo(DateUtil.getTime(afterkssj)) <= 0 &&
                    DateUtil.getTime(nowkssj).compareTo(DateUtil.getTime(nowjssj)) > 0){
                //今天的最晚打卡数据在后一天
                needGetDateList = computeEndTimeAdd(afterNeedGetDateList,needGetDateScheduling,needGetDateList,needGetDate);

            }else if (DateUtil.getTime(afterkssj).compareTo(DateUtil.getTime(afterkssj)) > 0 && DateUtil.getTime(nowkssj).compareTo(DateUtil.getTime(nowjssj)) <= 0){
                //后一天的最早开始时间在今天
                needGetDateList = computeEndTimeRemove(afterNeedGetDateScheduling,needGetDateScheduling,needGetDateList,needGetDate);

            }

        }


        return needGetDateList;
    }

    /**
     * 后一天的最早开始时间在今天，由于打卡时间以前一天优先，所暂不做任何处理
     * @param afterNeedGetDateScheduling
     * @param needGetDateScheduling
     * @param needGetDateList
     * @return
     */
    public List<Map<String,Object>> computeEndTimeRemove(List<Map<String,Object>> afterNeedGetDateScheduling,
                                                         List<Map<String,Object>> needGetDateScheduling,List<Map<String,Object>> needGetDateList,String needGetDate){
        //获得需要打卡的
        afterNeedGetDateScheduling =  afterNeedGetDateScheduling.stream().filter(e -> "1".equals(Util.null2String(e.get("ksdk")))).collect(Collectors.toList());
        Map<String,Object> firstDataMap = afterNeedGetDateScheduling.get(0);
        needGetDateScheduling = needGetDateScheduling.stream().filter(e -> "1".equals(Util.null2String(e.get("ksdk")))).collect(Collectors.toList());
        Map<String,Object> endNeedGetDateSchedule = needGetDateScheduling.get(needGetDateScheduling.size()-1);
        //判断最早日期是否跨天
        String kssj = needGetDate +" "+Util.null2String(firstDataMap.get("dtkssj"));
        String jssj = needGetDate +" "+Util.null2String(firstDataMap.get("dtjssj"));
        if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(jssj)) > 0){
            //最早打卡日期跨天

        }

        return needGetDateList;
    }

    /**
     * 今天的最晚打卡数据在后一天，添加后一天的打卡数据
     * @param afterNeedGetDateList
     * @param needGetDateScheduling
     * @param needGetDateList
     * @param needGetDate
     * @return
     */
    public List<Map<String,Object>> computeEndTimeAdd(List<Map<String,Object>> afterNeedGetDateList,
                                                      List<Map<String,Object>> needGetDateScheduling,List<Map<String,Object>> needGetDateList,String needGetDate){
        needGetDateScheduling = needGetDateScheduling.stream().filter(e -> "1".equals(Util.null2String(e.get("jsdk")))).collect(Collectors.toList());
        Map<String,Object> endNeedGetDateSchedule = needGetDateScheduling.get(needGetDateScheduling.size()-1);
        //判断最晚打卡时间是否跨天
        String kssj = needGetDate +" "+Util.null2String(endNeedGetDateSchedule.get("dtkssj"));
        String jssj = needGetDate +" "+Util.null2String(endNeedGetDateSchedule.get("dtjssj"));
        if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(jssj)) > 0){
            //结束时间
            jssj = DateUtil.AfterDay(needGetDate,1) +" "+endNeedGetDateSchedule.get("dtjssj");
            //推后打卡分钟数
            long thdkfzs = Util.null2String(endNeedGetDateSchedule.get("thdkfzs")).equals("") ? 0:Long.valueOf(Util.null2String(endNeedGetDateSchedule.get("thdkfzs")));

            String latestTime = DateUtil.AfterMinutes(jssj,thdkfzs);
            for (int i=afterNeedGetDateList.size()-1;i>=0;i--){
                //前一天的打卡数据集合里在当天最早打卡日期之后的都属于当天
                String dateTime = afterNeedGetDateList.get(i).get("signdate")+" "+afterNeedGetDateList.get(i).get("signtime");
                if (DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dateTime)) >=0){
                    needGetDateList.add(afterNeedGetDateList.get(i));
                }
                if (DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dateTime)) <0 &&
                        DateUtil.getTime(latestTime).compareTo(DateUtil.getTime(dateTime)) >=0){

                    needGetDateList.add(afterNeedGetDateList.get(i));
                    break;
                }

            }
            //排序
           // needGetDateList = needGetDateList.stream().sorted(Comparator.comparing(e->DateUtil.getTime(e.get("signdate")+" "+e.get("signtime")).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());

        }
        return needGetDateList;
    }



    /**
     * 计算当天开始时间，昨天的最晚打卡数据在今天，今天的打卡数据剔除昨天的打卡数据
     * @param beforeNeedGetDateScheduling
     * @param needGetDateList
     * @param needGetDate
     * @return
     */
    public List<Map<String,Object>> computeStartTimeRemove(List<Map<String,Object>> beforeNeedGetDateScheduling,List<Map<String,Object>> needGetDateList,String needGetDate){
        //获得需要打卡的
        beforeNeedGetDateScheduling =  beforeNeedGetDateScheduling.stream().filter(e -> "1".equals(Util.null2String(e.get("jsdk")))).collect(Collectors.toList());
        Map<String,Object> lastDataMap = beforeNeedGetDateScheduling.get(beforeNeedGetDateScheduling.size()-1);
        String kssj = needGetDate +" "+Util.null2String(lastDataMap.get("dtkssj"));
        String jssj = needGetDate +" "+Util.null2String(lastDataMap.get("dtjssj"));
        List<Map<String,Object>> resultList = Lists.newArrayList();
        //昨天的最晚打卡数据在今天
        if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(jssj)) > 0){
            //最后打卡日期跨天
            jssj = needGetDate +" "+lastDataMap.get("dtjssj");
            //最大打卡时间
            long thdkfzs = Util.null2String(lastDataMap.get("thdkfzs")).equals("") ? 0:Long.valueOf(Util.null2String(lastDataMap.get("thdkfzs")));
            String mostTime = DateUtil.AfterMinutes(jssj,thdkfzs);
            for (Map<String,Object> date : needGetDateList){
                //前一天最后打卡日期之前的打卡数据都归属前一天，进行过滤
                String dateTime = date.get("signdate")+" "+date.get("signtime");
                if (DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dateTime)) <=0){
                    resultList.add(date);

                }
            }
            Map<String,Object> resultMap = resultList.stream().min(Comparator.comparing(e->DateUtil.getTime(e.get("signdate")+" "+e.get("signtime")).toInstant(ZoneOffset.of("+8")).toEpochMilli())).get();
            String minTime = resultMap.get("signdate")+" "+resultMap.get("signtime");
            if (DateUtil.getTime(mostTime).compareTo(DateUtil.getTime(minTime)) >=0){
                //当天第一比时间在，最后打卡日期之后，最长延迟打卡时间之前的，归属前一天
                resultList.remove(resultMap);
            }
            needGetDateList = resultList;
        }
        return needGetDateList;
    }

    /**
     * 计算当天开始时间，今天的最早打卡数据在昨天，往今天的打卡数据里添加昨天的打卡数据
     * @param beforeNeedGetDateList
     * @param needGetDateScheduling
     * @param needGetDateList
     * @param needGetDate
     * @return
     */
    public List<Map<String,Object>> computeStartTimeAdd(List<Map<String,Object>> beforeNeedGetDateScheduling,List<Map<String,Object>> beforeNeedGetDateList,
                                                        List<Map<String,Object>> needGetDateScheduling,List<Map<String,Object>> needGetDateList,String needGetDate){
        //获得需要打卡的
        needGetDateScheduling =  needGetDateScheduling.stream().filter(e -> "1".equals(Util.null2String(e.get("ksdk")))).collect(Collectors.toList());
        Map<String,Object> firstDataMap = needGetDateScheduling.get(0);

        beforeNeedGetDateScheduling =  beforeNeedGetDateScheduling.stream().filter(e -> "1".equals(Util.null2String(e.get("jsdk")))).collect(Collectors.toList());
        Map<String,Object> lastDataMap = beforeNeedGetDateScheduling.get(beforeNeedGetDateScheduling.size()-1);
        //判断最早日期是否跨天
        String kssj = needGetDate +" "+Util.null2String(firstDataMap.get("dtkssj"));
        String jssj = needGetDate +" "+Util.null2String(firstDataMap.get("dtjssj"));
        //今天的最早打卡数据在昨天
        if(DateUtil.getTime(kssj).compareTo(DateUtil.getTime(jssj)) > 0){
            //最早打卡日期
            kssj = DateUtil.beforeDay(needGetDate,1) +" "+firstDataMap.get("dtkssj");
            //最早打卡时间
            long tqdkfzs = Util.null2String(firstDataMap.get("tqdkfzs")).equals("") ? 0:Long.valueOf(Util.null2String(firstDataMap.get("tqdkfzs")));
            String earliestTime = DateUtil.beforeMinutes(kssj,tqdkfzs);
            //前一天最晚打卡日期
            String beforejssj = DateUtil.beforeDay(needGetDate,1) + " "+Util.null2String(lastDataMap.get("dtjssj"));
            //前一天最晚延迟打卡日期
            long beforethdkfzs = Util.null2String(firstDataMap.get("thdkfzs")).equals("") ? 0:Long.valueOf(Util.null2String(firstDataMap.get("thdkfzs")));
            String lastestTime = DateUtil.AfterMinutes(jssj,beforethdkfzs);
            List<Map<String,Object>> beforeleaveDate = Lists.newArrayList();
            for (Map<String,Object> map : beforeNeedGetDateList){
                String dateTime = map.get("signdate")+" "+map.get("signtime");
                if (DateUtil.getTime(beforejssj).compareTo(DateUtil.getTime(dateTime)) <=0){
                    beforeleaveDate.add(map);
                }
            }
            if (beforeleaveDate.size() > 0){
                String dateTime = beforeleaveDate.get(0).get("signdate")+" "+beforeleaveDate.get(0).get("signtime");
                if (DateUtil.getTime(beforejssj).compareTo(DateUtil.getTime(dateTime)) <=0 && DateUtil.getTime(lastestTime).compareTo(DateUtil.getTime(dateTime)) >=0){
                    beforeleaveDate.remove(0);
                }
            }


            for (int i=beforeleaveDate.size()-1;i>=0;i--){
                //前一天的打卡数据集合里在当天最早打卡日期之后的都属于当天
                String dateTime = beforeNeedGetDateList.get(i).get("signdate")+" "+beforeNeedGetDateList.get(i).get("signtime");
                if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dateTime)) <=0){
                    needGetDateList.add(beforeNeedGetDateList.get(i));
                }
                if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dateTime)) >0 &&
                        DateUtil.getTime(earliestTime).compareTo(DateUtil.getTime(dateTime)) <=0){
                    //取前一天
                    needGetDateList.add(beforeNeedGetDateList.get(i));
                    break;
                }

            }
            //排序
           // needGetDateList = needGetDateList.stream().sorted(Comparator.comparing(e->DateUtil.getTime(e.get("signdate")+" "+e.get("signtime")).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());
        }
        return needGetDateList;
    }

}
