package com.bonus.system.att.service;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSONObject;
import com.bonus.common.core.utils.DateTimeHelper;
import com.bonus.common.core.utils.DateUtils;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.system.api.domain.MapVo;
import com.bonus.system.api.domain.SysUser;
import com.bonus.system.att.dao.AttGroupDao;
import com.bonus.system.att.dao.AttSourceDataDao;
import com.bonus.system.att.dao.OrgChangeDao;
import com.bonus.system.att.entity.*;
import com.bonus.system.att.utils.AddressCoordinateFormatUtil;
import com.bonus.system.att.utils.AttTimeUtil;
import com.bonus.system.att.utils.WorkdayCalculator;
import com.bonus.system.dept.dao.ProDeptRoleDao;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 组织架构-业务层
 *
 * @author zys
 */
@Slf4j
@Service("AttCalService")
public class AttCalServiceImpl implements AttCalService {

    @Resource(name = "attSourceDataDao")
    private AttSourceDataDao attSourceDataDao;

    @Resource(name = "attGroupDao")
    private AttGroupDao attGroupDao;

    @Resource(name = "sqlSessionTemplate")
    private SqlSessionTemplate sqlSessionTemplate;

    /**
     * 待考勤人员列表
     * 在模版数据之前生成
     *
     * @param pushDate 时间(可为空，为空则推历史60天内没生成的数据，不为空则推指定日期)
     */
    @Override
    public void insertAttDateHistory(String pushDate) {
        List<String> dateList = new ArrayList<>();
        if (StringUtils.isEmpty(pushDate)) {
            String startDate = DateUtil.today();
            // 解析 startDate 字符串到 LocalDate 对象
            LocalDate date = LocalDate.parse(startDate, DateTimeFormatter.ISO_LOCAL_DATE);
            // 向前推n天
            int n = 60;
            LocalDate newDate = date.minusDays(n);
            // 如果需要将结果格式化为特定格式的字符串，可以使用以下代码
            String formattedNewDate = newDate.format(DateTimeFormatter.ISO_LOCAL_DATE);
            //向前推1个月的时间检索，缺少哪一天推送哪一天
            List<String> dateListOne = attSourceDataDao.getAttSettingDate(startDate, n);
            dateList = AttTimeUtil.getStrDateListBetween(formattedNewDate, startDate);
            // 从 dateList 中移除所有在 dateListOne 中存在的元素
            dateListOne.removeIf(startDate::contains);
            dateList.removeIf(dateListOne::contains);
        } else {
            dateList.add(pushDate);
        }
        for (String currentDay : dateList) {
            List<AttGroupBean> attList = attSourceDataDao.getAttSettingHistoryDate(currentDay);
            if (!attList.isEmpty()) {
                attSourceDataDao.insertAttSettingHistoryData(attList);
            }
        }
    }

    /**
     * 考勤数据应用（步骤一：考勤数据更新）
     * 建议一小时一次
     *
     * @param pushDate 时间
     * @param pushType 1:自动推送（当天） 2:手动（历史）
     */
    @Override
    public void updateAttData(String pushDate, int pushType) {
        //查出人员考勤记录
        AtomicReference<List<AttSourceDataBean>> sourceDataList = new AtomicReference<>(attSourceDataDao.getSourceAttData(pushDate, pushType));
        //查出考勤组
        List<AttGroupBean> groupList = getGroupData(pushDate);
        //
        groupList.forEach(c -> {
            List<AttSourceDataBean> list = Collections.emptyList();
            //考勤规则里面的attType 1 固定打卡  2 自由打卡
            if ("1".equals(c.getAttType())) {
                list = groupFixedData(sourceDataList.get().stream()
                        .filter(a -> "1".equals(a.getGroupType()) &&
                                a.getGroupId() == c.getGroupId())
                        .collect(Collectors.toList()), c);
            } else if ("2".equals(c.getAttType())) {
                list = groupFreeData(sourceDataList.get().stream()
                        .filter(a -> "2".equals(a.getGroupType()) &&
                                a.getGroupId() == c.getGroupId())
                        .collect(Collectors.toList()), c);
            }
            //修改考勤记录 att_data
            if (!list.isEmpty()) {
                if ("1".equals(c.getAttType())) {
                    //固定打卡
                    // 定义时间格式
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    // 移除移除 attType 为 2 且 attCurrentTime 在上午 5 点到 12 点之间的元素
                    list.removeIf(record -> {
                        String attType = record.getAttType();
                        String attCurrentTime = record.getAttCurrentTime();
                        if (!"".equals(attCurrentTime)) {
                            if (attCurrentTime.contains("  ")) {
                                attCurrentTime = attCurrentTime.split("  ")[0];
                            }
                            LocalDateTime time = LocalDateTime.parse(attCurrentTime, formatter);
                            // 提取时间部分
                            LocalTime localTime = time.toLocalTime();
                            boolean condition1 = "2".equals(attType) && localTime.isAfter(LocalTime.of(5, 0)) && localTime.isBefore(LocalTime.of(12, 0));
                            boolean condition2 = "1".equals(attType) && localTime.isAfter(LocalTime.of(12, 0)) && localTime.isBefore(LocalTime.of(23, 59));
                            return condition1 || condition2;
                        } else {
                            return false;
                        }
                    });
                    // 插入剩余的元素
                    attSourceDataDao.updateAttStatusData(list);
                } else if ("2".equals(c.getAttType())) {
                    //自由打卡
                    attSourceDataDao.updateAttStatusData(list);
                }
            }
        });

    }

    /**
     * 考勤数据应用（步骤二：旷工状态更新）
     * 每天12点将当天未打卡考勤人员上班置为旷工
     * 每天晚上22点，将下班未打卡置为旷工
     * @param pushDate 时间
     * @param pushType 1:自动推送（当天） 2:手动（历史）
     */
    @Override
    public void updateAbsenteeismData(String pushDate, int pushType) {
        List<AttDataBean> list = new ArrayList<>();
        List<AttDataBean> listUpdate = new ArrayList<>();
        if(pushType == 1){
            //判断是否大于12点大于则更新所有attType = 1的未打卡状态为旷工
            //判断是否大于22点大于则更新所有未打卡状态为旷工
            boolean pm = AttTimeUtil.timeCheck(21, 59);
            if(pm){
                list = attSourceDataDao.getAttDataByStatus(pushDate,"");
                listUpdate = attSourceDataDao.getAttDataUpdateByStatus(pushDate,"");
            }else{
                boolean am = AttTimeUtil.timeCheck(11, 59);
                if(am){
                    list = attSourceDataDao.getAttDataByStatus(pushDate,"1");
                    listUpdate = attSourceDataDao.getAttDataUpdateByStatus(pushDate,"1");
                }
            }

        }else if(pushType == 2){
            list = attSourceDataDao.getAttDataByStatus(pushDate,"");
            listUpdate = attSourceDataDao.getAttDataUpdateByStatus(pushDate,"");
        }
        if(list != null && !list.isEmpty()){
            list.forEach(c -> c.setAttStatus("3"));
            attSourceDataDao.updateAttDataList(list);
        }
        if(listUpdate != null && !listUpdate.isEmpty()){
            listUpdate.forEach(c -> c.setAttStatus("3"));
            attSourceDataDao.updateAttDataUpdateList(listUpdate);
        }
    }

    @Override
    public void updateLegalHolidayData(String pushDate) {
        //查询当日是否是法假
        List<Holiday> holidays = attSourceDataDao.selectHolidayByDay(pushDate);
        if(!holidays.isEmpty()){
            //当日为节假日
            List<AttGroupBean> groupList = Optional.ofNullable(attGroupDao.selectAttGroupList(new AttGroupBean())).
                    orElseGet(ArrayList::new);
            List<AttGroupBean> attList = attSourceDataDao.getAttSettingHistoryDate(pushDate);
            groupList.forEach(c -> {
                if(c.getIsHaveHoliday() == 1){
                    List<AttGroupBean> collect = attList.stream().filter(a -> Objects.equals(a.getGroupId(), c.getGroupId())).collect(Collectors.toList());
                    if(!collect.isEmpty()){
                        // 创建一个新的 List<AttDataBean>
                        List<AttDataBean> listUpdate = new ArrayList<>();
                        collect.forEach(v -> {
                            AttDataBean dataBean = new AttDataBean();
                            dataBean.setUserId(v.getUserId());
                            dataBean.setAttCurrentDay(v.getCurrentDay());
                            dataBean.setAttStatus("11");
                            listUpdate.add(dataBean);
                        });
                        attSourceDataDao.updateAttDataList(listUpdate);
                        attSourceDataDao.updateAttDataUpdateList(listUpdate);
                    }
                }
            });

        }

    }
    /**
     * 请假数据应用（步骤二：请假数据更新）
     * 法定节假日不会随时间变化，一天执行一次就可以了
     * @param pushDate 时间
     */
    @Override
    public void updateLeaveData(String pushDate) {
        /**
         * 查出在考勤组人员的请假数据
         */
        List<LeaveBean> leaveList = Optional.ofNullable(attSourceDataDao.getLeaveData(pushDate)).
                orElseGet(ArrayList::new);
        if (!leaveList.isEmpty()) {
            leaveList.forEach(this::threadLeaveData);
        }
    }

    /**
     * 报表数据生成（日报表）
     * 每次更新数据都要执行(跟随)
     * @param pushDate 时间
     */
    @Override
    public void insertDayReportData(String pushDate) {
        //日报表查询
        List<AttDayReportBean> dayReportList = attSourceDataDao.selectAttDayReport(pushDate);
        //日报表新增
        attSourceDataDao.insertAttDayReport(dayReportList);
    }

    /**
     * 月报表模版生成（人员对应出月出勤）
     * 月初生成一次
     * @param pushDate 时间
     */
    @Override
    public void insertMonthReportTempData(String pushDate) {
        //查出本月需生成月计划人员
        List<AttMonthReportBean> monthReportList = attSourceDataDao.selectAttMonthReportTemp(pushDate);
        //查出已生成月计划人员
        List<Long> personList = attSourceDataDao.getAttMonthReportPerson(pushDate);
        monthReportList.removeIf(c -> personList.contains(c.getUserId()));
        //查出考勤组
        List<AttGroupBean> groupList = getGroupData(pushDate);
        //人员对应出月出勤天数
        monthReportList.forEach(c ->
                groupList.stream()
                        .filter(v -> c.getGroupId() != null && c.getGroupId().equals(v.getGroupId()))
                        .findFirst()
                        .ifPresent(v -> c.setRequiredDays(v.getAttWorkDayBean().getRequiredDays()))
        );
        //月报表模版生成
        if(!monthReportList.isEmpty()){
            attSourceDataDao.insertAttMonthReportTemp(monthReportList);
        }
    }

    /**
     * 月报表数据更新（人员对应出月出勤）
     * 每次更新完数据要执行(跟随)
     * @param pushDate 时间
     */
    @Override
    public void updateMonthReportData(String pushDate) {
        List<AttMonthReportBean> monthReportList = attSourceDataDao.selectAttMonthReport(pushDate);
        //月报表修改
        attSourceDataDao.updateAttMonthReport(monthReportList);
    }

    /**
     * 人员考勤模版数据（默认是未打卡）
     * 每天早上0点30执行一次
     * @param pushDate 时间
     * @param pushType 1:自动推送（当天） 2:手动（历史）
     */
    @Override
    public void insertAttTempData(String pushDate, int pushType) {
        //查询当天应考勤人员列表（每个人分上下午生成2条）
        List<AttDataBean> listPerson = attSourceDataDao.getAttPerson(pushDate);
        if (pushType == 1) {
            //只会在凌晨执行一次
            attSourceDataDao.insertAttDataList(listPerson);
        } else if (pushType == 2) {
            //1.查询出历史当天已插入模版
            //2.查询出历史当天考勤列表
            //3.对比增量更新
            List<Long> personId = attSourceDataDao.getAttDataPerson(pushDate);
            listPerson.removeIf(c -> personId.contains(c.getUserId()));
            if(!listPerson.isEmpty()){
                attSourceDataDao.insertAttDataList(listPerson);
            }
        }
    }

    /**
     * 获取考勤数据（数据拉取）
     *
     * @param pushDate 日期
     * @param pushType 1:自动推送（当天） 2:手动（历史）
     */
    @Override
    public void getAttendanceData(String pushDate, int pushType) {
        List<AttSourceDataBean> qsyAttData = getQsyAttendanceData(pushDate, pushType);
        List<AttSourceDataBean> machineAttSourceList = getMachineAttendanceData(pushDate, pushType);
        //新增考勤到考勤来源表(数据过多时分批次插入)
        machineAttSourceList.addAll(qsyAttData);
        insertAttSourceData(machineAttSourceList);
    }


    /**
     * 获取黔送云的考勤数据
     */
    private List<AttSourceDataBean> getQsyAttendanceData(String pushDate, int pushType) {
        List<AttSourceDataBean> attSourceList = Optional.ofNullable(attSourceDataDao.getQsyAttendances(pushDate, pushType)).
                orElseGet(ArrayList::new);
        if (!attSourceList.isEmpty()) {
            attSourceList.forEach(c -> {
                        String address;
                        String province;
                        try {
                            JSONObject result = AddressCoordinateFormatUtil.
                                    coordinateToAddress2(c.getAttLon(), c.getAttLat());
                            address = result.getString("formatted_address");
                            province = result.getJSONObject("addressComponent").getString("province");
                        } catch (Exception e) {
                            address = "地址未转化成功";
                            province = "地址未转化成功";
                        }
                        c.setAttAddress(address);
                        c.setProvince(province);
                    }
            );
        }
        return attSourceList;
    }

    /**
     * 获取考勤机的考勤数据
     */
    private List<AttSourceDataBean> getMachineAttendanceData(String pushDate, int pushType) {
        return Optional.ofNullable(attSourceDataDao.getMachineAttendances(pushDate, pushType)).
                orElseGet(ArrayList::new);
    }

    /**
     * 新增考勤到数据库(考勤来源表)
     * 处理过后的数据新增到考勤来源表
     *
     * @param attSourceList 考勤数据
     */
    public void insertAttSourceData(List<AttSourceDataBean> attSourceList) {
        if (attSourceList == null || attSourceList.isEmpty()) {
            return;
        }
        attSourceList.forEach(c -> {
            if ("0".equals(c.getAttType())) {
                //判断打卡类型
                int i = AttTimeUtil.getAttTypeByTime(c.getAttCurrentTime());
                c.setAttType(String.valueOf(i));
            }
            //判断打卡时间归属于当天还是昨天
            AttTimeUtil.changeAttCurrentDay(c);
        });
        int batchSize = 3000;
        int totalBatches = (int) Math.ceil((double) attSourceList.size() / batchSize);
        try {
            for (int i = 0; i < totalBatches; i++) {
                int fromIndex = i * batchSize;
                int toIndex = Math.min(fromIndex + batchSize, attSourceList.size());
                List<AttSourceDataBean> batch = attSourceList.subList(fromIndex, toIndex);
                attSourceDataDao.insertAttSourceData(batch);
                if ((i + 1) % 100 == 0 || i + 1 == totalBatches) {
                    sqlSessionTemplate.flushStatements(); // 提交事务
                    sqlSessionTemplate.clearCache(); // 清理缓存
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("考勤数据抓取到数据库出错啦", e);
        }
    }

    /**
     * 查出每一个考勤组的应出勤天数以及考勤组的规则
     *
     * @return 考勤组集合
     */
    public List<AttGroupBean> getGroupData(String pushDate) {
        //查出考勤组的数据
        List<AttGroupBean> groupList = Optional.ofNullable(attGroupDao.selectAttGroupList(new AttGroupBean())).
                orElseGet(ArrayList::new);
        if (groupList.isEmpty()) {
            return new ArrayList<>();
        }
        //查询当月否有节假日或补班
        List<Holiday> holidays = attSourceDataDao.selectHolidayByMonth(pushDate);
        groupList.forEach(c -> {
            //应考勤天
            List<String> attDayList = WorkdayCalculator.getWorkDay(c.getAttDay(),
                    c.getIsHaveHoliday(), holidays, pushDate);
            c.setAttWorkDayBean(new PersonAttWorkDayBean(c.getGroupId(), attDayList.size(), attDayList));
        });
        return groupList;
    }


    /**
     * 固定考勤数据计算
     *
     * @param list         考勤来源数据
     * @param attGroupBean 考勤组数据
     * @return 考勤数据
     */
    private List<AttSourceDataBean> groupFixedData(List<AttSourceDataBean> list,
                                                   AttGroupBean attGroupBean) {
        List<AttSourceDataBean> newList = new ArrayList<>();
        //分组排序(将每个人每天在自己考勤组的数据分组)
        Map<String, List<AttSourceDataBean>> groupedItems = list.stream()
                .collect(Collectors.groupingBy(
                        c -> c.getUserId() + "|" + c.getAttCurrentDay(),
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                v -> {
                                    v.sort(Comparator.comparing(AttSourceDataBean::getAttCurrentTime));
                                    return v;
                                }
                        )
                ));
        //固定打卡，以最靠近上班打卡时间前的出闸机的时间为基准，去除掉之前的所有打卡数据
        AttTimeUtil.processGroupedItems(groupedItems, attGroupBean);
        groupedItems.forEach((c, v) -> {
            //第一次上班时间
            AttSourceDataBean frontToWorkBean = v.stream()
                    .filter(a -> a.getAttType().equals("1"))
                    .collect(Collectors.toList())
                    .stream().min(Comparator.comparing(AttSourceDataBean::getAttCurrentTime)).orElse(null);
            //最新一次下班时间
            AttSourceDataBean backOffWorkBean = v.stream()
                    .filter(a -> a.getAttType().equals("2"))
                    .collect(Collectors.toList())
                    .stream().max(Comparator.comparing(AttSourceDataBean::getAttCurrentTime)).orElse(null);

            if (backOffWorkBean != null) {
                //最新一次下班时间插入list
                newList.add(backOffWorkBean);
            }
            //没有下班卡则添加第一次打卡数据
            newList.add(frontToWorkBean);
            //获取工作时间外出记录并存储（支线，不影响）
            addWorkTimeOutRecord(v, attGroupBean);
        });
        Iterator<AttSourceDataBean> iterator = newList.iterator();
        while (iterator.hasNext()) {
            if (iterator.next() == null) {
                iterator.remove();
            }
        }
        processAttendanceStatus(newList, attGroupBean.getToWorkTime(), attGroupBean.getOffWorkTime(), attGroupBean.getLateMinute(),
                attGroupBean.getAbsenteeismLateMinute(), attGroupBean.getLeaveMinute(), attGroupBean.getAbsenteeismLeaveMinute());
        return newList;
    }

    /**
     * 自由考勤数据计算
     *
     * @param list         考勤来源数据
     * @param attGroupBean 考勤组数据
     * @return 考勤数据
     */
    private List<AttSourceDataBean> groupFreeData(List<AttSourceDataBean> list, AttGroupBean attGroupBean) {
        List<AttSourceDataBean> newList = new ArrayList<>();
        //分组排序(将每个人每天在自己考勤组的数据分组)
        Map<String, List<AttSourceDataBean>> groupedItems = list.stream()
                .collect(Collectors.groupingBy(
                        c -> c.getUserId() + "|" + c.getAttCurrentDay(),
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                v -> {
                                    v.sort(Comparator.comparing(AttSourceDataBean::getAttCurrentTime));
                                    return v;
                                }
                        )
                ));

        groupedItems.forEach((c, v) -> {
            //第一次上班时间
            AttSourceDataBean frontToWorkBean = v.stream()
                    .filter(a -> a.getAttType().equals("1"))
                    .collect(Collectors.toList())
                    .stream().min(Comparator.comparing(AttSourceDataBean::getAttCurrentTime)).orElse(null);
            //最新一次下班时间
            AttSourceDataBean backOffWorkBean = v.stream()
                    .filter(a -> a.getAttType().equals("2"))
                    .collect(Collectors.toList())
                    .stream().max(Comparator.comparing(AttSourceDataBean::getAttCurrentTime)).orElse(null);
            //自由打卡不需要去除数据
            getFreeAttData(newList, frontToWorkBean, backOffWorkBean, attGroupBean);
        });
        return newList;
    }

    /**
     * 处理打卡状态
     *
     * @param newList                考勤数据
     * @param toWorkTime             上班时间
     * @param offWorkTime            下班时间
     * @param lateMinute             迟到时间
     * @param absenteeismLateMinute  旷工迟到分钟
     * @param leaveMinute            早退分钟
     * @param absenteeismLeaveMinute 旷工早退分钟
     */
    private void processAttendanceStatus(List<AttSourceDataBean> newList, String toWorkTime,
                                         String offWorkTime, long lateMinute,
                                         long absenteeismLateMinute, long leaveMinute,
                                         long absenteeismLeaveMinute) {
        newList.forEach(c -> {
//            if(c.getName().equals("肖阳")){
//                System.out.println("c.getAttCurrentTime() = " + c.getAttCurrentTime());
//            }
            System.out.println(c.getName());
            int attStatus = calculateStatus(
                    c.getAttType(),
                    c.getAttCurrentTime(),
                    "1".equals(c.getAttType()) ? toWorkTime : offWorkTime,
                    "1".equals(c.getAttType()) ? lateMinute : leaveMinute,
                    "1".equals(c.getAttType()) ? absenteeismLateMinute : absenteeismLeaveMinute
            );
            System.out.println(1111);
            // 如打卡状态为正常，检查是否有异常出入时间
            if (attStatus == 1 && c.getAttStatus() != null && c.getAttStatus() == 8) {
                attStatus = 8; // 异常
                boolean b = DateTimeHelper.compareTime2(c.getAttCurrentTime(), c.getAbnormalAttTime());
                String time = "";
                String address = "";
                if (b) {
                    time = c.getAttCurrentTime() + "  " + c.getAbnormalAttTime();
                    address = c.getAttAddress() + "  " + c.getAbnormalAttAddress();
                } else {
                    time = c.getAbnormalAttTime() + "  " + c.getAttCurrentTime();
                    address = c.getAbnormalAttAddress() + "  " + c.getAttAddress();
                }
                c.setAttCurrentTime(time);
                c.setAttAddress(address);
            }
            System.out.println(2222);
            c.setAttStatus(attStatus);
        });
    }

    /**
     * 获取自由考勤数据
     *
     * @param newList         考勤数据
     * @param frontToWorkBean 第一次上班考勤数据
     * @param backOffWorkBean 最后一次下班考勤数据
     * @param attGroupBean    考勤组数据
     */
    private void getFreeAttData(List<AttSourceDataBean> newList,
                                AttSourceDataBean frontToWorkBean,
                                AttSourceDataBean backOffWorkBean,
                                AttGroupBean attGroupBean) {
        // todayClockNum 自由打卡每天打卡次数
        if (attGroupBean.getTodayClockNum() == 2) {
            if (frontToWorkBean != null) {
                frontToWorkBean.setAttStatus(1);
                newList.add(frontToWorkBean);
            }
            if (backOffWorkBean != null) {
                if (frontToWorkBean != null) {
                    long minutesDiff = DateUtil.between(
                            DateUtils.parseDate(frontToWorkBean.getAttCurrentTime()),
                            DateUtils.parseDate(backOffWorkBean.getAttCurrentTime()),
                            DateUnit.MINUTE
                    );
                    if (minutesDiff >= attGroupBean.getAttendanceDuration()) {
                        backOffWorkBean.setAttStatus(1);
                    } else {
                        if (minutesDiff > attGroupBean.getAbsenteeismLateMinute()) {
                            backOffWorkBean.setAttStatus(1);
                        } else if (minutesDiff > attGroupBean.getAbsenteeismLeaveMinute()) {
                            backOffWorkBean.setAttStatus(4);
                        } else {
                            backOffWorkBean.setAttStatus(3);
                        }
                    }
                    newList.add(backOffWorkBean);
                } else {
                    backOffWorkBean.setAttStatus(1);
                    newList.add(backOffWorkBean);
                }
            }
        } else {
            if (frontToWorkBean != null) {
//                if(frontToWorkBean.getName().equals("位兆虎")){
//                    System.out.println(1);
//                }
                frontToWorkBean.setAttStatus(1);
                AttSourceDataBean bean;
                try {
                    bean = (AttSourceDataBean) BeanUtils.cloneBean(frontToWorkBean);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                bean.setAttCurrentTime("");
                bean.setAttType("2");
                newList.add(bean);
                newList.add(frontToWorkBean);
            } else if (backOffWorkBean != null) {
                backOffWorkBean.setAttStatus(1);
                AttSourceDataBean bean;
                try {
                    bean = (AttSourceDataBean) BeanUtils.cloneBean(backOffWorkBean);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                bean.setAttCurrentTime("");
                bean.setAttType("1");
                newList.add(bean);
                newList.add(backOffWorkBean);
            }
        }
    }

    /**
     * 计算时间差并返回状态
     *
     * @param attType              考勤类型
     * @param attTime              考勤时间
     * @param standardTime         上、下班时间
     * @param lateThreshold        迟到、早退时间
     * @param absenteeismThreshold 旷工时间
     * @return 考勤状态
     */
    private int calculateStatus(String attType, String attTime, String standardTime,
                                long lateThreshold, long absenteeismThreshold) {
        int status = 1;
        // 创建两个时间点
        Date date1 = DateUtils.parseDate(DateUtils.getYyyyMmDd(attTime) + " " + standardTime);
        Date date2 = DateUtils.parseDate(attTime);
        if ("2".equals(attType)) {
            String startTime = DateUtils.getYyyyMmDd(attTime) + " 00:00:00";
            String endTime = DateUtils.getYyyyMmDd(attTime) + " 04:59:59";
            if (DateUtils.getTimeIsRange(attTime, startTime, endTime)) {
                date1 = DateUtils.parseDate(DateUtils.getAfterDate(DateUtils.getYyyyMmDd(attTime)) + " " + standardTime);
            }
        }
        if ("1".equals(attType)) { // 上班打卡
            // 计算时间差
            // 减 1 原因：30上班，30:59不算迟到，类似于默认可以迟到一分钟
            double difference = (date2.getTime() - date1.getTime()) / 60000.0 - 1;
            if (difference > 0) {
                if (difference > absenteeismThreshold) {
                    status = 3; // 旷工
                } else if (difference > lateThreshold) {
                    status = 2; // 迟到
                }
            }
        } else if ("2".equals(attType)) { // 下班打卡
            // 计算时间差
            double difference = (date2.getTime() - date1.getTime()) / 60000.0;
            if (difference < 0) {
                if (Math.abs(difference) > lateThreshold) {
                    status = 4; // 早退
                }
                if (Math.abs(difference) > absenteeismThreshold) {
                    status = 3; // 旷工
                }
            }
        }
        return status; // 正常
    }

    private void addWorkTimeOutRecord(List<AttSourceDataBean> v, AttGroupBean attGroupBean) {
        LocalTime lastOutTime = null;
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
        try {
            //存储工作异常的list
            List<AttSourceDataBean> longBreakRecords = new ArrayList<>();
            for (int i = 0; i < v.size(); i++) {
                AttSourceDataBean record = v.get(i);
                // 如果是“出”的记录，保存时间
                if ("2".equals(record.getAttType())) {
                    lastOutTime = LocalDateTime.parse(record.getAttCurrentTime(), dateTimeFormatter).toLocalTime();
                    if (lastOutTime.isAfter(LocalTime.parse(attGroupBean.getOffWorkTime(), timeFormatter))) {
                        //进在下班之后，不考虑
                        break;
                    }
                }
                // 如果是“进”的记录并且之前有“出”的记录
                else if ("1".equals(record.getAttType()) && lastOutTime != null) {
                    LocalTime inTime = LocalDateTime.parse(record.getAttCurrentTime(), dateTimeFormatter).toLocalTime();
                    // 计算实际工作时间（不包括午休时间）
//                        if(record.getName().equals("何波")){
//                            System.out.println("11111111111");
//                        }
                    // 出-》进 的时间在上班时间前，去除
                    if (inTime.isBefore(LocalTime.parse(attGroupBean.getToWorkTime(), timeFormatter))) {
                        //进在上班之后，不考虑
                        break;
                    }
                    Duration workDuration = AttTimeUtil.calculateWorkDuration(lastOutTime, inTime, attGroupBean);
                    // 如果工作时间外出超过了规定时间，记录下这对“出”和“进”
                    if (workDuration != null && !workDuration.isNegative() && workDuration.toMinutes() > attGroupBean.getWorkAbnormalMinute()) {
                        AttSourceDataBean longBreakRecord = new AttSourceDataBean();
                        longBreakRecord.setUserId(record.getUserId());
                        longBreakRecord.setName(record.getName());
                        longBreakRecord.setOrgId(attGroupBean.getOrgId());
                        longBreakRecord.setAttCurrentDay(record.getAttCurrentDay());
                        longBreakRecord.setAttCurrentTime(v.get(i - 1).getAttCurrentTime() + "  " + record.getAttCurrentTime());
                        longBreakRecord.setAttAddress(v.get(i - 1).getAttAddress() + "  " + record.getAttAddress());
                        longBreakRecords.add(longBreakRecord);
                    }
                    // 更新lastOutTime为null，因为已经处理了这一对
                    lastOutTime = null;
                }
            }
            //判断有没有临时外出请假等等
            if (!longBreakRecords.isEmpty()) {
                int x = attSourceDataDao.getLeaveDataByUserId(longBreakRecords.get(0));
                if (x == 0) {
                    attSourceDataDao.insertWorkAbnormal(longBreakRecords);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("工作异常处理报错");
        }
    }

    /**
     * 根据请假数据去更新考勤数据
     */
    private void threadLeaveData(LeaveBean c) {
        //1.将请假区间变成日期集合
//        if(c.getUserId() == 263){
//            System.out.println("米娜");
//        }
        List<String> dateLists = AttTimeUtil.getStrDateListBetween(c.getLeaveStartDate(), c.getLeaveEndDate());
        if (!dateLists.isEmpty()) {
//            //根据开始时间、结束时间获取节假日的日期集合
            dateLists.forEach(v -> {
                boolean tf = false;
                AttDataBean toWorkBean = new AttDataBean(v, c.getAttStatus(), "1",
                         c.getUserId());
                AttDataBean offWorkBean = new AttDataBean(v, c.getAttStatus(), "2",
                         c.getUserId());
                //开始和结束的那天是否只请了半天
                if (c.getLeaveStartDate().equals(v)) {
                    if (c.getLeaveStartInterval().equals("2")) {
                        attSourceDataDao.updateLeaveData(offWorkBean);
                    } else {
                        tf = true;
                    }
                } else if (c.getLeaveEndDate().equals(v)) {
                    if (c.getLeaveEndInterval().equals("1")) {
                        attSourceDataDao.updateLeaveData(toWorkBean);
                    } else {
                        tf = true;
                    }
                } else {
                    tf = true;
                }
                if (tf) {
                    attSourceDataDao.updateLeaveData(toWorkBean);
                    attSourceDataDao.updateLeaveData(offWorkBean);
                }
            });
        }
    }


}
