package com.engine.jucailinkq.attendance.attendanceanalysis.service.impl;

import com.engine.jucailinkq.attendance.attendanceanalysis.cmd.workovertime.GetOvertimeDurationCmd;
import com.engine.jucailinkq.attendance.attendanceanalysis.cmd.item.WorkOvertimeItemCmd;
import com.engine.jucailinkq.attendance.attendanceanalysis.cmd.workovertime.SaveWorkOverTimeCmd;
import com.engine.jucailinkq.attendance.attendanceanalysis.dto.clockpoint.ClockPointDTO;
import com.engine.jucailinkq.attendance.attendanceanalysis.service.WorkOverTimeService;
import com.engine.jucailinkq.attendance.enums.*;
import com.engine.jucailinkq.common.util.CommonUtil;
import com.engine.jucailinkq.common.util.DateUtil;
import com.engine.jucailinkq.common.util.Utils;
import com.engine.core.impl.Service;
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.Calendar;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
public class WorkOverTimeServiceImpl extends Service implements WorkOverTimeService {
    @Override
    public Map<String, Object> recordWorkOverTime(Map<String, Object> params) {
        //考勤项目
        List<Map<String,Object>> attendanceItems = (List<Map<String,Object>>)params.get("attendanceItems");
        //排班
        List<Map<String, Object>> scheduleResult = (List<Map<String,Object>>)params.get("scheduleResult");
        //分析日期
        String analysisDate = Util.null2String(params.get("analysisDate"));
        //打卡卡点
        List<ClockPointDTO> clcokInTimeDataList = (List<ClockPointDTO>)params.get("clcokInTimeData");

        String userId = String.valueOf(params.get("userId"));

        Map<String,Map<String,Object>> clcokInTimeMap = Maps.newHashMap();

        Calendar calendar = Calendar.getInstance();
        calendar.set(Integer.valueOf(analysisDate.split("-")[0]), Integer.valueOf(analysisDate.split("-")[1]) - 1, 1);

        long diffdays  = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        params.put("diffdays",diffdays);

        for (ClockPointDTO clockPointDTO :clcokInTimeDataList){
            //当天打卡数据
            Map<String,Object> clcokInTime = clockPointDTO.getClockTime();
            //需要计算的班次打卡时间点
            String pointTime = clockPointDTO.getClassTime();
            clcokInTimeMap.put(pointTime,clcokInTime);
        }
        params.put("clcokInTimeMap",clcokInTimeMap);

        List<Map<String, Object>> restOverTimeList = scheduleResult.stream().filter(e->e.get("bdlx").equals(ClassSegmentTypeEnum.OVERTIME_PLAN.getKey())
                            && ClassSegmentTypeEnum.WORK_TIME.getKey().equals(e.get("beforeClassSegment"))).collect(Collectors.toList());


        /**
         *  非休息班次，加班项目结果集
         */
        Map<String,Object> resultMap = Maps.newHashMap();
        List<Map<String, Object>> workOverTimeItemList = Lists.newArrayList();
        List<Map<String, Object>> overTimeHolidayList = Lists.newArrayList();
        List<Map<String, Object>> overTimeResultList = Lists.newArrayList();
        for (Map<String, Object> scheduleMap :scheduleResult){
            List<Map<String,Object>> workOvertimeItems = getWorkOvertimeItems(scheduleMap,attendanceItems,false);
            if (workOvertimeItems.size() == 0 || ClassSegmentTypeEnum.WORK_TIME.getKey().equals(scheduleMap.get("beforeClassSegment"))){
                continue;
            }
            String ktjbzdcfwlb = Util.null2String(workOvertimeItems.get(0).get("ktjbzdcfwlb"));
            List<Map<String,Object>> scheduleMapList = Lists.newArrayList();
            scheduleMap.put("overTimeItem",workOvertimeItems);
            scheduleMapList.add(scheduleMap);


            params.put("workTimeBeLateItems",workOvertimeItems);
            params.put("scheduleMap",scheduleMap);
            //获得加班时长以及加班开始时间和结束时间
            Map<String,Object> overTimeDuraionMap = commandExecutor.execute(new GetOvertimeDurationCmd(params));
            String realityStartTime = Util.null2String(overTimeDuraionMap.get("realityStartTime"));
            String realityEndime = Util.null2String(overTimeDuraionMap.get("realityEndime"));
            //获得加班时长以及加班开始时间和结束时间
            params.putAll(overTimeDuraionMap);
            //获得加班项目
            Map<String,Object> fatherSaveWorkOverTimeMap = commandExecutor.execute(new SaveWorkOverTimeCmd(params));

            if (ktjbzdcfwlb.equals(CheckBoxEnum.CHECKED.getKey())){
                //加班跨天时自动拆分为两笔
                String cflbdsjd = Util.null2String(workOvertimeItems.get(0).get("cflbdsjd"));
                String kssj = Utils.getkssjTime(scheduleMap,analysisDate);
                String jssj = Utils.getjssjTime(scheduleMap,analysisDate);
                String splitTime = null;
                if (kssj.split(" ").equals(jssj.split(" "))){
                    String time = kssj.split(" ")[0] +" "+cflbdsjd;
                    if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(time))<=0 &&
                            DateUtil.getTime(jssj).compareTo(DateUtil.getTime(time)) >=0){
                        splitTime = time;
                    }
                }else {
                    String time = kssj.split(" ")[0] +" "+cflbdsjd;
                    if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(time))<=0 &&
                    DateUtil.getTime(jssj).compareTo(DateUtil.getTime(time)) >=0){
                        splitTime = time;
                    }
                    if (splitTime == null){
                        time = jssj.split(" ")[0] +" "+cflbdsjd;
                        if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(time))<=0 &&
                                DateUtil.getTime(jssj).compareTo(DateUtil.getTime(time)) >=0){
                            splitTime = time;
                        }
                    }
                }
                if (splitTime != null && !"".equals(realityStartTime) && !"".equals(realityEndime)){
                    scheduleMapList.clear();
                    //需要分割
                    Map<String,Object> beforeschedule = Maps.newHashMap();
                    beforeschedule.putAll(scheduleMap);
                    beforeschedule.put("dtjssj",splitTime.split(" ")[1]);
                    beforeschedule.put("jsdk",CheckBoxEnum.UNCHECKED.getKey());
                    double jbsc = DateUtil.getBetWeenMinutes(realityStartTime,splitTime);
                    beforeschedule.put("edxss",String.format ("%.2f", jbsc/60));
                    scheduleMapList.add(beforeschedule);
                    beforeschedule.put("rqlx", CommonUtil.getRqlx(userId,scheduleMap.get("dtkssj").toString().split(" ")[0]));
                    if (beforeschedule.get("gsrq").equals(ClassBelongToEnum.NOWDAY.getKey())){
                        beforeschedule.put("overTimeItem",getWorkOvertimeItems(beforeschedule,attendanceItems,false));
                    }else {
                        beforeschedule.put("overTimeItem",getWorkOvertimeItems(beforeschedule,attendanceItems,true));
                    }

                    Map<String,Object> afterschedule = Maps.newHashMap();
                    afterschedule.putAll(scheduleMap);
                    afterschedule.put("dtkssj",splitTime.split(" ")[1]);
                    jbsc = DateUtil.getBetWeenMinutes(splitTime,realityEndime);
                    afterschedule.put("edxss",String.format ("%.2f", jbsc/60));
                    afterschedule.put("ksdk",CheckBoxEnum.UNCHECKED.getKey());
                    if (DateUtil.getTime(splitTime.split(" ")[0]).compareTo(DateUtil.getTime(analysisDate)) == 0){
                        afterschedule.put("gsrq",ClassBelongToEnum.NOWDAY.getKey());
                    }else if (DateUtil.getTime(splitTime.split(" ")[0]).compareTo(DateUtil.getTime(analysisDate)) < 0){
                        afterschedule.put("gsrq",ClassBelongToEnum.YESTERDAY.getKey());
                    }else if (DateUtil.getTime(splitTime.split(" ")[0]).compareTo(DateUtil.getTime(analysisDate)) > 0){
                        afterschedule.put("gsrq",ClassBelongToEnum.NEXTDAY.getKey());
                    }
                    afterschedule.put("rqlx",CommonUtil.getRqlx(userId,splitTime.split(" ")[0]));
                    if (afterschedule.get("gsrq").equals(ClassBelongToEnum.NOWDAY.getKey())){
                        afterschedule.put("overTimeItem",getWorkOvertimeItems(afterschedule,attendanceItems,false));
                    }else {
                        afterschedule.put("overTimeItem",getWorkOvertimeItems(afterschedule,attendanceItems,true));
                    }
                    scheduleMapList.add(afterschedule);

                }
            }

            if (scheduleMapList.size() > 1){
                //加班需拆分
                //提前打卡开始的时长计入加班
                String tqdkjrjb = Util.null2String(workOvertimeItems.get(0).get("tqdkjrjb"));
                double jbsc = 0;
                if (CheckBoxEnum.CHECKED.getKey().equals(tqdkjrjb) && CheckBoxEnum.CHECKED.getKey().equals(scheduleMapList.get(0).get("ksdk"))) {
                    jbsc = DateUtil.getBetWeenMinutes(realityStartTime,scheduleMapList.get(0).get("dtjssj").toString());
                }else {
                    jbsc = DateUtil.getBetWeenMinutes(Utils.getkssjTime(scheduleMapList.get(0),analysisDate),Utils.getjssjTime(scheduleMapList.get(0),analysisDate));
                }

                if (fatherSaveWorkOverTimeMap.get("workOverTimeItems") != null){
                    Map<String,Object> workOverTimeItems = (Map<String,Object>)fatherSaveWorkOverTimeMap.get("workOverTimeItems");
                    workOverTimeItemList.add(workOverTimeItems);

                    double alljbsc = (double)workOverTimeItems.get("jbsc");
                    double afterjbsc = alljbsc-jbsc;
                    if (jbsc > alljbsc){
                        jbsc = alljbsc;
                    }
                    if (afterjbsc < 0){
                        afterjbsc = 0;
                    }

                    Map<String,Object> beforeParam = Maps.newHashMap();
                    beforeParam.putAll(params);
                    beforeParam.put("workTimeBeLateItems",scheduleMapList.get(0).get("overTimeItem"));
                    beforeParam.put("scheduleMap",scheduleMapList.get(0));
                    beforeParam.put("realityStartTime",realityStartTime);
                    beforeParam.put("realityEndime",Utils.getjssjTime(scheduleMapList.get(0),analysisDate));
                    beforeParam.put("beSplit",true);
                    beforeParam.put("jbsc",jbsc);

                    Map<String,Object> beforeSaveWorkOverTimeMap = commandExecutor.execute(new SaveWorkOverTimeCmd(beforeParam));
                    if (beforeSaveWorkOverTimeMap.get("overTimeHoliday") != null){
                        overTimeHolidayList.add((Map<String,Object>)beforeSaveWorkOverTimeMap.get("overTimeHoliday"));
                    }
                    if (beforeSaveWorkOverTimeMap.get("overTimeResult") != null){
                        overTimeResultList.add((Map<String,Object>)beforeSaveWorkOverTimeMap.get("overTimeResult"));
                    }

                    Map<String,Object> afterParam = Maps.newHashMap();
                    afterParam.putAll(params);
                    afterParam.put("workTimeBeLateItems",scheduleMapList.get(1).get("overTimeItem"));
                    afterParam.put("scheduleMap",scheduleMapList.get(1));
                    afterParam.put("jbsc",afterjbsc);
                    afterParam.put("beSplit",true);
                    afterParam.put("realityStartTime",Utils.getkssjTime(scheduleMapList.get(1),analysisDate));
                    afterParam.put("realityEndime",realityEndime);
                    Map<String,Object> afterSaveWorkOverTimeMap = commandExecutor.execute(new SaveWorkOverTimeCmd(afterParam));
                    if (afterSaveWorkOverTimeMap.get("overTimeHoliday") != null){
                        overTimeHolidayList.add((Map<String,Object>)afterSaveWorkOverTimeMap.get("overTimeHoliday"));
                    }
                    if (afterSaveWorkOverTimeMap.get("overTimeResult") != null){
                        overTimeResultList.add((Map<String,Object>)afterSaveWorkOverTimeMap.get("overTimeResult"));
                    }

                }


//                //拆分开加班重新计算单独计算
//                for (int i=0;i<scheduleMapList.size();i++){
//                    params.put("workTimeBeLateItems",scheduleMapList.get(i).get("overTimeItem"));
//                    params.put("scheduleMap",scheduleMapList.get(i));
//                    params.putAll(overTimeDuraionMap);
//
//                    //获得加班项目
//                    Map<String,Object> saveWorkOverTimeMap = commandExecutor.execute(new SaveWorkOverTimeCmd(params));
//
//                    if (saveWorkOverTimeMap.get("workOverTimeItems") != null){
//                        workOverTimeItemList.add((Map<String,Object>)saveWorkOverTimeMap.get("workOverTimeItems"));
//                    }
//                    if (saveWorkOverTimeMap.get("overTimeHoliday") != null){
//                        overTimeHolidayList.add((Map<String,Object>)saveWorkOverTimeMap.get("overTimeHoliday"));
//                    }
//                    if (saveWorkOverTimeMap.get("overTimeResult") != null){
//                        overTimeResultList.add((Map<String,Object>)saveWorkOverTimeMap.get("overTimeResult"));
//                    }
//                }

            }else {

                if (fatherSaveWorkOverTimeMap.get("workOverTimeItems") != null){
                    workOverTimeItemList.add((Map<String,Object>)fatherSaveWorkOverTimeMap.get("workOverTimeItems"));
                }
                if (fatherSaveWorkOverTimeMap.get("overTimeHoliday") != null){
                    overTimeHolidayList.add((Map<String,Object>)fatherSaveWorkOverTimeMap.get("overTimeHoliday"));
                }
                if (fatherSaveWorkOverTimeMap.get("overTimeResult") != null){
                    overTimeResultList.add((Map<String,Object>)fatherSaveWorkOverTimeMap.get("overTimeResult"));
                }
            }


        }

        /**
         * 休息班次，工作时段转加班计划项目结果集
         */
        List<Map<String,Object>> restOverTimeDuraion = Lists.newArrayList();
        double jbsc = 0;
        for (Map<String, Object> restOverTimeMap :restOverTimeList){
            List<Map<String,Object>> workTimeBeLateItems = getWorkOvertimeItems(restOverTimeMap,attendanceItems,false);
            if (workTimeBeLateItems.size() == 0){
                continue;
            }
            params.put("workTimeBeLateItems",workTimeBeLateItems);
            params.put("scheduleMap",restOverTimeMap);
            //获得加班时长以及加班开始时间和结束时间
            Map<String,Object> overTimeDuraionMap = commandExecutor.execute(new GetOvertimeDurationCmd(params));
            jbsc += Double.valueOf(overTimeDuraionMap.get("jbsc").toString());
            if (overTimeDuraionMap.get("realityStartTime") != null && overTimeDuraionMap.get("realityEndime") != null){
                restOverTimeDuraion.add(overTimeDuraionMap);
            }
        }
        if (restOverTimeDuraion.size() > 0){
            params.put("jbsc",jbsc);
            String realityStartTime = restOverTimeDuraion.stream().min(Comparator.comparing(e->DateUtil.getTime(e.get("realityStartTime").toString()).toInstant(ZoneOffset.of("+8")).toEpochMilli())).get().get("realityStartTime").toString();
            String realityEndime = restOverTimeDuraion.stream().max(Comparator.comparing(e->DateUtil.getTime(e.get("realityEndime").toString()).toInstant(ZoneOffset.of("+8")).toEpochMilli())).get().get("realityEndime").toString();
            params.put("realityStartTime",realityStartTime);
            params.put("realityEndime",realityEndime);
            Map<String,Object> saveWorkOverTimeMap = commandExecutor.execute(new SaveWorkOverTimeCmd(params));
            if (saveWorkOverTimeMap.get("workOverTimeItems") != null){
                workOverTimeItemList.add((Map<String,Object>)saveWorkOverTimeMap.get("workOverTimeItems"));
            }
            if (saveWorkOverTimeMap.get("overTimeHoliday") != null){
                overTimeHolidayList.add((Map<String,Object>)saveWorkOverTimeMap.get("overTimeHoliday"));
            }
            if (saveWorkOverTimeMap.get("overTimeResult") != null){
                overTimeResultList.add((Map<String,Object>)saveWorkOverTimeMap.get("overTimeResult"));
            }
        }

        resultMap.put("workOverTimeItemList",workOverTimeItemList);
        resultMap.put("overTimeHolidayList",overTimeHolidayList);
        resultMap.put("overTimeResultList",overTimeResultList);
        return resultMap;
    }

    public List<Map<String,Object>> getWorkOvertimeItems(Map<String, Object> scheduleMap,List<Map<String,Object>> attendanceItems,boolean findAgain){
        String bdlx = Util.null2String(scheduleMap.get("bdlx"));
        Map<String,Object> getWorkOverTimeParam = Maps.newHashMap();

        getWorkOverTimeParam.put("attendanceItems",attendanceItems);
        getWorkOverTimeParam.put("rqlx",scheduleMap.get("rqlx"));
        getWorkOverTimeParam.put("workfor",Utils.getWorkFor(bdlx));
        List<Map<String,Object>> workTimeBeLateItems = Lists.newArrayList();
        if (Utils.ifOverTimeClassSegment(bdlx)){
            if (ClassSegmentTypeEnum.OVERTIME_PLAN.getKey().equals(bdlx) && !findAgain){
                getWorkOverTimeParam.put("workfor",WorkForTimeEnum.PLAN_WORK_OVERTIME.getKey());
                workTimeBeLateItems = (List<Map<String,Object>>)scheduleMap.get("jblx");
            }else {
                Map<String,Object> result = commandExecutor.execute(new WorkOvertimeItemCmd(getWorkOverTimeParam));
                //加班项目
                workTimeBeLateItems = (List<Map<String,Object>>)result.get("attendanceItems");
            }
        }
        return workTimeBeLateItems;
    }

}
