package com.engine.attendance.attendanceanalysis.wrapper;

import com.engine.attendance.attendanceanalysis.dto.ClockPointDTO;
import com.engine.attendance.attendanceanalysis.service.ComprehensiveWorkingHourService;
import com.engine.attendance.attendanceanalysis.service.UtilService;
import com.engine.attendance.attendanceanalysis.service.impl.ComprehensiveWorkingHourServiceImpl;
import com.engine.attendance.attendanceanalysis.service.impl.UtilServiceImpl;
import com.engine.attendance.enums.AttendanceItemTypeEnum;
import com.engine.attendance.enums.CheckBoxEnum;
import com.engine.common.util.CommonUtil;
import com.engine.common.util.DateUtil;
import com.engine.common.util.ServiceUtil;
import com.engine.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 org.apache.struts.tiles.xmlDefinition.I18nFactorySet;
import weaver.general.Util;

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

/**
 * 考勤分析主题逻辑
 */
@Slf4j
public class AttendanceAnalysisWrapper extends Service {

    private UtilService utilService = ServiceUtil.getService(UtilServiceImpl.class);
    private UpdateAttendanceResultWrapper updateAttendanceResultWrapper = ServiceUtil.getService(UpdateAttendanceResultWrapper.class);
    private ComprehensiveWorkingHourService comprehensiveWorkingHourService = ServiceUtil.getService(ComprehensiveWorkingHourServiceImpl.class);

    /**
     * 考勤分析主逻辑入口
     * @param userId 人员id
     * @param dataList 打卡数据
     * @param attendanceItems 考勤项目
     */
    public void attendanceAnalysis(String userId, List<Map<String,Object>> dataList,List<Map<String,Object>> attendanceItems,List<Map<String,Object>> workHourItems,Map<String,Map<String,Object>> clockInTimeMap){
        log.info("***********analysis userId:{} start***********",userId);
        log.info("clockInTimeDate : [{}]",dataList);

        String beforeFourDayDate = DateUtil.getCurrentDateMinusDay(4);
        String beforeTwoDayDate = DateUtil.getCurrentDateMinusDay(2);
        String beforeOneDayDate = DateUtil.getCurrentDateMinusDay(1);
        String nowDate = DateUtil.getCurrentDate();
        /** 打卡数据 */
        Map<String, List<Map<String,Object>>> collect = Maps.newHashMap();
        if (dataList != null && dataList.size() >0){
            collect = dataList.stream().collect(Collectors.groupingBy(e -> Util.null2String(e.get("signdate"))));
        }
        /** 获取人员班次*/
        Map<String,Object> classesParamMap = Maps.newHashMap();
        classesParamMap.put("tableName","uf_pbjg");
        classesParamMap.put("startDate",beforeFourDayDate);
        classesParamMap.put("endDate",nowDate);
        classesParamMap.put("pblx","0");
        classesParamMap.put("pbdx",userId);
        classesParamMap.put("current","1");
        classesParamMap.put("pageSize",10);
        classesParamMap.put("recurrence",1);
        classesParamMap.put("clockInTimeMap",clockInTimeMap);
        classesParamMap.put("attendanceItems",attendanceItems);
        classesParamMap.put("clockInData",dataList);
        Map<String,Object> schedulMap = utilService.getSchedulingInFormation(classesParamMap);
        Map<String,List<Map<String,Object>>> schedulingResultsMap = (Map<String,List<Map<String,Object>>>)schedulMap.get("schedulingResultsMap");
        /**计算获取前一天和第二天打卡数据*/
        Map<String,Object> getClockTimeParam = Maps.newHashMap();
        getClockTimeParam.put("date",beforeOneDayDate);
        getClockTimeParam.put("clockInTimeList",dataList);
        getClockTimeParam.put("clockInTimeCollect",collect);
        getClockTimeParam.put("schedulingResultCollect",schedulingResultsMap);
        getClockTimeParam.put("clockInTimeMap",clockInTimeMap);
        getClockTimeParam.put("userId",userId);
        //前一天打卡数据
        log.info("getClockTimeParam : [{}]",getClockTimeParam);
        List<Map<String, Object>> beforeOneDayClockInTimeList = utilService.getClockInTime(getClockTimeParam);
        log.info("beforeOneDayClockInTimeList : [{}]",beforeOneDayClockInTimeList);
        //分析前一天考勤
        Map<String,Object> recordDataTime1 = analysis(userId,beforeOneDayDate,beforeOneDayClockInTimeList,schedulingResultsMap.get(beforeOneDayDate),attendanceItems,workHourItems);
        clockInTimeMap.put(beforeOneDayDate,recordDataTime1);
        getClockTimeParam.put("date",beforeTwoDayDate);
        //前第二天打卡数据
        List<Map<String, Object>> beforeTwoDayClockInTimeList = utilService.getClockInTime(getClockTimeParam);
        log.info("beforeTwoDayClockInTimeList : [{}]",beforeTwoDayClockInTimeList);
        //分析前第二天考勤
        Map<String,Object> recordDataTime2 = analysis(userId,beforeTwoDayDate,beforeTwoDayClockInTimeList,schedulingResultsMap.get(beforeTwoDayDate),attendanceItems,workHourItems);
        clockInTimeMap.put(beforeTwoDayDate,recordDataTime2);

    }

    /**
     * 考勤分析主逻辑入口
     * @param userId 人员id
     * @param analysisDate 分析日期
     * @param dataList 需要包含分析日期以及分析日期前后2天的3天打卡数据
     * @param attendanceItems 人员考勤项目
     */
    public void attendanceAnalysisForApi(String userId,String analysisDate, List<Map<String,Object>> dataList,List<Map<String,Object>> attendanceItems,Map<String,Object> schedulMap,List<Map<String,Object>> workHourItems,Map<String,Map<String,Object>> clockInTimeMap){
        log.info("***********analysis userId:{},analysisDate:{} start***********",userId,analysisDate);
        log.info("clockInTimeDate : [{}]",dataList);
        Map<String, List<Map<String,Object>>> collect = Maps.newHashMap();
        if (dataList != null && dataList.size() >0){
            collect = dataList.stream().collect(Collectors.groupingBy(e -> Util.null2String(e.get("signdate"))));
        }
        Map<String,List<Map<String,Object>>> schedulingResultsMap = (Map<String,List<Map<String,Object>>>)schedulMap.get("schedulingResultsMap");

        Map<String,Object> getClockTimeParam = Maps.newHashMap();
        getClockTimeParam.put("date",analysisDate);
        getClockTimeParam.put("clockInTimeList",dataList);
        getClockTimeParam.put("schedulingResultCollect",schedulingResultsMap);
        getClockTimeParam.put("clockInTimeMap",clockInTimeMap);
        getClockTimeParam.put("clockInTimeCollect",collect);
        getClockTimeParam.put("userId",userId);
        //打卡数据
        log.info("getClockTimeParam : [{}]",getClockTimeParam);
        List<Map<String, Object>> clockInTimeList = utilService.getClockInTime(getClockTimeParam);
        Map<String,Object> recordDataTime = analysis(userId,analysisDate,clockInTimeList,schedulingResultsMap.get(analysisDate),attendanceItems,workHourItems);
        clockInTimeMap.put(analysisDate,recordDataTime);
    }
    /**
     * 分析数据
     * @param userId 分析人员
     * @param analysisDate 分析日期
     * @param clockInTimeList 打卡数据
     * @param scheduleResult  班次
     * @param attendanceItems 考勤项目
     */
    public Map<String,Object> analysis(String userId,String analysisDate,List<Map<String, Object>> clockInTimeList,List<Map<String, Object>> scheduleResult,List<Map<String,Object>> attendanceItems,List<Map<String,Object>> workHourItems){
        Map<String,Object> recordParam = Maps.newHashMap();
        Map<String,String> formModeIdMap = Utils.getFormmodeIdMap();
        recordParam.put("userId",userId);
        recordParam.put("analysisDate",analysisDate);
        recordParam.put("classInfo",scheduleResult);
        recordParam.put("formmodeIdMap",formModeIdMap);
        recordParam.put("attendanceDuration",0);

        recordParam.put("modeId",formModeIdMap.get("uf_jcl_kq_cqjg"));

        Map<String,Object> workingHourparam = Maps.newHashMap();
        workingHourparam.put("clockInTimeCollect",clockInTimeList);
        workingHourparam.put("analysisDate",analysisDate);
        workingHourparam.put("userId",userId);
        workingHourparam.put("attendanceItems",attendanceItems);
        workingHourparam.put("scheduleResult",scheduleResult);

        /**
         * 津贴
         */
        Map<String,Object> allowanceMap = updateAttendanceResultWrapper.allowanceHandle(recordParam);

        if (workHourItems !=null && workHourItems.size() >0){
            workingHourparam.put("workHourItem",workHourItems.get(0));
            String ifPriority = Util.null2String(workHourItems.get(0).get("hlpbyxsyzhgs"));
            //核算工时的日期类型
            String hsgsdrqlx = Util.null2String(workHourItems.get(0).get("hsgsdrqlx"));
            String rqlx = Utils.getDateType(analysisDate,Util.null2String(workHourItems.get(0).get("qyrl")));

            if (CheckBoxEnum.CHECKED.getKey().equals(ifPriority) && CommonUtil.ifContainStr(hsgsdrqlx,rqlx,",")){
                comprehensiveWorkingHourService.excuteByWorkHour(workingHourparam);
                return null;
            }
        }

        if (scheduleResult == null || scheduleResult.size() ==0){
            //没有排班
            Map<String,Object> params = Maps.newHashMap();
            params.put("userId",userId);
            params.put("analysisDate",analysisDate);
            params.put("clockInTimeCollect",clockInTimeList);
            params.put("modeId",formModeIdMap.get("uf_jcl_kq_cqjg"));
            params.put("workHourItems",workHourItems);
            params.put("attendanceItems",attendanceItems);
            params.put("allowanceMap",allowanceMap);
            updateAttendanceResultWrapper.recordNoClass(params);
            return null;
        }
        recordParam.put("rqlx",scheduleResult.get(0).get("rqlx"));
        //休息班次,休息班打卡自动加班不算自动加班
        if (scheduleResult.get(0).get("sfxx") != null && CheckBoxEnum.CHECKED.getKey().equals(scheduleResult.get(0).get("sfxx")) &&
                scheduleResult.get(0).get("xxbdkzdjb") != null && CheckBoxEnum.UNCHECKED.getKey().equals(scheduleResult.get(0).get("xxbdkzdjb"))){
            updateAttendanceResultWrapper.recordRest(recordParam);
            return null;
        }



        List<Map<String,Object>> askForLeaveAndEvctionSchedule = Lists.newArrayList();
        //请假记录
        Map<String,Object> askForLeaveDataMap = updateAttendanceResultWrapper.getAskForLeave(workingHourparam);
        if (askForLeaveDataMap.get("alldayVaction") != null){
            //全天请假
            recordParam.put("cqzt",CheckBoxEnum.UNCHECKED.getKey());
            recordParam.put("recordData",askForLeaveDataMap.get("alldayVaction"));
            utilService.recordItem(recordParam);
            return null;
        }
        askForLeaveAndEvctionSchedule.addAll((List<Map<String,Object>>)askForLeaveDataMap.get("askForLeaveSchedule"));

        //出差记录
        Map<String,Object> evectionDataMap = updateAttendanceResultWrapper.getEvection(workingHourparam);
        if (evectionDataMap.get("alldayEvection") != null){
            //全天出差
            recordParam.put("cqzt",CheckBoxEnum.UNCHECKED.getKey());
            recordParam.put("recordData",evectionDataMap.get("alldayEvection"));
            utilService.recordItem(recordParam);
            return null;
        }
        askForLeaveAndEvctionSchedule.addAll((List<Map<String,Object>>)evectionDataMap.get("evectionSchedule"));


        if (askForLeaveAndEvctionSchedule.size() > 0){
            askForLeaveAndEvctionSchedule = mergeAskForLeaveAndEvctionSchedule(askForLeaveAndEvctionSchedule,analysisDate);
        }
        Map<String,Object> clcokInTimeDataParam = Maps.newHashMap();
        clcokInTimeDataParam.put("analysisDate",analysisDate);
        clcokInTimeDataParam.put("scheduleResult",scheduleResult);
        clcokInTimeDataParam.put("clockInTimeList",clockInTimeList);
        clcokInTimeDataParam.put("askForLeaveAndEvctionSchedule",askForLeaveAndEvctionSchedule);
        //打卡卡点以及匹配的打卡时间
        List<ClockPointDTO> clcokInTimeData = utilService.getClockInPointCmd(clcokInTimeDataParam);

        Map<String,Object> recordAbnormalParam = Maps.newHashMap();
        recordAbnormalParam.put("clcokInTimeData",clcokInTimeData);
        recordAbnormalParam.put("attendanceItems",attendanceItems);
        recordAbnormalParam.put("scheduleResult",scheduleResult);
        recordAbnormalParam.put("analysisDate",analysisDate);
        recordAbnormalParam.put("userId",userId);
        recordAbnormalParam.put("rqlx",scheduleResult.get(0).get("rqlx"));

        recordAbnormalParam.put("formmodeIdMap",formModeIdMap);

        log.info("recordAbnormalParam clcokInTimeList:{},attendanceItems size :{},scheduleResult :{},analysisDate:[{}],userId:[{}],rqlx:[{}],modeId:[{}]",clcokInTimeData,
                attendanceItems.size(),scheduleResult,analysisDate,userId,scheduleResult.get(0).get("rqlx"));


        /**
         * 计算是否考勤异常,是否有早退、迟到、漏卡的情况
         *
         **/

        recordAbnormalParam.put("askForLeaveList",askForLeaveDataMap.get("askForLeaveList"));
        recordAbnormalParam.put("askForLeaveItems",askForLeaveDataMap.get("askForLeaveItems"));
        recordAbnormalParam.put("evectionList",evectionDataMap.get("evectionList"));
        recordAbnormalParam.put("evectionItems",evectionDataMap.get("evectionItems"));

        List<Map<String,Object>> abnormalClockInList = updateAttendanceResultWrapper.recordAbnormalClockIn(recordAbnormalParam);
        //需要记录的异常卡点
        List<Map<String,Object>> needRecordAbnormalClockInList = abnormalClockInList.stream().filter(e-> (boolean)e.get("record")).collect(Collectors.toList());
        //不需要记录的异常卡点
        List<Map<String,Object>> notRecordAbnormalClockInList = abnormalClockInList.stream().filter(e-> !(boolean)e.get("record")).collect(Collectors.toList());
        /**
         * 出勤津贴
         */
        recordAbnormalParam.put("abnormalClockInList",needRecordAbnormalClockInList);
        recordAbnormalParam.put("notRecordAbnormalClockInList",notRecordAbnormalClockInList);
        String ifnotWork = Util.null2String(allowanceMap.get("ifnotWork"));
        if (!"".equals(ifnotWork)){
            //次日免班
            recordParam.put("recordData",Lists.newArrayList());
            recordParam.put("recordDataTime",Maps.newHashMap());
            recordParam.put("attendanceDuration",scheduleResult.get(0).get("edsc").toString());
            recordParam.put("cqzt",CheckBoxEnum.UNCHECKED.getKey());
            utilService.recordItem(recordParam);
            return null;
        }
        if (!"".equals(Util.null2String(allowanceMap.get("delayMinute")))){
            recordAbnormalParam.put("delayMinute",allowanceMap.get("delayMinute"));
            updateAttendanceResultWrapper.removeAbnormal(recordAbnormalParam);
        }

        /**
         * 请假
         */

        Map<String, Object> vactionMap = updateAttendanceResultWrapper.recordAskForLeave(recordAbnormalParam);
        List<Map<String,Object>> abnormalClockInListByAskForLeave = (List<Map<String,Object>>)vactionMap.get("abnormalClockInList");
        List<Map<String,Object>> vactionList = (List<Map<String,Object>>)vactionMap.get("resultList");
        recordAbnormalParam.put("offsetAskForLeaveAnomaly",vactionMap.get("offsetAskForLeaveAnomaly"));
        log.info("请假后消除的异常 : [{}]",vactionMap.get("offsetAskForLeaveAnomaly"));
        /**
         * 出差、外出
         */
        recordAbnormalParam.put("abnormalClockInList",abnormalClockInListByAskForLeave);

        Map<String, Object> recordEvection= updateAttendanceResultWrapper.recordEvection(recordAbnormalParam);
        List<Map<String,Object>> abnormalClockInListByEvction = (List<Map<String,Object>>)recordEvection.get("abnormalClockInList");
        List<Map<String,Object>> evectionResultList = (List<Map<String,Object>>)recordEvection.get("resultList");

        recordAbnormalParam.put("abnormalClockInList",abnormalClockInListByEvction);
        recordAbnormalParam.put("offsetEvectionAnomaly",recordEvection.get("offsetEvectionAnomaly"));
        log.info("出差外出后消除的异常 : [{}]",recordEvection.get("offsetEvectionAnomaly"));
        /**
         * 加班
         */
        List<Map<String,Object>> recordWorkOverTime= updateAttendanceResultWrapper.recordWorkOverTime(recordAbnormalParam);



        /**
         * 计算出勤时长
         */
        double attendanceDuration = utilService.computeAttendanceDuration(recordAbnormalParam);

        /**
         * 入库
         */
        List<Map<String,Object>> recordData = Lists.newArrayList();
        recordData.addAll(vactionList);
        recordData.addAll(evectionResultList);
        abnormalClockInListByEvction = abnormalClockInListByEvction.stream().filter(e-> (boolean)e.get("record")).collect(Collectors.toList());
        recordData.addAll(abnormalClockInListByEvction);
        recordData.addAll(recordWorkOverTime);
        recordParam.put("recordData",recordData);
        recordParam.put("recordDataTime",utilService.getNeedRecordClockInTime(clcokInTimeData));
        recordParam.put("attendanceDuration",attendanceDuration);
        log.info("recordParam : {}",recordParam);
        if (abnormalClockInListByEvction.size()>0){
            recordParam.put("cqzt",CheckBoxEnum.CHECKED.getKey());
        }else {
            recordParam.put("cqzt",CheckBoxEnum.UNCHECKED.getKey());
        }

        //休息班次,休息班打卡自动加班不算自动加班,且为正常
        if (scheduleResult.get(0).get("sfxx") != null && CheckBoxEnum.CHECKED.getKey().equals(scheduleResult.get(0).get("sfxx"))){
            recordParam.put("sfxx",CheckBoxEnum.CHECKED.getKey());
            recordParam.put("cqzt",CheckBoxEnum.UNCHECKED.getKey());
            recordParam.put("attendanceDuration",0);
        }
        utilService.recordItem(recordParam);
        return (Map<String,Object>)recordParam.get("recordDataTime");
    }


    /**
     * 合并请假或出差
     * @param askForLeaveAndEvctionSchedule
     * @param analysisDate
     * @return
     */
    public List<Map<String,Object>> mergeAskForLeaveAndEvctionSchedule(List<Map<String,Object>> askForLeaveAndEvctionSchedule,String analysisDate){

        askForLeaveAndEvctionSchedule = askForLeaveAndEvctionSchedule.stream().sorted(Comparator.comparing(e->DateUtil.getTime(Utils.getkssjTime(e,analysisDate)).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());

        for (int i=0;i<askForLeaveAndEvctionSchedule.size()-1;i++){
            String beforeDtkssj = askForLeaveAndEvctionSchedule.get(i).get("dtkssj").toString();
            String beforeDtjssj = askForLeaveAndEvctionSchedule.get(i).get("dtjssj").toString();

            for (int j=i+1;j<askForLeaveAndEvctionSchedule.size();j++){
                String dtkssj = askForLeaveAndEvctionSchedule.get(j).get("dtkssj").toString();
                String dtjssj = askForLeaveAndEvctionSchedule.get(j).get("dtjssj").toString();
                if (beforeDtjssj.equals(dtkssj)){
                    askForLeaveAndEvctionSchedule.get(i).put("dtjssj",dtjssj);
                    askForLeaveAndEvctionSchedule.get(i).put("jsdk",askForLeaveAndEvctionSchedule.get(j).get("jsdk"));
                    askForLeaveAndEvctionSchedule.get(i).put("thfghlfzs",askForLeaveAndEvctionSchedule.get(j).get("thfghlfzs"));
                    askForLeaveAndEvctionSchedule.remove(askForLeaveAndEvctionSchedule.get(j));
                    j--;
                    i--;
                }
            }
        }

        return askForLeaveAndEvctionSchedule;
    }
}
