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

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.PageUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.mortals.framework.common.Rest;
import com.mortals.framework.util.StringUtils;
import com.mortals.xhx.common.code.*;
import com.mortals.xhx.module.attendance.model.*;
import com.mortals.xhx.module.attendance.service.*;
import com.mortals.xhx.module.attendance.service.work.AttendanceWorkAbstract;
import com.mortals.xhx.module.attendance.service.work.CommonData;
import com.mortals.xhx.module.hik.door.model.req.door.DoorEventReq;
import com.mortals.xhx.module.hik.door.model.rsp.door.DoorEventDataInfo;
import com.mortals.xhx.module.hik.door.service.IHikDoorService;
import com.mortals.xhx.module.holiday.model.HolidayEntity;
import com.mortals.xhx.module.holiday.model.HolidayQuery;
import com.mortals.xhx.module.holiday.service.HolidayService;
import com.mortals.xhx.module.staff.model.StaffEntity;
import com.mortals.xhx.module.staff.model.StaffQuery;
import com.mortals.xhx.module.staff.service.StaffService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.mortals.framework.service.impl.AbstractCRUDServiceImpl;
import com.mortals.xhx.module.attendance.dao.AttendanceRecordHikDao;
import com.mortals.framework.model.Context;
import org.springframework.util.ObjectUtils;


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

/**
 * AttendanceRecordHikService
 * 海康考勤打卡记录汇总信息 service实现
 *
 * @author zxfei
 * @date 2023-04-08
 */
@Service("attendanceRecordHikService")
@Slf4j
public class AttendanceRecordHikServiceImpl extends AbstractCRUDServiceImpl<AttendanceRecordHikDao, AttendanceRecordHikEntity, Long> implements AttendanceRecordHikService {

    @Autowired
    private AttendanceRecordService attendanceRecordService;
    @Autowired
    private AttendanceRecordHikService attendanceRecordHikService;
    @Autowired
    private AttendanceGroupStaffService attendanceGroupStaffService;
    @Autowired
    private AttendanceGroupService attendanceGroupService;
    @Autowired
    private AttendanceClassDetailService attendanceClassDetailService;
    @Autowired
    private StaffService staffService;
    @Autowired
    private AttendanceRecordErrorService errorService;
    @Autowired
    private AttendanceGroupFixedworkService groupFixedworkService;
    @Autowired
    private HolidayService holidayService;
    @Autowired
    private IHikDoorService hikDoorService;
    @Autowired
    private AttendanceClassService attendanceClassService;
    @Autowired
    private AttendanceGroupFixedworkSpecialService specialService;

    @Override
    public void addAttendanceRecord(AttendanceRecordHikEntity hikEntity, Context context) throws Exception {
        List<AttendanceRecordHikEntity> hikEntityList = new ArrayList<>();
        addAttendanceOtherRecordList(hikEntityList, hikEntity, context);
    }

    @Override
    public void addAttendanceRecordByQuery(AttendanceRecordHikEntity attendanceRecordHikQuery, Context context) throws Exception {
        List<AttendanceRecordHikEntity> hikEntityList = attendanceRecordHikService.find(attendanceRecordHikQuery);
        addAttendanceOtherRecordList(hikEntityList, attendanceRecordHikQuery, context);
    }

    @Override
    public void addAttendanceRecordByQueryCustom(AttendanceRecordHikEntity attendanceRecordHikQuery, Context context) throws Exception {
        List<AttendanceRecordHikEntity> hikEntityList = attendanceRecordHikService.find(attendanceRecordHikQuery);
        hikEntityList = hikEntityList.stream().map(item -> {
            String dateStr = DateUtil.formatDate(item.getAttendanceDate());
            Boolean checkWorkByHoliday = checkWorkByHoliday(dateStr);
            Boolean checkHolidayByWorkDay = checkHolidayByWorkDay(dateStr);
            if (!checkWorkByHoliday) {
                return null;
            }
            if (checkHolidayByWorkDay) {
                return null;
            }
            return item;
        }).filter(f -> f != null).collect(Collectors.toList());
        addAttendanceOtherRecordList(hikEntityList, attendanceRecordHikQuery, context);
    }


    public void addAttendanceOtherRecordList(List<AttendanceRecordHikEntity> hikEntityList, AttendanceRecordHikEntity attendanceRecordHikQuery, Context context) throws Exception {
        List<AttendanceRecordHikEntity> collect = hikEntityList.stream().sorted(Comparator.comparing(AttendanceRecordHikEntity::getAttendanceDate)).collect(Collectors.toList());
        Map<Long, List<AttendanceRecordHikEntity>> listMap = collect.stream().collect(Collectors.groupingBy(AttendanceRecordHikEntity::getStaffId));
        Map<Long, List<AttendanceGroupStaffEntity>> groupStaffMap = attendanceGroupStaffService.find(new AttendanceGroupStaffQuery()).parallelStream().collect(Collectors.groupingBy(x -> x.getStaffId()));
        Map<Long, AttendanceGroupEntity> groupMap = attendanceGroupService.find(new AttendanceGroupQuery()).parallelStream().collect(Collectors.toMap(x -> x.getId(), y -> y, (o, n) -> n));
        Map<Long, AttendanceClassEntity> classEntityMap = attendanceClassService.find(new AttendanceClassQuery()).parallelStream().collect(Collectors.toMap(x -> x.getId(), y -> y, (o, n) -> n));
        Map<Long, AttendanceClassDetailEntity> classDetailEntityMap = attendanceClassDetailService.find(new AttendanceClassDetailQuery()).parallelStream().collect(Collectors.toMap(x -> x.getId(), y -> y, (o, n) -> n));
        Map<Long, List<AttendanceGroupFixedworkSpecialEntity>> fixedSpecialGroupMap = specialService.find(new AttendanceGroupFixedworkSpecialEntity()).parallelStream().collect(Collectors.groupingBy(x -> x.getFixedWorkId()));

        String attendanceDateStart = attendanceRecordHikQuery.getAttendanceDateStart();
        String attendanceDateEnd = attendanceRecordHikQuery.getAttendanceDateEnd();

        AttendanceRecordQuery query = new AttendanceRecordQuery();
        query.setAttendanceDateStart(attendanceDateStart);
        query.setAttendanceDateEnd(attendanceDateEnd);
        Map<Long, AttendanceRecordEntity> staffRecordMap = attendanceRecordService.find(query).parallelStream().collect(Collectors.toMap(x -> x.getStaffId(), y -> y, (o, n) -> n));
        //获取日期
        List<AttendanceRecordEntity> saveList = new ArrayList<>();
        List<AttendanceRecordEntity> updateList = new ArrayList<>();
        listMap.entrySet().stream().forEach(itemEntry -> {
            //   });
            //  for (Map.Entry<Long, List<AttendanceRecordHikEntity>> itemEntry : listMap.entrySet()) {
            //按人员  todo 改为多线程并行计算
            Long staffId = itemEntry.getKey();
            List<AttendanceRecordHikEntity> recordHikEntityList = itemEntry.getValue();
            Map<String, List<AttendanceRecordHikEntity>> dateRecordMap = recordHikEntityList.stream().collect(Collectors.groupingBy(hikEntity -> DateUtil.formatDate(hikEntity.getAttendanceDate())));
            for (Map.Entry<String, List<AttendanceRecordHikEntity>> dateEntry : dateRecordMap.entrySet()) {
                //按每日
                String dateStr = dateEntry.getKey();
                List<AttendanceRecordHikEntity> recordHikEntities = dateEntry.getValue();
                if (ObjectUtils.isEmpty(recordHikEntities)) continue;
                AttendanceRecordHikEntity item = recordHikEntities.get(0);
                AttendanceRecordEntity attendanceRecordEntity = new AttendanceRecordEntity();
                attendanceRecordEntity.initAttrValue();

                attendanceRecordEntity.setStaffId(item.getStaffId());
                attendanceRecordEntity.setStaffName(item.getStaffName());
                attendanceRecordEntity.setDeptId(item.getDeptId());
                attendanceRecordEntity.setDeptName(item.getDeptName());

                attendanceRecordEntity.setPositionId(item.getPositionId());
                attendanceRecordEntity.setPositionName(item.getPositionName());
                attendanceRecordEntity.setWorkNum(item.getWorkNum());
                attendanceRecordEntity.setAttendanceDate(item.getAttendanceDate());
                attendanceRecordEntity.setCreateTime(item.getAttendanceDate());
                attendanceRecordEntity.setCreateUserId(this.getContextUserId(context));

                StaffEntity staffEntity = staffService.getExtCache(staffId.toString());
                if (ObjectUtils.isEmpty(staffEntity)) {
                    //log.info("staffEntity is null ,staffId:{}", staffId);
                    continue;
                }

                attendanceRecordEntity.setSalaId(staffEntity.getSalaId());
                attendanceRecordEntity.setSalaName(staffEntity.getSalaName());
                //通过员工id查询考勤组人员信息
                List<AttendanceGroupStaffEntity> attendanceGroupStaffEntities = groupStaffMap.getOrDefault(staffId, new ArrayList<>(0));
                //过滤重复考勤组与人员
                attendanceGroupStaffEntities = attendanceGroupStaffEntities.stream().collect(Collectors.toMap(x -> x.getGroupId() + "#" + x.getStaffId(), y -> y, (o, n) -> n)).values().stream().collect(Collectors.toList());
                List<AttendanceRecordDetailEntity> detailEntityList = new ArrayList<>();
                if (!ObjectUtils.isEmpty(attendanceGroupStaffEntities) && attendanceGroupStaffEntities.size() == 1) {
                    //查询考勤组
                    AttendanceGroupEntity attendanceGroupEntity = groupMap.get(attendanceGroupStaffEntities.get(0).getGroupId());
                    attendanceRecordEntity.setAttendanceGroupId(attendanceGroupEntity == null ? 0L : attendanceGroupEntity.getId());
                    attendanceRecordEntity.setAttendanceGroupName(attendanceGroupEntity == null ? "" : attendanceGroupEntity.getGroupName());
                    //查询考勤组详细信息获取班次 todo 默认固定班次 还有自由 与排班制
                    AttendanceWorkAbstract workAbstract = AttendanceWorkAbstract.newType(attendanceGroupEntity.getType());
                    CommonData commonData = new CommonData();
                    commonData.setContext(context);
                    commonData.setAttendanceGroupEntity(attendanceGroupEntity);
                    commonData.setAttendanceRecordEntity(attendanceRecordEntity);
                    commonData.setAttendanceDate(attendanceRecordEntity.getAttendanceDate());
                    commonData.setDetailEntityList(detailEntityList);
                    commonData.setStaffId(attendanceRecordEntity.getStaffId());
                    commonData.setDateStr(dateStr);
                    commonData.setClassEntityMap(classEntityMap);
                    commonData.setRecordHikEntities(recordHikEntities);
                    commonData.setFixedSpecialGroupMap(fixedSpecialGroupMap);
                    commonData.setClassDetailEntityMap(classDetailEntityMap);
                    workAbstract.doHandleWork(commonData);
                }
                //如果考勤人员信息list长度大于1 则该考勤人员有多个考勤组.
                if (StringUtils.isNotNull(attendanceGroupStaffEntities) && attendanceGroupStaffEntities.size() > 1) {
                    for (AttendanceGroupStaffEntity groupStaffEntity : attendanceGroupStaffEntities) {
                        detailEntityList = new ArrayList<>();
                        //多考勤组 todo 暂时和单一覆盖
                       //查询考勤组
                       AttendanceGroupEntity attendanceGroupEntity = groupMap.get(groupStaffEntity.getGroupId());
                        attendanceRecordEntity.setAttendanceGroupId(attendanceGroupEntity == null ? 0L : attendanceGroupEntity.getId());
                        attendanceRecordEntity.setAttendanceGroupName(attendanceGroupEntity == null ? "" : attendanceGroupEntity.getGroupName());
                        //查询考勤组详细信息获取班次 todo 默认固定班次 还有自由 与排班制
                        AttendanceWorkAbstract workAbstract = AttendanceWorkAbstract.newType(attendanceGroupEntity.getType());
                        CommonData commonData = new CommonData();
                        commonData.setContext(context);
                        commonData.setAttendanceGroupEntity(attendanceGroupEntity);
                        commonData.setAttendanceRecordEntity(attendanceRecordEntity);
                        commonData.setDetailEntityList(detailEntityList);
                        commonData.setAttendanceDate(attendanceRecordEntity.getAttendanceDate());
                        commonData.setStaffId(attendanceRecordEntity.getStaffId());
                        commonData.setDateStr(dateStr);
                        commonData.setClassEntityMap(classEntityMap);
                        commonData.setRecordHikEntities(recordHikEntities);
                        commonData.setFixedSpecialGroupMap(fixedSpecialGroupMap);
                        commonData.setClassDetailEntityMap(classDetailEntityMap);
                        workAbstract.doHandleWork(commonData);
                    }
                }

                if (!ObjectUtils.isEmpty(detailEntityList)) {
                    attendanceRecordEntity.setAttendanceRecordDetailList(detailEntityList);
                    //判断签到 只要存在一次正常打卡详细记录 就判断签到
                    attendanceRecordEntity.setSignInResult(YesNoEnum.YES.getValue());
                    for (AttendanceRecordDetailEntity detailEntity : detailEntityList) {
                        if (GoWorkResultEnum.缺卡.getValue() == detailEntity.getGoWorkResult() || GoWorkResultEnum.迟到.getValue() == detailEntity.getOffWorkResult()) {
                            attendanceRecordEntity.setSignInResult(YesNoEnum.NO.getValue());
                            break;
                        }
                    }
                    attendanceRecordEntity.setSignOutResult(YesNoEnum.YES.getValue());
                    for (AttendanceRecordDetailEntity detailEntity : detailEntityList) {
                        if (OffWorkResultEnum.缺卡.getValue() == detailEntity.getOffWorkResult() || OffWorkResultEnum.早退.getValue() == detailEntity.getOffWorkResult()) {
                            attendanceRecordEntity.setSignOutResult(YesNoEnum.NO.getValue());
                            break;
                        }
                    }

                    if (YesNoEnum.YES.getValue() == attendanceRecordEntity.getSignInResult() && YesNoEnum.YES.getValue() == attendanceRecordEntity.getSignOutResult()) {
                        attendanceRecordEntity.setPunchResult(YesNoEnum.YES.getValue());
                    } else {
                        attendanceRecordEntity.setPunchResult(YesNoEnum.NO.getValue());
                    }

                    attendanceRecordEntity.setAttendType("现场打卡");
                    //判断是否存在记录 如果存在 则更新  维度   staffId  attendanceDate shiftsId attendanceGroupId
                    AttendanceRecordEntity recordEntity = staffRecordMap.get(attendanceRecordEntity.getStaffId());
                    if (!ObjectUtils.isEmpty(recordEntity)) {
                        attendanceRecordEntity.setId(recordEntity.getId());
                        attendanceRecordEntity.setUpdateTime(new Date());
                        attendanceRecordEntity.setUpdateUserId(this.getContextUserId(context));
                        updateList.add(attendanceRecordEntity);
                    } else {
                        saveList.add(attendanceRecordEntity);
                    }
                }
            }
        });
        // }
        if (!ObjectUtils.isEmpty(saveList)) {
            log.info("新增考勤记录数：" + saveList.size());
            attendanceRecordService.save(saveList);
        }

        if (!ObjectUtils.isEmpty(updateList)) {
            log.info("更新考勤记录数：" + updateList.size());
            attendanceRecordService.update(updateList);
        }
    }

    public void addAttendanceRecordList(List<AttendanceRecordHikEntity> hikEntityList, Context context) throws Exception {
        //对考勤数据根据考勤时间进行排序
        List<AttendanceRecordHikEntity> collect = hikEntityList.stream().sorted(Comparator.comparing(AttendanceRecordHikEntity::getAttendanceDate)).collect(Collectors.toList());
        //根据工号对考勤数据进行分组
        Map<String, List<AttendanceRecordHikEntity>> listMap = collect.stream().collect(Collectors.groupingBy(AttendanceRecordHikEntity::getWorkNum));
        for (Map.Entry<String, List<AttendanceRecordHikEntity>> itemEntry : listMap.entrySet()) {
            String workNum = itemEntry.getKey();
            List<AttendanceRecordHikEntity> recordHikEntityList = itemEntry.getValue();
            //对按照工号分组了的数据recordHikEntityList进行时间分组
            // DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            Map<String, List<AttendanceRecordHikEntity>> dateRecordMap = recordHikEntityList.stream().collect(Collectors.groupingBy(hikEntity -> DateUtil.formatDate(hikEntity.getAttendanceDate())));
            for (Map.Entry<String, List<AttendanceRecordHikEntity>> dateEntry : dateRecordMap.entrySet()) {
                String dateStr = dateEntry.getKey();
                List<AttendanceRecordHikEntity> attendanceRecordHikEntities = dateEntry.getValue();
                AttendanceRecordEntity attendanceRecordEntity = new AttendanceRecordEntity();
                attendanceRecordEntity.initAttrValue();
                //分日期 遍历考勤记录 考勤记录一天只生成一条 详细多条
                List<AttendanceRecordDetailEntity> detailEntityList = null;
                for (AttendanceRecordHikEntity item : attendanceRecordHikEntities) {
                    detailEntityList = new ArrayList<>();
                    //对主表的对象进行赋值
                    attendanceRecordEntity.setStaffId(item.getStaffId());
                    attendanceRecordEntity.setStaffName(item.getStaffName());
                    attendanceRecordEntity.setDeptId(item.getDeptId());
                    attendanceRecordEntity.setDeptName(item.getDeptName());
                    attendanceRecordEntity.setSalaId(item.getSalaId());
                    attendanceRecordEntity.setSalaName(item.getSalaName());
                    attendanceRecordEntity.setPositionId(item.getPositionId());
                    attendanceRecordEntity.setPositionName(item.getPositionName());
                    attendanceRecordEntity.setWorkNum(item.getWorkNum());
                    attendanceRecordEntity.setAttendanceDate(item.getAttendanceDate());
                    attendanceRecordEntity.setCreateTime(item.getAttendanceDate());
                    attendanceRecordEntity.setCreateUserId(this.getContextUserId(context));
                    //获取考勤打卡时间
                    Date attendanceDate = item.getAttendanceDate();
                    //通过工号查询员工信息
                    StaffEntity staffEntity = staffService.getExtCache(StrUtil.padPre(item.getWorkNum(), 8, "0"));
                    if (ObjectUtils.isEmpty(staffEntity)) {
                        log.info("staffEntity is null ,workNum:{}", StrUtil.padPre(item.getWorkNum(), 8, "0"));
                        continue;
                    }
                    //通过员工id查询考勤组人员信息
                    List<AttendanceGroupStaffEntity> attendanceGroupStaffEntities = attendanceGroupStaffService.find(new AttendanceGroupStaffQuery().staffId(staffEntity.getId()));
                    //查询该考勤人员,如果查出来的考勤人员信息list长度为1 则该考勤人员只有一个考勤组
                    if (!ObjectUtils.isEmpty(attendanceGroupStaffEntities) && attendanceGroupStaffEntities.size() == 1) {
                        //查询考勤组
                        AttendanceGroupEntity attendanceGroupEntity = attendanceGroupService.get(attendanceGroupStaffEntities.get(0).getGroupId(), context);
                        attendanceRecordEntity.setAttendanceGroupId(attendanceGroupEntity == null ? 0L : attendanceGroupEntity.getId());
                        attendanceRecordEntity.setAttendanceGroupName(attendanceGroupEntity == null ? "" : attendanceGroupEntity.getGroupName());
                        //查询考勤组详细信息获取班次 todo 默认固定班次 还有自由 与排班制
                        AttendanceWorkAbstract workAbstract = AttendanceWorkAbstract.newType(attendanceGroupEntity.getType());
                        CommonData commonData = new CommonData();
                        commonData.setAttendanceGroupEntity(attendanceGroupEntity);
                        commonData.setAttendanceDate(attendanceDate);
                        commonData.setDetailEntityList(detailEntityList);
                        commonData.setStaffId(attendanceRecordEntity.getStaffId());
                        workAbstract.doHandleWork(commonData);
                    }

                    //如果考勤人员信息list长度大于1 则该考勤人员有多个考勤组.
                    if (StringUtils.isNotNull(attendanceGroupStaffEntities) && attendanceGroupStaffEntities.size() > 1) {
                        for (AttendanceGroupStaffEntity groupStaffEntity : attendanceGroupStaffEntities) {
                            //多考勤组 todo 暂时和单一覆盖
                            //checkAttendGroupByOne(attendanceRecordEntity, detailEntityList, attendanceDate, groupStaffEntity, context);
                            //查询考勤组
                            AttendanceGroupEntity attendanceGroupEntity = attendanceGroupService.get(groupStaffEntity.getGroupId(), context);
                            attendanceRecordEntity.setAttendanceGroupId(attendanceGroupEntity == null ? 0L : attendanceGroupEntity.getId());
                            attendanceRecordEntity.setAttendanceGroupName(attendanceGroupEntity == null ? "" : attendanceGroupEntity.getGroupName());
                            //查询考勤组详细信息获取班次 todo 默认固定班次 还有自由 与排班制
                            AttendanceWorkAbstract workAbstract = AttendanceWorkAbstract.newType(attendanceGroupEntity.getType());
                            CommonData commonData = new CommonData();
                            commonData.setAttendanceGroupEntity(attendanceGroupEntity);
                            commonData.setAttendanceDate(attendanceDate);
                            commonData.setDetailEntityList(detailEntityList);
                            commonData.setStaffId(attendanceRecordEntity.getStaffId());
                            workAbstract.doHandleWork(commonData);

                        }
                    }
                }
                if (!ObjectUtils.isEmpty(detailEntityList)) {
                    AttendanceClassDetailEntity attendanceClassDetailEntity = attendanceClassDetailService.get(detailEntityList.get(0).getShiftsId(), context);
                    attendanceRecordEntity.setClassId(attendanceClassDetailEntity == null ? 0L : attendanceClassDetailEntity.getClassId());
                    attendanceRecordEntity.setClassName(attendanceClassDetailEntity == null ? "" : attendanceClassDetailEntity.getClassName());
                }
                //生成异常记录
                log.info("开始生成异常考勤记录");
                genErrorAttendRecord(context, dateStr, attendanceRecordEntity, detailEntityList);
                if (!ObjectUtils.isEmpty(detailEntityList)) {
                    attendanceRecordEntity.setAttendanceRecordDetailList(detailEntityList);
                    //判断签到 只要存在一次正常打卡详细记录 就判断签到
                    attendanceRecordEntity.setSignInResult(YesNoEnum.YES.getValue());
                    for (AttendanceRecordDetailEntity detailEntity : detailEntityList) {
                        if (GoWorkResultEnum.缺卡.getValue() == detailEntity.getGoWorkResult() || GoWorkResultEnum.迟到.getValue() == detailEntity.getOffWorkResult()) {
                            attendanceRecordEntity.setSignInResult(YesNoEnum.NO.getValue());
                            break;
                        }
                    }
                    attendanceRecordEntity.setSignOutResult(YesNoEnum.YES.getValue());
                    for (AttendanceRecordDetailEntity detailEntity : detailEntityList) {
                        if (OffWorkResultEnum.缺卡.getValue() == detailEntity.getOffWorkResult() || OffWorkResultEnum.早退.getValue() == detailEntity.getOffWorkResult()) {
                            attendanceRecordEntity.setSignOutResult(YesNoEnum.NO.getValue());
                            break;
                        }
                    }
                    if (YesNoEnum.YES.getValue() == attendanceRecordEntity.getSignInResult() && YesNoEnum.YES.getValue() == attendanceRecordEntity.getSignOutResult()) {
                        attendanceRecordEntity.setPunchResult(YesNoEnum.YES.getValue());
                    } else {
                        attendanceRecordEntity.setPunchResult(YesNoEnum.NO.getValue());
                    }

                    attendanceRecordEntity.setAttendType("现场打卡");
                    //判断是否存在记录 如果存在 则更新  维度   staffId  attendanceDate shiftsId attendanceGroupId
                    AttendanceRecordQuery query = new AttendanceRecordQuery();
                    query.setStaffId(attendanceRecordEntity.getStaffId());
                    query.setClassId(attendanceRecordEntity.getClassId());
                    query.setAttendanceGroupId(attendanceRecordEntity.getAttendanceGroupId());
                    query.setAttendanceDate(attendanceRecordEntity.getAttendanceDate());

                    AttendanceRecordEntity recordEntity = attendanceRecordService.selectOne(query);
                    if (!ObjectUtils.isEmpty(recordEntity)) {
                        attendanceRecordEntity.setId(recordEntity.getId());
                        attendanceRecordEntity.setUpdateTime(new Date());
                        attendanceRecordEntity.setUpdateUserId(this.getContextUserId(context));
                        attendanceRecordService.update(attendanceRecordEntity, context);
                    } else {
                        attendanceRecordService.save(attendanceRecordEntity, context);
                    }
                }
            }
        }
    }


    private 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;
            AttendanceRecordErrorEntity errorEntity = new AttendanceRecordErrorEntity();
            errorEntity.initAttrValue();
            BeanUtils.copyProperties(attendanceRecordEntity, errorEntity, new String[]{"id"});
            errorEntity.setGoOffDateTime(errorEntity.getErrorDateTime());
            errorEntity.setProcessStatus(YesNoEnum.NO.getValue());
            errorEntity.setCreateTime(new Date());
            errorEntity.setCreateUserId(this.getContextUserId(context));

            //判断上班
            if (GoWorkResultEnum.正常.getValue() != goWorkResult) {
                Date goWorkDate = attendanceClassDetailEntity.getGoWorkDate();
                errorEntity.setGoOffDateTime(goWorkDate);
                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) {
                Date offWorkDate = attendanceClassDetailEntity.getOffWorkDate();
                errorEntity.setGoOffDateTime(offWorkDate);
                if (!ObjectUtils.isEmpty(recordDetailEntity.getGoWorkDate())) {
                    errorEntity.setErrorDateTime(recordDetailEntity.getGoWorkDate());
                    errorEntity.setActualAttendanceDateTime(recordDetailEntity.getGoWorkDate());
                } 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)) {
            errorService.save(errorEntityList, context);
        }
    }

    public String getWeek(Date date) {
        // Get the day of the week (1 = Sunday, 2 = Monday, ..., 7 = Saturday)
        int dayOfWeek = DateUtil.dayOfWeek(date);
        // Map the numeric day of the week to its corresponding Chinese name
        String[] dayOfWeekNames = new String[]{
                "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"
        };
        // Get the Chinese name of the day of the week
        String dayOfWeekName = dayOfWeekNames[dayOfWeek - 1];
        return dayOfWeekName;
    }

    /**
     * 获取通过星期获取班次id  如果返参为-1 则不在考勤
     *
     * @return
     */
    public Long getWeekClassId(AttendanceGroupFixedworkEntity attendanceGroupFixedworkEntity, String week) {
        Long weekClassId = 0L;
        switch (week) {
            case "星期一":
                if (attendanceGroupFixedworkEntity.getMonday() == 0) {
                    weekClassId = -1L;
                    return weekClassId;
                }
                weekClassId = attendanceGroupFixedworkEntity.getMondayClassId();
                break;
            case "星期二":
                if (attendanceGroupFixedworkEntity.getTuesday() == 0) {
                    weekClassId = -1L;
                    return weekClassId;
                }
                weekClassId = attendanceGroupFixedworkEntity.getTuesdayClassId();
                break;
            case "星期三":
                if (attendanceGroupFixedworkEntity.getWednesday() == 0) {
                    weekClassId = -1L;
                    return weekClassId;
                }
                weekClassId = attendanceGroupFixedworkEntity.getWednesdayClassId();
                break;
            case "星期四":
                if (attendanceGroupFixedworkEntity.getThursday() == 0) {
                    weekClassId = -1L;
                    return weekClassId;
                }
                weekClassId = attendanceGroupFixedworkEntity.getThursdayClassId();
                break;
            case "星期五":
                if (attendanceGroupFixedworkEntity.getFriday() == 0) {
                    weekClassId = -1L;
                    return weekClassId;
                }
                weekClassId = attendanceGroupFixedworkEntity.getFridayClassId();
                break;
            case "星期六":
                if (attendanceGroupFixedworkEntity.getSaturday() == 0) {
                    weekClassId = -1L;
                    return weekClassId;
                }
                weekClassId = attendanceGroupFixedworkEntity.getSaturdayClassId();
                break;
            case "星期日":
                if (attendanceGroupFixedworkEntity.getSunday() == 0) {
                    weekClassId = -1L;
                    return weekClassId;
                }
                weekClassId = attendanceGroupFixedworkEntity.getSundayClassId();
                break;
        }
        return weekClassId;
    }

    /**
     * 计算考勤
     *
     * @param recordHikQuery
     * @param context
     */
    @Override
    public void buildCustomHikRecord(AttendanceRecordHikQuery recordHikQuery, Context context) {

        Set<Long> attendStaffSet = this.find(recordHikQuery).stream().map(i -> i.getStaffId()).collect(Collectors.toSet());
        Map<Long, List<AttendanceGroupStaffEntity>> groupStaffCollect = attendanceGroupStaffService.find(new AttendanceGroupStaffQuery()).stream().collect(Collectors.groupingBy(x -> x.getGroupId()));
        Iterator<Map.Entry<Long, List<AttendanceGroupStaffEntity>>> iterator = groupStaffCollect.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Long, List<AttendanceGroupStaffEntity>> item = iterator.next();
            //分组查看当前人
            Long groupId = item.getKey();
            AttendanceGroupFixedworkEntity attendanceGroupFixedworkEntity = groupFixedworkService.selectOne(new AttendanceGroupFixedworkQuery().groupId(groupId));
            String week = this.getWeek(DateUtil.parseDate(recordHikQuery.getAttendanceDateStart()));
            Long weekClassId = this.getWeekClassId(attendanceGroupFixedworkEntity, week);
            //weekClassId为-1 则不在考勤
            //对于节假日 分两种情况。
            // 1.当前是工作日，但是是节假日。则不做考勤continue;
            // 2.当前是非工作日，但是由于节假日情况，需要补班，需要做考勤
            //weekClassId == -1L 当日不需要考勤的 与节假日冲突的 以节假日为准
            Boolean checkWorkByHoliday = checkWorkByHoliday(recordHikQuery.getAttendanceDateStart());
            Boolean checkHolidayByWorkDay = checkHolidayByWorkDay(recordHikQuery.getAttendanceDateStart());
            if (weekClassId == -1L) {
                //跳过本次循环
                log.info("当前日期不在考勤时间范围内，不做处理！");
                if (!checkWorkByHoliday) {
                    continue;
                }
            } else {
                if (checkHolidayByWorkDay) {
                    //本来当天是需要考勤的，但是是节假日，则不计算考勤
                    continue;
                }
            }

            List<AttendanceGroupStaffEntity> groupStaffList = item.getValue();
            //查看当前需要考勤但是没有记录的人
            List<Long> unAttendStaffIdList = groupStaffList.stream().filter(f -> !attendStaffSet.contains(f.getStaffId())).map(i -> i.getStaffId()).collect(Collectors.toList());
            if (!ObjectUtils.isEmpty(unAttendStaffIdList)) {
                for (Long staffId : unAttendStaffIdList) {
                    StaffEntity staffCache = staffService.getCache(staffId.toString());
                    if (!ObjectUtils.isEmpty(staffCache) && StaffSatusEnum.离职.getValue() != staffCache.getStatus()) {
                        //构建考勤记录  判断当前人是否离职，如果非离职 构建记录
                        AttendanceRecordHikEntity recordHikEntity = new AttendanceRecordHikEntity();
                        recordHikEntity.initAttrValue();
                        recordHikEntity.setStaffId(staffCache.getId());
                        recordHikEntity.setStaffName(staffCache.getName());
                        recordHikEntity.setWorkNum(staffCache.getWorkNum());
                        recordHikEntity.setDeptId(staffCache.getDeptId());
                        recordHikEntity.setDeptName(staffCache.getDeptName());
                        recordHikEntity.setSalaId(staffCache.getSalaId());
                        recordHikEntity.setSalaName(staffCache.getSalaName());
                        recordHikEntity.setPositionId(staffCache.getPositionId());
                        recordHikEntity.setPositionName(staffCache.getPositionName());
                        recordHikEntity.setAttendanceGroupId(groupId);
                        recordHikEntity.setAttendanceDate(DateUtil.parseDate(recordHikQuery.getAttendanceDateStart()).toJdkDate());
                        recordHikEntity.setAttendanceAddress("自定义地点");
                        recordHikEntity.setEventSource("当日未有记录虚增考勤记录！");
                        recordHikEntity.setCreateTime((DateUtil.parseDate(recordHikQuery.getAttendanceDateStart()).toJdkDate()));
                        recordHikEntity.setCreateUserId(1L);
                        try {
                            //查询当天是否有考勤记录，没有的才添加虚增考勤记录
                            AttendanceRecordHikEntity condition = new AttendanceRecordHikEntity();
                            condition.setStaffId(staffCache.getId());
                            condition.setAttendanceDateStart(recordHikQuery.getAttendanceDateStart());
                            condition.setAttendanceDateEnd(recordHikQuery.getAttendanceDateEnd());
                            AttendanceRecordHikEntity hikEntity = this.selectOne(condition);
                            if (ObjectUtils.isEmpty(hikEntity)) {
                                this.getDao().insert(recordHikEntity);
                            } else {
                                log.info("当天已有考勤记录，无需添加！");
                            }

                        } catch (Exception e) {
                            log.error(e.getMessage());
                        }
                    } else {
                        log.error("未找到当前员工，staffId:{}", staffId);
                    }
                }
            }
        }
    }

    @Override
    public void buildAllCustomHikRecord(AttendanceRecordHikQuery recordHikQuery, Context context) {
        //虚增所有考勤组用户的考勤记录
        List<StaffEntity> staffList = staffService.find(new StaffQuery());
        for (StaffEntity staffCache : staffList) {
            if (!ObjectUtils.isEmpty(staffCache) && StaffSatusEnum.离职.getValue() != staffCache.getStatus()) {
                //构建考勤记录  判断当前人是否离职，如果非离职 构建记录
                AttendanceRecordHikEntity recordHikEntity = new AttendanceRecordHikEntity();
                recordHikEntity.initAttrValue();
                recordHikEntity.setStaffId(staffCache.getId());
                recordHikEntity.setStaffName(staffCache.getName());
                recordHikEntity.setWorkNum(staffCache.getWorkNum());
                recordHikEntity.setDeptId(staffCache.getDeptId());
                recordHikEntity.setDeptName(staffCache.getDeptName());
                recordHikEntity.setSalaId(staffCache.getSalaId());
                recordHikEntity.setSalaName(staffCache.getSalaName());
                recordHikEntity.setPositionId(staffCache.getPositionId());
                recordHikEntity.setPositionName(staffCache.getPositionName());
                recordHikEntity.setAttendanceDate(DateUtil.parseDate(recordHikQuery.getAttendanceDateStart()).toJdkDate());
                recordHikEntity.setAttendanceAddress("自定义地点");
                recordHikEntity.setEventSource("当日未有记录虚增考勤记录！");
                recordHikEntity.setCreateTime((DateUtil.parseDate(recordHikQuery.getAttendanceDateStart()).toJdkDate()));
                recordHikEntity.setCreateUserId(1L);
                this.getDao().insert(recordHikEntity);
            }
        }
    }

    @Override
    public Rest<Integer> buildSourceHikRecord(AttendanceRecordHikQuery recordHikQuery, Context context) {
        deletFakeRecord(recordHikQuery, context);
        return Rest.ok();
    }

    @Override
    public void deletFakeRecord(AttendanceRecordHikQuery recordHikQuery, Context context) {
        //重新拉去的考勤记录，判断是否存在虚增的记录
        log.info("开始删除虚增的记录！");
        return;
        //只删除多条重复的记录
      /*  recordHikQuery.setEventSource("当日未有记录虚增考勤记录！");
        List<AttendanceRecordHikEntity> fackAttendlist = this.find(recordHikQuery);
        if (!ObjectUtils.isEmpty(fackAttendlist)) {
            log.info("虚增的记录：{}", fackAttendlist.size());
            for (AttendanceRecordHikEntity recordHikEntity : fackAttendlist) {
                //判断是否已经重新有新的当日数据，如果有 则删除当前虚增记录
                AttendanceRecordHikQuery query = new AttendanceRecordHikQuery();
                query.setStaffId(recordHikEntity.getStaffId());
                query.setAttendanceDateStart(recordHikEntity.getAttendanceDateStart());
                query.setAttendanceDateEnd(recordHikQuery.getAttendanceDateEnd());
                query.setIdNotList(Arrays.asList(recordHikEntity.getId()));
                int count = this.count(query, context);
                if (count > 0) {
                    //删除当前虚增的记录
                    log.info("删除虚增的记录：{}", recordHikEntity.getId());
                    this.remove(recordHikEntity.getId(), context);
                }
            }
        }*/
    }

    public void syncDoorEvents(AttendanceRecordHikQuery recordHikQuery) {
        DoorEventReq doorEventReq = new DoorEventReq();
        List<Integer> eventTypes = new ArrayList<>();
        eventTypes.add(196885);
        eventTypes.add(196887);
        eventTypes.add(196893);
        eventTypes.add(196888);
        eventTypes.add(196889);
        eventTypes.add(196890);
        eventTypes.add(196891);
        //   eventTypes.add(196893);//人脸认证通过
        doorEventReq.setEventTypes(eventTypes);
        // 获取当天的开始时间
        //Date todayStart = DateUtil.offsetHour(new Date(), -5).toJdkDate();
        Date todayStart = DateUtil.beginOfDay(DateUtil.parseDate(recordHikQuery.getAttendanceDateStart()));
        // 获取当天的结束时间
        Date todayEnd = DateUtil.endOfDay(DateUtil.parseDate(recordHikQuery.getAttendanceDateEnd()));
        doorEventReq.setStartTime(todayStart);
        doorEventReq.setEndTime(todayEnd);
        doorEventReq.setPageNo(1);
        doorEventReq.setPageSize(1);

        Rest<DoorEventDataInfo> doorEventsRest = hikDoorService.getDoorEvents(doorEventReq);
        log.info("doorEventsRest:{} msg:{}", doorEventsRest.getCode(), doorEventsRest.getMsg());
        if (doorEventsRest.getCode() == YesNoEnum.YES.getValue()) {
            //分页获取考勤数据
            Integer total = doorEventsRest.getData().getTotal();
            int pageCount = PageUtil.totalPage(total, 1000);
            for (int i = 1; i <= pageCount; i++) {
                doorEventReq.setPageNo(i);
                doorEventReq.setPageSize(1000);
                try {
                    doorEventsRest = hikDoorService.getDoorEvents(doorEventReq);
                    log.info("doorEventsRest:{} msg:{},page:{}", doorEventsRest.getCode(), doorEventsRest.getMsg(), doorEventReq.getPageNo());
                    getDoorEvents(doorEventsRest, doorEventReq);
                } catch (Exception e) {
                    log.error("分页获取考勤数据异常:{}", e.getMessage());
                }

            }
        }
    }

    private void getDoorEvents(Rest<DoorEventDataInfo> doorEventsRest, DoorEventReq doorEventReq) {
        //同步当前考勤数据
        List<AttendanceRecordHikEntity> attRecords = doorEventsRest.getData().getList().stream().map(item -> {
            AttendanceRecordHikEntity recordHikEntity = new AttendanceRecordHikEntity();
            recordHikEntity.initAttrValue();

            if (ObjectUtils.isEmpty(item.getJobNo())) {
                log.info("jobNo is null ==>{}", JSON.toJSONString(item));
                return null;
            }
            StaffEntity staffCache = staffService.getExtCache(StrUtil.padPre(item.getJobNo(), 8, "0"));
            if (ObjectUtils.isEmpty(staffCache)) {
                log.info("staff is null !staffCode:{}", item.getJobNo());
                return null;
            }

            recordHikEntity.setStaffId(staffCache.getId());
            recordHikEntity.setStaffName(staffCache.getName());
            recordHikEntity.setWorkNum(staffCache.getWorkNum());
            recordHikEntity.setDeptId(staffCache.getDeptId());
            recordHikEntity.setDeptName(staffCache.getDeptName());
            recordHikEntity.setSalaId(staffCache.getSalaId());
            recordHikEntity.setSalaName(staffCache.getSalaName());
            recordHikEntity.setPositionId(staffCache.getPositionId());
            recordHikEntity.setPositionName(staffCache.getPositionName());
            recordHikEntity.setAttendanceDate(item.getEventTime());
            recordHikEntity.setAttendanceAddress(item.getDoorName());
            recordHikEntity.setEventSource("门禁点");
            recordHikEntity.setRemark(item.getEventId());
            recordHikEntity.setCreateTime(new Date());
            recordHikEntity.setCreateUserName("系统管理员");
            recordHikEntity.setCreateUserId(1L);
            return recordHikEntity;
        }).filter(f -> f != null).collect(Collectors.toList());
        log.info("receive recordHikRecords size:{}", attRecords.size());
        List<String> eventIds = attRecords.parallelStream().filter(f -> !ObjectUtils.isEmpty(f) && !ObjectUtils.isEmpty(f.getRemark())).map(i -> i.getRemark()).collect(Collectors.toList());

        //查询当天考勤记录是否有重复的 有的 则不添加
        AttendanceRecordHikQuery recordHikQuery = new AttendanceRecordHikQuery();
        recordHikQuery.setAttendanceDateStart(DateUtil.format(doorEventReq.getStartTime(), "yyyy-MM-dd"));
        recordHikQuery.setAttendanceDateEnd(DateUtil.format(doorEventReq.getEndTime(), "yyyy-MM-dd"));
        recordHikQuery.setRemarkList(eventIds);
        Set<String> eventIdSet = this.find(recordHikQuery).parallelStream().map(i -> i.getRemark()).collect(Collectors.toSet());

        //去重 时分秒打卡的 也要去掉重复。
        List<AttendanceRecordHikEntity> saveRecordList = attRecords.stream().filter(f -> !eventIdSet.contains(f.getRemark())).collect(Collectors.toList());
        if (!ObjectUtils.isEmpty(saveRecordList)) {
            //单个插入 去掉重复时间段的打卡记录
            for (AttendanceRecordHikEntity recordHikEntity : saveRecordList) {
                try {
                    this.getDao().insert(recordHikEntity);
                } catch (Exception e) {
                    //log.error("基础考勤数据保存异常", e.getMessage());
                }
            }
        }
        log.info("saveRecordList size:{}", saveRecordList.size());

    }

    private Boolean checkWorkByHoliday(String dateStr) {
        Boolean bool = false;
        HolidayQuery holidayQuery = new HolidayQuery();
        holidayQuery.setStartTimeStart(dateStr);
        holidayQuery.setStartTimeEnd(dateStr);
        HolidayEntity holidayEntity = holidayService.selectOne(holidayQuery);
        if (!ObjectUtils.isEmpty(holidayEntity)) {
            Integer workorholiday = holidayEntity.getWorkorholiday();
            if (workorholiday == YesNoEnum.YES.getValue()) {
                bool = true;
            }
        }

        return bool;
    }

    private Boolean checkHolidayByWorkDay(String dateStr) {
        Boolean bool = false;
        HolidayQuery holidayQuery = new HolidayQuery();
        holidayQuery.setStartTimeStart(dateStr);
        holidayQuery.setStartTimeEnd(dateStr);
        HolidayEntity holidayEntity = holidayService.selectOne(holidayQuery);
        if (!ObjectUtils.isEmpty(holidayEntity)) {
            Integer workorholiday = holidayEntity.getWorkorholiday();
            if (workorholiday == YesNoEnum.NO.getValue()) {
                bool = true;
            }
        }

        return bool;
    }
}
