package com.mortals.xhx.module.attendance.service.work;

import cn.hutool.core.date.DateUtil;
import com.mortals.framework.model.Context;
import com.mortals.framework.model.OrderCol;
import com.mortals.xhx.common.code.*;
import com.mortals.xhx.module.attendance.model.*;
import com.mortals.xhx.module.attendance.service.*;
import com.mortals.xhx.utils.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 固定班
 *
 * @author:
 * @date: 2023/7/31 15:15
 */
@Slf4j
public class FixWorkOtherAttendance extends AttendanceWorkAbstract {


    private AttendanceGroupFixedworkService attendanceGroupFixedworkService;

    private AttendanceClassService attendanceClassService;

    private AttendanceClassDetailService attendanceClassDetailService;

    private AttendanceGroupFixedworkSpecialService specialService;

    private AttendanceRecordService attendanceRecordService;

    private AttendanceRecordHikService recordHikService;

    private AttendanceRecordErrorService errorService;


    public FixWorkOtherAttendance(int type) {
        super(type);
        this.attendanceGroupFixedworkService = SpringUtils.getBean(AttendanceGroupFixedworkService.class);
        this.attendanceClassService = SpringUtils.getBean(AttendanceClassService.class);
        this.specialService = SpringUtils.getBean(AttendanceGroupFixedworkSpecialService.class);
        this.attendanceRecordService = SpringUtils.getBean(AttendanceRecordService.class);
        this.recordHikService = SpringUtils.getBean(AttendanceRecordHikService.class);
        this.attendanceClassDetailService = SpringUtils.getBean(AttendanceClassDetailService.class);
        this.errorService = SpringUtils.getBean(AttendanceRecordErrorService.class);
    }

    @Override
    int getType() {
        return TypeEnum.固定班制.getValue();
    }

    @Override
    void initData() {

    }

    @Override
    public void doHandleWork(CommonData commonData) {
        AttendanceGroupFixedworkEntity attendanceGroupFixedworkEntity = attendanceGroupFixedworkService.selectOne(new AttendanceGroupFixedworkQuery()
                .groupId(commonData.getAttendanceGroupEntity().getId()));
        if (ObjectUtils.isEmpty(attendanceGroupFixedworkEntity)) {
            log.info("attendanceGroupFixedworkEntity is null ! groupId:{}", commonData.getAttendanceGroupEntity().getId());
            return;
        }
        //判断当前考勤日期为周几
        String week = super.getWeek(DateUtil.parseDate(commonData.getDateStr()));
        //log.info("week:{}", week);
        //通过考勤日期的星期拿到班次id.

        //获取当前日期的详细班次
        Long weekClassId = this.getWeekClassId(attendanceGroupFixedworkEntity, week);
        //log.info("weekClassId:{}", weekClassId);
        //weekClassId为-1 则不在考勤
        if (weekClassId == -1L) {
            //跳过本次循环
            return;
        }


        //特殊日期考勤配置
        List<AttendanceGroupFixedworkSpecialEntity> specialEntities = specialService.find(new AttendanceGroupFixedworkSpecialQuery().fixedWorkId(attendanceGroupFixedworkEntity.getId()));
        if (!ObjectUtils.isEmpty(specialEntities)) {
            //分组 需要考勤与不需要考勤
            Map<Boolean, List<AttendanceGroupFixedworkSpecialEntity>> collect = specialEntities.stream().collect(Collectors.partitioningBy(item -> item.getMust() == MustEnum.是.getValue()));
            List<AttendanceGroupFixedworkSpecialEntity> mustList = collect.get(true);
            if (!ObjectUtils.isEmpty(mustList)) {
                //需要打卡
                for (AttendanceGroupFixedworkSpecialEntity specialEntity : mustList) {
                    //必须考勤时间，单位日
                    Date specialTime = specialEntity.getSpecialTime();
                    //判断当前考勤日期是否需要考勤，如果需要重叠 则更新为特殊日期考勤
                    //判断考勤日期与特殊日期是否一致
                    if (!ObjectUtils.isEmpty(specialTime) && DateUtil.formatDate(commonData.getAttendanceDate()).equals(DateUtil.formatDate(specialTime))) {
                        //更新打卡情况
                        if (!ObjectUtils.isEmpty(specialEntity.getClassId())) {
                            weekClassId = specialEntity.getClassId();
                        }
                    }
                }
            }
            List<AttendanceGroupFixedworkSpecialEntity> mustNotList = collect.get(false);
            if (!ObjectUtils.isEmpty(mustNotList)) {
                //不需要考勤 查看是时间段还是单独时间
                for (AttendanceGroupFixedworkSpecialEntity specialEntity : mustNotList) {
                    if (AddWayEnum.单个日期.getValue() == specialEntity.getAddWay()) {
                        Date specialTime = specialEntity.getSpecialTime();
                        if (!ObjectUtils.isEmpty(specialTime) && DateUtil.parseDate(commonData.getDateStr()).equals(DateUtil.formatDate(specialTime))) {
                            log.info("当天特殊日期，无需考勤！dateStr:{}", commonData.getDateStr());
                            return;
                        }
                    }

                    if (AddWayEnum.时间段.getValue() == specialEntity.getAddWay()) {
                        Date specialStartTime = specialEntity.getSpecialStartTime();
                        Date specialEndTime = specialEntity.getSpecialEndTime();
                        if (!ObjectUtils.isEmpty(specialStartTime) && !ObjectUtils.isEmpty(specialEndTime)) {
                            boolean in = DateUtil.isIn(DateUtil.parseDate(commonData.getDateStr()), specialStartTime, specialEndTime);
                            if (in) {
                                //直接返回 无班次信息
                                log.info("当天特殊日期，无需考勤！dateStr:{}", commonData.getDateStr());
                                return;
                            }
                        }
                    }
                }
            }
        }

        //获取班次信息
        AttendanceClassEntity attendanceClassEntity = attendanceClassService.get(weekClassId);
        if (ObjectUtils.isEmpty(attendanceClassEntity)) {
            log.info("attendanceClassEntity is null ,weekClassId:{}", weekClassId);
            return;
        }

        //查询当天，该人员的考勤记录
        AttendanceRecordHikQuery recordHikQuery = new AttendanceRecordHikQuery();
        recordHikQuery.setAttendanceDateStart(commonData.getDateStr());
        recordHikQuery.setAttendanceDateEnd(commonData.getDateStr());
        recordHikQuery.setStaffId(commonData.getStaffId());
        recordHikQuery.setOrderColList(Arrays.asList(new OrderCol("attendanceDate")));
        List<AttendanceRecordHikEntity> recordHikEntities = recordHikService.find(recordHikQuery);
        List<AttendanceClassDetailEntity> attendanceClassDetailEntities = attendanceClassEntity.getAttendanceClassDetailList();

        Integer orderNum = 0;
        for (AttendanceClassDetailEntity classDetailEntity : attendanceClassDetailEntities) {
            orderNum++;
            AttendanceRecordDetailEntity recordDetailEntity = new AttendanceRecordDetailEntity();
            recordDetailEntity.setShiftsId(classDetailEntity.getId());
            recordDetailEntity.setShiftsName(classDetailEntity.getClassName());
            recordDetailEntity.setGoWorkResult(GoWorkResultEnum.缺卡.getValue());
            recordDetailEntity.setOffWorkResult(GoWorkResultEnum.缺卡.getValue());
            recordDetailEntity.setOrderNum(orderNum);
            commonData.getDetailEntityList().add(recordDetailEntity);
        }

        if (!ObjectUtils.isEmpty(recordHikEntities)) {
            //针对当天的考勤记录进行计算与判断
            //获取当前班的多个班次，一个班次为一个上下班时间段
            for (AttendanceRecordHikEntity recordHikEntity : recordHikEntities) {
                Date attendanceDate = recordHikEntity.getAttendanceDate();
                //遍历班次详细记录
                for (AttendanceClassDetailEntity classDetail : attendanceClassDetailEntities) {
                    //计算区间范围
                    //上班打卡前时间
                    Date goWorkDateBefore = DateUtil.offsetMinute(classDetail.getGoWorkDate(), -classDetail.getGoWorkDateBefore());
                    //上班打卡后时间
                    Date goWorkDateAfter = DateUtil.offsetMinute(classDetail.getGoWorkDate(), classDetail.getGoWorkDateAfter());
                    // 下班打卡前时间
                    Date offWorkDateBefore = DateUtil.offsetMinute(classDetail.getOffWorkDate(), -classDetail.getOffWorkDateBefore());
                    //下班打卡后时间
                    Date offWorkDateAfter = DateUtil.offsetMinute(classDetail.getOffWorkDate(), classDetail.getOffWorkDateAfter());
                    //判断考勤时间是否在上班打卡区间内  true 在 false 不在  格式化时间
                    //String currDate = DateUtil.formatTime(attendanceDate);
                    Date curDateTime = DateUtil.parseTime(DateUtil.formatTime(attendanceDate));
                    boolean goInTime = DateUtil.isIn(curDateTime, goWorkDateBefore, goWorkDateAfter);
                    //判断考勤时间是否在下班打卡区间内
                    boolean offInTime = DateUtil.isIn(curDateTime, offWorkDateBefore, offWorkDateAfter);
                    if (goInTime == false && offInTime == false) {
                        log.info("考勤时间不在上班区间与下班区间中，不做处理！attendDate:{}", DateUtil.formatDateTime(commonData.getAttendanceDate()));
                        continue;
                    }
                    if (goInTime) {
                        //如果是上班打卡区间范围,判断是否迟到
                        boolean inTime = DateUtil.isIn(curDateTime, goWorkDateBefore, goWorkDateAfter);
                        if (inTime) {
                            for (AttendanceRecordDetailEntity attendanceRecordDetailEntity : commonData.getDetailEntityList()) {
                                if (attendanceRecordDetailEntity.getShiftsId() == classDetail.getId()) {
                                    attendanceRecordDetailEntity.setGoWorkResult(GoWorkResultEnum.正常.getValue());
                                    attendanceRecordDetailEntity.setGoWorkDate(recordHikEntity.getAttendanceDate());
                                }
                            }
                        } else {
                            for (AttendanceRecordDetailEntity attendanceRecordDetailEntity : commonData.getDetailEntityList()) {
                                if (attendanceRecordDetailEntity.getShiftsId() == classDetail.getId()) {
                                    attendanceRecordDetailEntity.setGoWorkResult(GoWorkResultEnum.迟到.getValue());
                                    attendanceRecordDetailEntity.setGoWorkDate(recordHikEntity.getAttendanceDate());
                                }
                            }
                        }
                    }
                    if (offInTime) {
                        boolean inTime = DateUtil.isIn(curDateTime, offWorkDateBefore, offWorkDateAfter);
                        if (inTime) {
                            for (AttendanceRecordDetailEntity attendanceRecordDetailEntity : commonData.getDetailEntityList()) {
                                if (attendanceRecordDetailEntity.getShiftsId() == classDetail.getId()) {
                                    attendanceRecordDetailEntity.setOffWorkResult(GoWorkResultEnum.正常.getValue());
                                    attendanceRecordDetailEntity.setOffWorkDate(recordHikEntity.getAttendanceDate());
                                }
                            }
                        } else {
                            for (AttendanceRecordDetailEntity attendanceRecordDetailEntity : commonData.getDetailEntityList()) {
                                if (attendanceRecordDetailEntity.getShiftsId() == classDetail.getId()) {
                                    attendanceRecordDetailEntity.setOffWorkResult(GoWorkResultEnum.早退.getValue());
                                    attendanceRecordDetailEntity.setOffWorkDate(recordHikEntity.getAttendanceDate());
                                }
                            }
                        }
                    }
                }
            }
        }
        if (!ObjectUtils.isEmpty(commonData.getDetailEntityList())) {
            AttendanceClassDetailEntity attendanceClassDetailEntity = attendanceClassDetailService.get(commonData.getDetailEntityList().get(0).getShiftsId());
            commonData.getAttendanceRecordEntity().setClassId(attendanceClassDetailEntity == null ? 0L : attendanceClassDetailEntity.getClassId());
            commonData.getAttendanceRecordEntity().setClassName(attendanceClassDetailEntity == null ? "" : attendanceClassDetailEntity.getClassName());
        }
        //生成异常记录
        genErrorAttendRecord(commonData.getContext(), commonData.getDateStr(), commonData.getAttendanceRecordEntity(), commonData.getDetailEntityList());

    }


    public void genErrorAttendRecord(Context context, String dateStr, AttendanceRecordEntity attendanceRecordEntity, List<AttendanceRecordDetailEntity> detailEntityList) {
        //处理异常打卡，所以异常打卡的 都新增一条记录
        List<AttendanceRecordErrorEntity> errorEntityList = new ArrayList<>();
        for (AttendanceRecordDetailEntity recordDetailEntity : detailEntityList) {
            Integer goWorkResult = recordDetailEntity.getGoWorkResult();
            Integer offWorkResult = recordDetailEntity.getOffWorkResult();
            //判断上班
            AttendanceClassDetailEntity attendanceClassDetailEntity = attendanceClassDetailService.get(recordDetailEntity.getShiftsId());
            if (ObjectUtils.isEmpty(attendanceClassDetailEntity)) continue;
            //判断上班
            if (GoWorkResultEnum.正常.getValue() != goWorkResult) {
                AttendanceRecordErrorEntity errorEntity = new AttendanceRecordErrorEntity();
                errorEntity.initAttrValue();
                BeanUtils.copyProperties(attendanceRecordEntity, errorEntity, new String[]{"id"});

                errorEntity.setShiftsId(recordDetailEntity.getShiftsId());
                errorEntity.setShiftsName(recordDetailEntity.getShiftsName());
                errorEntity.setProcessStatus(YesNoEnum.NO.getValue());
                errorEntity.setCreateTime(new Date());
                errorEntity.setCreateUserId(context.getUser().getId());
                Date goWorkDate = attendanceClassDetailEntity.getGoWorkDate();
                errorEntity.setGoOffDateTime(DateUtil.parseDateTime(dateStr + " " + DateUtil.formatTime(goWorkDate)).toJdkDate());
                if (!ObjectUtils.isEmpty(recordDetailEntity.getGoWorkDate())) {
                    errorEntity.setErrorDateTime(recordDetailEntity.getGoWorkDate());
                    errorEntity.setActualAttendanceDateTime(recordDetailEntity.getGoWorkDate());
                } else {
                    errorEntity.setErrorDateTime(DateUtil.parseDateTime(dateStr + " " + DateUtil.formatTime(goWorkDate)).toJdkDate());
                }
                if (GoWorkResultEnum.早退.getValue() == recordDetailEntity.getGoWorkResult()) {
                    errorEntity.setErrorStatus(ErrorStatusEnum.早退.getValue());
                }
                if (GoWorkResultEnum.迟到.getValue() == recordDetailEntity.getGoWorkResult()) {
                    errorEntity.setErrorStatus(ErrorStatusEnum.迟到.getValue());
                }
                if (GoWorkResultEnum.缺卡.getValue() == recordDetailEntity.getGoWorkResult()) {
                    errorEntity.setErrorStatus(ErrorStatusEnum.缺卡.getValue());
                }
                errorEntityList.add(errorEntity);
            }
            //判断下班
            if (OffWorkResultEnum.正常.getValue() != offWorkResult) {
                AttendanceRecordErrorEntity errorEntity = new AttendanceRecordErrorEntity();
                errorEntity.initAttrValue();
                BeanUtils.copyProperties(attendanceRecordEntity, errorEntity, new String[]{"id"});
                errorEntity.setShiftsId(recordDetailEntity.getShiftsId());
                errorEntity.setShiftsName(recordDetailEntity.getShiftsName());
                errorEntity.setProcessStatus(YesNoEnum.NO.getValue());
                errorEntity.setCreateTime(new Date());
                errorEntity.setCreateUserId(context.getUser().getId());
                Date offWorkDate = attendanceClassDetailEntity.getOffWorkDate();
                errorEntity.setGoOffDateTime(DateUtil.parseDateTime(dateStr + " " + DateUtil.formatTime(offWorkDate)).toJdkDate());
                if (!ObjectUtils.isEmpty(recordDetailEntity.getOffWorkDate())) {
                    errorEntity.setErrorDateTime(recordDetailEntity.getOffWorkDate());
                    errorEntity.setActualAttendanceDateTime(recordDetailEntity.getOffWorkDate());
                } else {
                    errorEntity.setErrorDateTime(DateUtil.parseDateTime(dateStr + " " + DateUtil.formatTime(offWorkDate)).toJdkDate());
                }
                if (OffWorkResultEnum.缺卡.getValue() == recordDetailEntity.getOffWorkResult()) {
                    errorEntity.setErrorStatus(ErrorStatusEnum.缺卡.getValue());
                }
                if (OffWorkResultEnum.早退.getValue() == recordDetailEntity.getOffWorkResult()) {
                    errorEntity.setErrorStatus(ErrorStatusEnum.早退.getValue());
                }
                if (OffWorkResultEnum.迟到.getValue() == recordDetailEntity.getOffWorkResult()) {
                    errorEntity.setErrorStatus(ErrorStatusEnum.迟到.getValue());
                }
                errorEntityList.add(errorEntity);
            }
        }

        if (!ObjectUtils.isEmpty(errorEntityList)) {
            for (AttendanceRecordErrorEntity errorEntity : errorEntityList) {
                //查看是否存在相同的异常记录，如果存在 则不添加
                AttendanceRecordErrorQuery errorQuery = new AttendanceRecordErrorQuery();
                errorQuery.setShiftsId(errorEntity.getShiftsId());
                errorQuery.setGoOffDateTime(errorEntity.getErrorDateTime());
                errorQuery.setStaffId(errorEntity.getStaffId());
                errorQuery.setProcessStatus(ProcessStatusEnum.未处理.getValue());

                AttendanceRecordErrorEntity attendanceRecordErrorEntity = errorService.selectOne(errorQuery, context);
                if (ObjectUtils.isEmpty(attendanceRecordErrorEntity)) {
                    errorService.save(errorEntity, context);
                } else {
                    errorEntity.setId(attendanceRecordErrorEntity.getId());
                    errorService.update(errorEntity,context);
                    log.info("已经存在相同的异常记录，更新保存！");
                }
            }
        }
    }
}
