package jnpf.attendance.service.handle.rule;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.JSON;
import jnpf.attendance.service.RuleProcessor;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.entity.attendance.LeaveParam;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.enums.attendance.LeaveUnitEnum;
import jnpf.enums.attendance.v2.WorkBoundaryCoverageEnum;
import jnpf.model.attendance.vo.DailyRuleResultVo;
import jnpf.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 处理历史请假申请
 */
@Component
@Slf4j
public class LeaveRuleProcessor extends RuleProcessor {

    @Override
    public void ruleArrangementHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> currDailyRule, List<DailyRuleResultVo> resultList) {
        Map<Integer, List<FtbAttendanceDailyRule>> collect = hisDailyRules.stream().collect(Collectors.groupingBy(FtbAttendanceDailyRule::getAttendanceType));
        List<FtbAttendanceDailyRule> ftbAttendanceDailyRules = collect.getOrDefault(AttendanceTypeEnum.LEAVE.getCode(), List.of()).stream().filter(rule -> Objects.isNull(rule.getIsInsert()) || !rule.getIsInsert()).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(ftbAttendanceDailyRules)) {
            Iterator<FtbAttendanceDailyRule> iterator = currDailyRule.iterator();
            while (iterator.hasNext()) {
                FtbAttendanceDailyRule rule = iterator.next();
                //新增排休
                if (restHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
                    continue;
                }
                //新增上班
                if (ordinaryHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
                    continue;
                }
                //新增加班
                if (workOvertimeHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
                    continue;
                }
                //新增请假
                if (leaveHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
                    continue;
                }
                //新增出差、外出
                if (stepOutHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
                    continue;
                }
                //新增清除
                clearHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList);
            }
        }
        if (Objects.nonNull(nextRuleProcessor)) {
            nextRuleProcessor.ruleArrangementHandle(hisDailyRules, currDailyRule, resultList);
        }
    }

    private Boolean clearHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
        //新增清除
        if (!Objects.equals(AttendanceTypeEnum.CLEAR.getCode(), rule.getAttendanceType())) {
            return Boolean.FALSE;
        }
        ftbAttendanceDailyRules.forEach(oldRule -> {
            oldRule.setShiftId("");
            oldRule.setInPoint(oldRule.getApplyStart());
            oldRule.setOutPoint(oldRule.getApplyEnd());
            oldRule.setApplyViewEnable(2);
            oldRule.setLeaveDay(BigDecimal.ZERO);
            oldRule.setPayrollHours(BigDecimal.ZERO);
            oldRule.setValidDuration(0);

        });
        return Boolean.TRUE;
    }

    /**
     * 新增外出、出差申请
     *
     * @param hisDailyRules           历史规则
     * @param ftbAttendanceDailyRules 新增规则集合
     * @param rule                    当前规则
     */
    private Boolean stepOutHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
        //新增外出、出差申请
        if (!Objects.equals(AttendanceTypeEnum.BUSINESS_TRIP.getCode(), rule.getAttendanceType()) && !Objects.equals(AttendanceTypeEnum.STEP_OUT.getCode(), rule.getAttendanceType())) {
            return Boolean.FALSE;
        }
        ftbAttendanceDailyRules.forEach(oldRule -> {
            //过滤隐藏规则
            if (Objects.equals(oldRule.getApplyViewEnable(), 0)) {
                return;
            }
            rule.setShiftId(oldRule.getShiftId());
            rule.setPeriodId(oldRule.getPeriodId());
            //原小时外出没命中已有班次数据，隐藏外出申请
            if (rule.getOutPoint().before(oldRule.getInPoint())
                    || rule.getInPoint().after(oldRule.getOutPoint())
                    || rule.getInPoint().after(oldRule.getInPoint()) && rule.getOutPoint().before(oldRule.getOutPoint())) {
                if (!rule.getIsInsert()) {
                    if (!hisDailyRules.contains(rule)) {
                        hisDailyRules.add(rule);
                    }
                }
                log.error("新增排班数据未命中小时外出申请或者外出数据完全被排班数据覆盖，过滤{}", JSON.toJSONString(rule));
                return;
            }
            rule.insertTrue();
            if (!hisDailyRules.contains(rule)) {
                hisDailyRules.add(rule);
            }
            rule.setApplyViewEnable(0);
            oldRule.setApplyViewEnable(rule.getAttendanceType());
            //原小时外出数据覆盖现在新增排班数据上班时间
            if (!rule.getInPoint().after(oldRule.getInPoint())) {
                oldRule.setInStepOutType(1);
                oldRule.setInStepOutApplyId(rule.getApplyId());
            }
            //原小时外出数据覆盖现在新增排班数据下班时间
            if (!rule.getOutPoint().before(oldRule.getOutPoint())) {
                oldRule.setOutStepOutType(1);
                oldRule.setOutStepOutApplyId(rule.getApplyId());
            }
            log.error("新增外出、出差申请标记原请假时段{}", JSON.toJSONString(rule));
            resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
        });
        return Boolean.TRUE;
    }

    /**
     * 新增请假
     *
     * @param hisDailyRules           历史规则
     * @param ftbAttendanceDailyRules 新增规则集合
     * @param rule                    当前规则
     */
    private Boolean leaveHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
        //新增请假
        if (!Objects.equals(AttendanceTypeEnum.LEAVE.getCode(), rule.getAttendanceType())) {
            return Boolean.FALSE;
        }
        ftbAttendanceDailyRules.forEach(oldRule -> {
            //新加入数据不做处理
            if (oldRule.getIsInsert() || Objects.equals(rule.getId(), oldRule.getId())) {
                return;
            }
            if (!Objects.equals(LeaveUnitEnum.HOUR.getCode(), rule.getApplyUnit()) || !Objects.equals(LeaveUnitEnum.HOUR.getCode(), oldRule.getApplyUnit())) {
                if (isLeaveDateConflict(rule, oldRule)) {
                    log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.LEAVE));
                    resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.LEAVE.getCode(), rule.getAttendanceType()));
                    return;
                }
                return;
            }
            //如果当前申请的请假单位为天或者半天，原班次存在单位为小时的请假，则直接提示
            Assert.isFalse(isLeaveDateConflict(rule, oldRule) || isLeaveDateConflict(oldRule, rule), "当前请假时间与原请假时间冲突");
            //请假单位非小时，不走下述逻辑
            if (Objects.nonNull(rule.getApplyUnit()) && !Objects.equals(rule.getApplyUnit(), LeaveUnitEnum.HOUR.getCode())) {
                return;
            }
            rule.setShiftId(oldRule.getShiftId());
            rule.setPeriodId(oldRule.getPeriodId());
            //新增请假时间完全覆盖原来请假时段
            if (DateDetail.checkTimeBetween(oldRule.getApplyStart(), rule.getApplyStart(), rule.getApplyEnd())
                    && DateDetail.checkTimeBetween(oldRule.getApplyEnd(), rule.getApplyStart(), rule.getApplyEnd())) {
                log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.LEAVE));
                resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.LEAVE.getCode(), rule.getAttendanceType()));
                return;
            }

            //部分覆盖
            //开始部分覆盖
            if (DateDetail.checkBetween(rule.getApplyEnd(), oldRule.getApplyStart(), oldRule.getApplyEnd())) {
                log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.LEAVE));
                resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.LEAVE.getCode(), rule.getAttendanceType()));
                return;
            }
            //结束部分覆盖
            if (DateDetail.checkBetween(rule.getApplyStart(), oldRule.getApplyStart(), oldRule.getApplyEnd())) {
                log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.LEAVE));
                resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.LEAVE.getCode(), rule.getAttendanceType()));
                return;
            }
            //新增请假时段处于原请假时段中间
            if (DateDetail.checkTimeBetweenL(rule.getApplyStart(), oldRule.getApplyStart(), oldRule.getApplyEnd())
                    && DateDetail.checkTimeBetweenR(rule.getApplyEnd(), oldRule.getApplyStart(), oldRule.getApplyEnd())) {
                log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.LEAVE));
                resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.LEAVE.getCode(), rule.getAttendanceType()));
                return;
            }
            //请假与请假时间边界连接
            //请假结束时间与原请假开始时间相同
            if (oldRule.getInPoint().compareTo(rule.getApplyEnd()) == 0) {
                oldRule.setInUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
                rule.setOutUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
            }
            //请假开始时间与原请假时段结束时间相同
            if (oldRule.getOutPoint().compareTo(rule.getApplyStart()) == 0) {
                oldRule.setOutUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
                rule.setInUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
            }
            if (!hisDailyRules.contains(rule) && !rule.getIsInsert()) {
                hisDailyRules.add(rule);
                log.error("新增请假时段与原请假时段没交集{}", JSON.toJSONString(rule));
            }
        });
        return Boolean.TRUE;
    }

    /**
     * 判断修改后的规则是否与旧规则在请假时间上存在冲突
     * 此方法专门用于检查是否存在请假日期冲突，即旧规则设置为请假，而新规则不设置为请假的情况
     * 这种冲突检测对于确保考勤政策的一致性和准确性至关重要
     *
     * @param rule    新的考勤日常规则对象，包含修改后的规则信息
     * @param oldRule 旧的考勤日常规则对象，包含修改前的规则信息
     * @return 如果存在请假日期冲突，则返回true；否则返回false
     */
    private boolean isLeaveDateConflict(FtbAttendanceDailyRule rule, FtbAttendanceDailyRule oldRule) {
        if (oldRule.getIsInsert()) {
            return Boolean.FALSE;
        }
        if (!Objects.equals(rule.getApplyUnit(), oldRule.getApplyUnit())) {
            log.error("新增请假与原请假时间冲突");
            return Boolean.TRUE;
        }
        //新增请假不是全天且不是半天，则过滤
        if (Objects.equals(rule.getApplyUnit(), LeaveUnitEnum.HOUR.getCode()) || Objects.isNull(rule.getApplyUnit())) {
            return Boolean.FALSE;
        }

        // 检查旧规则是否请假单位为小时，同时新规则的请假单位不为小时，表示存在冲突
        //如果原来为全天请假则冲突
        if (Objects.equals(oldRule.getApplyUnit(), LeaveUnitEnum.DAY.getCode())) {
            log.error("新增请假与原全天请假冲突");
            return Boolean.TRUE;
        }
        //如果原来为全天请假则冲突
        //如果原半天请假时间处于新增请假中间
        LeaveParam leaveParam = JsonUtil.getJsonToBean(rule.getLeaveParam(), LeaveParam.class);
        LeaveParam oldLeaveParam = JsonUtil.getJsonToBean(oldRule.getLeaveParam(), LeaveParam.class);
        if (leaveParam.getStart().compareTo(oldLeaveParam.getEnd()) == 0 && oldLeaveParam.getEndTimeType() < leaveParam.getStartTimeType()) {
            return Boolean.FALSE;
        }
        if (leaveParam.getEnd().compareTo(oldLeaveParam.getStart()) == 0 && oldLeaveParam.getStartTimeType() > leaveParam.getEndTimeType()) {
            return Boolean.FALSE;
        }
        log.error("新增半天请假与原半天请假冲突");
        return Boolean.TRUE;
    }

    /**
     * 新增上班
     *
     * @param hisDailyRules           历史规则
     * @param ftbAttendanceDailyRules 新增规则集合
     * @param ordinaryRule            当前规则
     */
    private Boolean ordinaryHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule ordinaryRule, List<DailyRuleResultVo> resultList) {
        //新增上班
        if (!Objects.equals(AttendanceTypeEnum.ORDINARY.getCode(), ordinaryRule.getAttendanceType())) {
            return Boolean.FALSE;
        }
        Set<String> seen = new HashSet<>();
        hisDailyRules.removeAll(ftbAttendanceDailyRules);
        List<FtbAttendanceDailyRule> ftbAttendanceDailyRules1 = ftbAttendanceDailyRules.stream()
                .filter(p -> seen.add(p.getApplyId()))
                .collect(Collectors.toList());
        hisDailyRules.addAll(ftbAttendanceDailyRules1);
        ftbAttendanceDailyRules1.stream().filter(rule1 -> !Objects.equals(rule1.getApplyUnit(), 1) && Objects.nonNull(rule1.getApplyUnit())).forEach(leaveRule -> {
            daysLeaveHandle(hisDailyRules, leaveRule, ordinaryRule, resultList);
        });
        ftbAttendanceDailyRules1.removeIf(dailyRule -> Objects.equals(dailyRule.getAttendanceType(), AttendanceTypeEnum.LEAVE.getCode()) && !Objects.equals(dailyRule.getApplyUnit(), LeaveUnitEnum.HOUR.getCode()));
        List<FtbAttendanceDailyRule> collect = ftbAttendanceDailyRules1.stream().filter(rule1 -> Objects.equals(rule1.getApplyUnit(), 1) || Objects.isNull(rule1.getApplyUnit())).collect(Collectors.toList());
        Iterator<FtbAttendanceDailyRule> leaveRuleIterator = collect.iterator();
        while (leaveRuleIterator.hasNext()) {
            houseLeaveHandle(hisDailyRules, ordinaryRule, leaveRuleIterator, resultList);
        }
        return Boolean.TRUE;
    }

    /**u
     * 小时请假处理
     *
     * @param hisDailyRules
     * @param ordinaryRule
     * @param leaveRuleIterator
     * @param resultList
     */
    private void houseLeaveHandle(List<FtbAttendanceDailyRule> hisDailyRules, FtbAttendanceDailyRule ordinaryRule, Iterator<FtbAttendanceDailyRule> leaveRuleIterator, List<DailyRuleResultVo> resultList) {
        FtbAttendanceDailyRule leaveRule = leaveRuleIterator.next();
        if (Objects.nonNull(leaveRule.getApplyUnit()) && !Objects.equals(leaveRule.getApplyUnit(), LeaveUnitEnum.HOUR.getCode())) {
            return;
        }
        if (Objects.equals(ordinaryRule.getApplyViewEnable(), 0)) {
            leaveRule.setApplyViewEnable(2);
            return;
        }
        ordinaryRule.setSelfGroup(leaveRule.getSelfGroup());
        leaveRule.setApplyViewEnable(1);
        leaveRule.setFixedMark(ordinaryRule.getFixedMark());
        leaveRule.setPeriodId(ordinaryRule.getPeriodId());
        //新增上班时段处于原请假时段中间
        if (DateDetail.checkTimeBetween(ordinaryRule.getInPoint(), leaveRule.getApplyStart(), leaveRule.getApplyEnd())
                && DateDetail.checkTimeBetween(ordinaryRule.getOutPoint(), leaveRule.getApplyStart(), leaveRule.getApplyEnd())) {
            leaveRule = getFtbAttendanceDailyRule(ordinaryRule, leaveRule);
            leaveRule.setInPoint(ordinaryRule.getInPoint());
            leaveRule.setOutPoint(ordinaryRule.getOutPoint());
            if (!hisDailyRules.contains(leaveRule)) {
                hisDailyRules.add(leaveRule);
            }
            getBreakTimeByOrdinary(leaveRule, ordinaryRule);
            houseLeaveDayProcess(leaveRule, ordinaryRule.getOriginValidDuration(), ordinaryRule.getPeriodWorkDay(), ordinaryRule.getPayrollHours());
            ordinaryRule.insertTrue();
            hisDailyRules.remove(ordinaryRule);
            log.error("新增上班时段处于原请假时段中间{}", JSON.toJSONString(ordinaryRule));
            resultList.add(DailyRuleResultVo.successBuild(leaveRule, ordinaryRule));
            return;
        }
        //新增上班时间完全覆盖原来请假时段
        if (DateDetail.checkTimeBetween(leaveRule.getApplyStart(), ordinaryRule.getInPoint(), ordinaryRule.getOutPoint())
                && DateDetail.checkTimeBetween(leaveRule.getApplyEnd(), ordinaryRule.getInPoint(), ordinaryRule.getOutPoint())) {
            leaveRule = getFtbAttendanceDailyRule(ordinaryRule, leaveRule);
            if (!hisDailyRules.contains(leaveRule)) {
                hisDailyRules.add(leaveRule);
            }
            FtbAttendanceDailyRule rule1 = BeanUtil.toBean(ordinaryRule, FtbAttendanceDailyRule.class);
            resultList.add(DailyRuleResultVo.successBuild(leaveRule, ordinaryRule));
            ordinaryRule.setOutLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getOutPoint(), ordinaryRule.getOutLackPoint(), leaveRule.getApplyStart()));
            ordinaryRule.setEarlyPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getOutPoint(), ordinaryRule.getEarlyPoint(), leaveRule.getApplyStart()));
            ordinaryRule.setOutPoint(leaveRule.getApplyStart());
            ordinaryRule.setOutUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
            ordinaryRule.calInLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getInLackPoint(), leaveRule.getApplyStart()));
            ordinaryRule.calLatePoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getLatePoint(), leaveRule.getApplyStart()));
            getBreakTimeByOrdinary(leaveRule, ordinaryRule);
            rule1.calInLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getInLackPoint(), leaveRule.getApplyEnd()));
            rule1.setClockStartPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getClockStartPoint(), leaveRule.getApplyEnd()));
            rule1.calLatePoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getLatePoint(), leaveRule.getApplyEnd()));
            rule1.setInPoint(leaveRule.getApplyEnd());
            rule1.setInUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
            rule1.setId(RandomUtil.uuId());
            getBreakTimeByOrdinary(leaveRule, rule1);
            houseLeaveDayProcess(leaveRule, ordinaryRule.getOriginValidDuration(), ordinaryRule.getPeriodWorkDay(), ordinaryRule.getPayrollHours());
            if (!hisDailyRules.contains(ordinaryRule)) {
                ordinaryRule.insertTrue();
                hisDailyRules.add(ordinaryRule);
            }
            if (DateUtil.dateDiff(ordinaryRule.getOutPoint(), ordinaryRule.getInPoint()) == 0) {
                hisDailyRules.remove(ordinaryRule);
            }
            log.error("新增上班时间完全覆盖原来请假时段{}", JSON.toJSONString(ordinaryRule));
            if (DateUtil.dateDiff(rule1.getOutPoint(), rule1.getInPoint()) != 0) {
                leaveRuleIterator.remove();
                if (!leaveRuleIterator.hasNext()) {
                    if (!hisDailyRules.contains(rule1)) {
                        rule1.insertTrue();
                        hisDailyRules.add(rule1);
                        resultList.add(DailyRuleResultVo.successBuild(leaveRule, rule1));
                    }
                    return;
                }
                houseLeaveHandle(hisDailyRules, rule1, leaveRuleIterator, resultList);
            }
            return;
        }
        //部分覆盖
        //开始部分覆盖
        if (DateDetail.checkTimeBetweenR(ordinaryRule.getOutPoint(), leaveRule.getApplyStart(), leaveRule.getApplyEnd())) {
            leaveRule = getFtbAttendanceDailyRule(ordinaryRule, leaveRule);
            leaveRule.setOutPoint(ordinaryRule.getOutPoint());
            if (!hisDailyRules.contains(leaveRule)) {
                hisDailyRules.add(leaveRule);
            }
            ordinaryRule.setOutLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getOutPoint(), ordinaryRule.getOutLackPoint(), leaveRule.getApplyStart()));
            ordinaryRule.setEarlyPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getOutPoint(), ordinaryRule.getEarlyPoint(), leaveRule.getApplyEnd()));
            ordinaryRule.setOutPoint(leaveRule.getApplyStart());
            ordinaryRule.setOutUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
            ordinaryRule.calInLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getInLackPoint(), ordinaryRule.getInPoint()));
            ordinaryRule.calLatePoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getLatePoint(), ordinaryRule.getInPoint()));
            getBreakTimeByOrdinary(leaveRule, ordinaryRule);
            houseLeaveDayProcess(leaveRule, ordinaryRule.getOriginValidDuration(), ordinaryRule.getPeriodWorkDay(), ordinaryRule.getPayrollHours());
            log.error("新增上班时段开始部分覆盖原请假时段中间{}", JSON.toJSONString(ordinaryRule));
            if (!hisDailyRules.contains(ordinaryRule)) {
                ordinaryRule.insertTrue();
                hisDailyRules.add(ordinaryRule);
            }
            resultList.add(DailyRuleResultVo.successBuild(leaveRule, ordinaryRule));
            return;
        }
        //结束部分覆盖
        if (DateDetail.checkTimeBetweenL(ordinaryRule.getInPoint(), leaveRule.getApplyStart(), leaveRule.getApplyEnd())) {
            leaveRule = getFtbAttendanceDailyRule(ordinaryRule, leaveRule);
            leaveRule.setInPoint(ordinaryRule.getInPoint());
            if (!hisDailyRules.contains(leaveRule)) {
                hisDailyRules.add(leaveRule);
            }
            ordinaryRule.calInLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getInLackPoint(), leaveRule.getApplyEnd()));
            ordinaryRule.setClockStartPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getClockStartPoint(), leaveRule.getApplyEnd()));
            ordinaryRule.calLatePoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getLatePoint(), leaveRule.getApplyEnd()));
            ordinaryRule.setInPoint(leaveRule.getApplyEnd());
            ordinaryRule.setInUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
            getBreakTimeByOrdinary(leaveRule, ordinaryRule);
            houseLeaveDayProcess(leaveRule, ordinaryRule.getOriginValidDuration(), ordinaryRule.getPeriodWorkDay(), ordinaryRule.getPayrollHours());
            log.error("新增上班时段结束部分覆盖原请假时段中间{}", JSON.toJSONString(ordinaryRule));
            if (DateUtil.dateDiff(ordinaryRule.getOutPoint(), ordinaryRule.getInPoint()) != 0) {
                leaveRuleIterator.remove();
                if (!leaveRuleIterator.hasNext()) {
                    if (!hisDailyRules.contains(ordinaryRule)) {
                        ordinaryRule.insertTrue();
                        hisDailyRules.add(ordinaryRule);
                        resultList.add(DailyRuleResultVo.successBuild(leaveRule, ordinaryRule));
                    }
                    return;
                }
                houseLeaveHandle(hisDailyRules, ordinaryRule, leaveRuleIterator, resultList);
            }
            return;
        }

        if (!leaveRule.getIsInsert()) {
            leaveRule.setApplyViewEnable(2);
        }
        if (!hisDailyRules.contains(ordinaryRule) && !ordinaryRule.getIsInsert()) {
            //完全没交集
            hisDailyRules.add(ordinaryRule);
            ordinaryRule.insertTrue();
        }
        log.error("新增上班时间与原来请假时段完全没交集{}", JSON.toJSONString(ordinaryRule));
    }

    private FtbAttendanceDailyRule getFtbAttendanceDailyRule(FtbAttendanceDailyRule ordinaryRule, FtbAttendanceDailyRule rule) {
        if (rule.getIsInsert()) {
            rule = BeanUtil.toBean(rule, FtbAttendanceDailyRule.class);
            rule.setId(RandomUtil.uuId());
            rule.setSelfGroup(ordinaryRule.getSelfGroup());
            rule.setLeaveDay(BigDecimal.ZERO);
            rule.setPayrollHours(BigDecimal.ZERO);
        }
        rule.setApplyViewEnable(1);
        rule.setFixedMark(ordinaryRule.getFixedMark());
        rule.setBreakEnable(ordinaryRule.getBreakEnable());
        rule.setSchedulesType(ordinaryRule.getSchedulesType());
        rule.setShiftId(ordinaryRule.getShiftId());
        rule.setPeriodId(ordinaryRule.getPeriodId());
        rule.setInPoint(rule.getApplyStart());
        rule.setOutPoint(rule.getApplyEnd());
        rule.insertTrue();
        return rule;
    }

    private void houseLeaveDayProcess(FtbAttendanceDailyRule leaveRule, Integer validDuration, BigDecimal periodWorkDay, BigDecimal payrollHours) {
        leaveRule.calValidDuration();
        leaveRule.setLeaveDay(Objects.isNull(periodWorkDay) ? null : BigDecimal.valueOf(leaveRule.getValidDuration())
                .divide(BigDecimal.valueOf(validDuration), 4, RoundingMode.HALF_UP)
                .multiply(periodWorkDay).setScale(2, RoundingMode.HALF_UP));
        housePayrollHoursProcess(leaveRule, payrollHours, validDuration);
    }
    private void housePayrollHoursProcess(FtbAttendanceDailyRule leaveRule, BigDecimal payrollHours, Integer validDuration) {
        leaveRule.calValidDuration();
        leaveRule.setPayrollHours(Objects.isNull(payrollHours) ? null : BigDecimal.valueOf(leaveRule.getValidDuration())
                .divide(BigDecimal.valueOf(validDuration), 4, RoundingMode.HALF_UP)
                .multiply(payrollHours).setScale(2, RoundingMode.HALF_UP));
    }
    /**
     * 天、半天请假
     *
     * @param hisDailyRules
     * @param leaveRule
     * @param ordinaryRule
     * @param resultList
     */
    private void daysLeaveHandle(List<FtbAttendanceDailyRule> hisDailyRules, FtbAttendanceDailyRule leaveRule, FtbAttendanceDailyRule ordinaryRule, List<DailyRuleResultVo> resultList) {
        //同一请假申请保留一条请假记录
        if (Objects.isNull(leaveRule.getApplyUnit()) || Objects.equals(leaveRule.getApplyUnit(), LeaveUnitEnum.HOUR.getCode())) {
            return;
        }
        LeaveParam leaveParam = JsonUtil.getJsonToBean(leaveRule.getLeaveParam(), LeaveParam.class);
        //是否为半天假
        halfDayLeave(hisDailyRules, ordinaryRule, resultList, leaveRule, leaveParam);
        //全天请假
        dayLeave(hisDailyRules, ordinaryRule, resultList, leaveRule);
        //休息时间处理
        //如果开始时间处于休息时间中间，开始时间变更为休息时间的开始时间
        if (Objects.nonNull(ordinaryRule.getBreakStartPoint()) && DateDetail.checkTimeBetween(leaveRule.getInPoint(), ordinaryRule.getOriginBreakStartPoint(), ordinaryRule.getOriginBreakEndPoint())) {
            leaveRule.setInPoint(ordinaryRule.getOriginBreakStartPoint());
            leaveRule.setBreakStartPoint(ordinaryRule.getOriginBreakStartPoint());
            ordinaryRule.setOutPoint(ordinaryRule.getOriginBreakStartPoint());
            ordinaryRule.setBreakStartPoint(null);
            ordinaryRule.setBreakEndPoint(null);
            log.error("新增请假开始时间调整为休息开始时间{}", JSON.toJSONString(ordinaryRule.getOriginBreakStartPoint()));
        }
        //如果结束时间处理休息时间中间，结束时间变更为休息时间的结束时间
        if (Objects.nonNull(ordinaryRule.getBreakStartPoint()) && DateDetail.checkTimeBetween(leaveRule.getOutPoint(), ordinaryRule.getOriginBreakStartPoint(), ordinaryRule.getOriginBreakEndPoint())) {
            leaveRule.setOutPoint(ordinaryRule.getOriginBreakEndPoint());
            leaveRule.setBreakEndPoint(ordinaryRule.getOriginBreakEndPoint());
            ordinaryRule.setInPoint(ordinaryRule.getOriginBreakEndPoint());
            ordinaryRule.setBreakStartPoint(null);
            ordinaryRule.setBreakEndPoint(null);
            log.error("新增请假结束时间调整为休息结束时间{}", JSON.toJSONString(ordinaryRule.getOriginBreakEndPoint()));
        }

    }

    /**
     * 处理全天请假的逻辑
     *
     * @param hisDailyRules 历史每日规则列表
     * @param ordinaryRule  原有的每日规则
     * @param resultList    结果列表，用于存储处理结果
     * @param leaveRule     请假的每日规则
     */
    private void dayLeave(List<FtbAttendanceDailyRule> hisDailyRules, FtbAttendanceDailyRule ordinaryRule, List<DailyRuleResultVo> resultList, FtbAttendanceDailyRule leaveRule) {
        // 检查请假类型是否为全天
        if (!Objects.equals(leaveRule.getApplyUnit(), LeaveUnitEnum.DAY.getCode())) {
            return;
        }
        // 如果是插入操作，则直接返回
        if (leaveRule.getIsInsert()) {
            return;
        }
        //全天请假
        leaveRule = getFtbAttendanceDailyRule(ordinaryRule, leaveRule);
        hisDailyRules.remove(ordinaryRule);
        leaveRule.setInPoint(ordinaryRule.getInPoint());
        leaveRule.setOutPoint(ordinaryRule.getOutPoint());
        //如果为全天班，则请假时长为时段工时
        leaveRule.setLeaveDay(!Objects.equals(ordinaryRule.getSchedulesType(), 0) ? ordinaryRule.getPeriodWorkDay() : BigDecimal.ONE);
        leaveRule.setPayrollHours(ordinaryRule.getPayrollHours());
        if (!hisDailyRules.contains(leaveRule)) {
            hisDailyRules.add(leaveRule);
        }
        log.error("新增全天请假时间覆盖原来班时段{}", JSON.toJSONString(leaveRule));
        resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, leaveRule));
    }

    private void halfDayLeave(List<FtbAttendanceDailyRule> hisDailyRules, FtbAttendanceDailyRule ordinaryRule, List<DailyRuleResultVo> resultList, FtbAttendanceDailyRule leaveRule, LeaveParam leaveParam) {
        //是否为半天假
        if (!Objects.equals(leaveRule.getApplyUnit(), LeaveUnitEnum.HALF_DAY.getCode())) {
            return;
        }
        //划线排班，隐藏半天请假
        if (Objects.equals(ordinaryRule.getFixedMark(), 2)) {
            leaveRule.setApplyViewEnable(0);
            return;
        }
        if (isNotBetweenByHalfDayLeave(ordinaryRule, leaveParam)) {
            //完全没交集
            if (!hisDailyRules.contains(leaveRule)) {
                leaveRule.setApplyViewEnable(2);
                hisDailyRules.add(leaveRule);
            }
            if (!hisDailyRules.contains(ordinaryRule)) {
                hisDailyRules.add(ordinaryRule);
            }
            return;
        }
        leaveRule = getFtbAttendanceDailyRule(ordinaryRule, leaveRule);
        if (Objects.equals(ordinaryRule.getSchedulesType(), 0)) {
            Date leaveDate = getLeaveDate(ordinaryRule);
            boolean isMorningHalfDay = isHalfDayLeave(ordinaryRule, leaveParam, 1);
            boolean isAfternoonHalfDay = isHalfDayLeave(ordinaryRule, leaveParam, 2);
            //请假开始是否为上半天请假
            if (isMorningHalfDay && !isAfternoonHalfDay) {
                if (leaveDate.before(ordinaryRule.getInPoint())) {
                    return;
                }
                //请假开始时间为开始日期当天排班开始时间
                leaveRule.setInPoint(ordinaryRule.getOriginInPoint());
                leaveRule.setOutPoint(leaveDate);
                leaveRule.setSchedulesType(ordinaryRule.getSchedulesType());
                leaveRule.setLeaveDay(BigDecimal.valueOf(0.5));
                getBreakTimeByOrdinary(leaveRule,ordinaryRule);
                housePayrollHoursProcess(leaveRule, ordinaryRule.getPayrollHours(), ordinaryRule.getOriginValidDuration());
                if (leaveDate.compareTo(ordinaryRule.getInPoint()) == 0) {
                    log.error("新增下半天请假时间覆盖原来全天班时段{}", JSON.toJSONString(leaveRule));
                    if (!hisDailyRules.contains(leaveRule)) {
                        hisDailyRules.add(leaveRule);
                    }
                    resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, leaveRule));
                    hisDailyRules.remove(ordinaryRule);
                    return;
                }
                ordinaryRule.calInLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getInLackPoint(), leaveDate));
                ordinaryRule.calLatePoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getLatePoint(), leaveDate));
                ordinaryRule.setInPoint(leaveDate);
                ordinaryRule.setSchedulesType(2);
                ordinaryRule.setInUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
                housePayrollHoursProcess(ordinaryRule, ordinaryRule.getPayrollHours(), ordinaryRule.getOriginValidDuration());
                log.error("新增全天班时段时间覆盖原来上半天请假{}", JSON.toJSONString(leaveRule));
                if (!hisDailyRules.contains(leaveRule)) {
                    hisDailyRules.add(leaveRule);
                }
                if (!hisDailyRules.contains(ordinaryRule)) {
                    hisDailyRules.add(ordinaryRule);
                }
                resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, leaveRule));
                //请假开始是否为下半天请假
            } else if (!isMorningHalfDay && isAfternoonHalfDay) {
                if (leaveDate.after(ordinaryRule.getOutPoint())) {
                    return;
                }
                leaveRule.setInPoint(leaveDate);
                leaveRule.setSchedulesType(ordinaryRule.getSchedulesType());
                leaveRule.setOutPoint(ordinaryRule.getOriginOutPoint());
                leaveRule.setLeaveDay(BigDecimal.valueOf(0.5));
                getBreakTimeByOrdinary(leaveRule,ordinaryRule);
                housePayrollHoursProcess(leaveRule, ordinaryRule.getPayrollHours(), ordinaryRule.getOriginValidDuration());
                if (leaveDate.compareTo(ordinaryRule.getInPoint()) == 0) {
                    log.error("新增下半天请假时间覆盖原来全天班时段{}", JSON.toJSONString(leaveRule));
                    if (!hisDailyRules.contains(leaveRule)) {
                        hisDailyRules.add(leaveRule);
                    }
                    resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, leaveRule));
                    hisDailyRules.remove(ordinaryRule);
                    return;
                }
                ordinaryRule.setEarlyPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getOutPoint(), ordinaryRule.getEarlyPoint(), leaveDate));
                ordinaryRule.setOutLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getOutPoint(), ordinaryRule.getOutLackPoint(), leaveDate));
                ordinaryRule.setOutPoint(leaveDate);
                ordinaryRule.setOutUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
                ordinaryRule.setSchedulesType(1);
                housePayrollHoursProcess(ordinaryRule, ordinaryRule.getPayrollHours(), ordinaryRule.getOriginValidDuration());
                log.error("新增全天班时段覆盖原来下半天请假时间{}", JSON.toJSONString(leaveRule));
                if (!hisDailyRules.contains(leaveRule)) {
                    hisDailyRules.add(leaveRule);
                }
                if (!hisDailyRules.contains(ordinaryRule)) {
                    hisDailyRules.add(ordinaryRule);
                }
                resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, leaveRule));
            } else {
                //请假两个半天，隐藏全天班
                leaveRule.setInPoint(ordinaryRule.getInPoint());
                leaveRule.setOutPoint(ordinaryRule.getOutPoint());
                leaveRule.setSchedulesType(ordinaryRule.getSchedulesType());
                leaveRule.setLeaveDay(BigDecimal.ONE);
                housePayrollHoursProcess(leaveRule, ordinaryRule.getPayrollHours(), ordinaryRule.getOriginValidDuration());
                hisDailyRules.removeIf(rule -> StringUtil.equals(rule.getId(), ordinaryRule.getId()));
                if (!hisDailyRules.contains(leaveRule)) {
                    hisDailyRules.add(leaveRule);
                }
                if (!hisDailyRules.contains(ordinaryRule)) {
                    ordinaryRule.setApplyViewEnable(0);
                    hisDailyRules.add(ordinaryRule);
                }
                resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, leaveRule));
                log.error("新增全天班完全覆盖请假时间{}", JSON.toJSONString(ordinaryRule));
            }
            return;
        }
        //如果为半天班，每个上下班只保留一条
        if (!Objects.equals(ordinaryRule.getSchedulesType(), leaveRule.getSchedulesType())) {
            return;
        }
        //请假开始时间为开始日期当天排班开始时间
        leaveRule.setInPoint(ordinaryRule.getInPoint());
        leaveRule.setOutPoint(ordinaryRule.getOutPoint());
        leaveRule.setSchedulesType(ordinaryRule.getSchedulesType());
        leaveRule.setLeaveDay(BigDecimal.valueOf(0.5));
        leaveRule.setPayrollHours(ordinaryRule.getPayrollHours());
        getBreakTimeByOrdinary(leaveRule, ordinaryRule);
        hisDailyRules.removeIf(rule -> StringUtil.equals(rule.getId(), ordinaryRule.getId()));
        if (!hisDailyRules.contains(leaveRule)) {
            hisDailyRules.add(leaveRule);
        }
        ordinaryRule.insertTrue();
        log.error("新增半天班时段覆盖原来半天请假时间{}", JSON.toJSONString(leaveRule));
        resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, leaveRule));

    }

    // 提取辅助方法，减少重复逻辑
    private boolean isHalfDayLeave(FtbAttendanceDailyRule oldRule, LeaveParam leaveParam, int timeType) {
        // 开始日期且时间类型匹配
        boolean isStartDateMatch = Objects.equals(leaveParam.getStartTimeType(), timeType) &&
                oldRule.getDay().compareTo(leaveParam.getStart()) == 0;

        // 中间日期
        boolean isMiddleDate = (Objects.equals(timeType, 2) || oldRule.getDay().after(leaveParam.getStart())) &&
                (Objects.equals(timeType, 1) || oldRule.getDay().before(leaveParam.getEnd()));

        // 结束日期且时间类型匹配
        boolean isEndDateMatch = Objects.equals(leaveParam.getEndTimeType(), timeType) &&
                oldRule.getDay().compareTo(leaveParam.getEnd()) == 0;

        return isStartDateMatch || isMiddleDate || isEndDateMatch;
    }

    /**
     * 是否不属于半天、全天假范围内
     *
     * @param oldRule2
     * @param leaveParam
     * @return
     */
    private static boolean isNotBetweenByHalfDayLeave(FtbAttendanceDailyRule oldRule2, LeaveParam leaveParam) {
        return !DateDetail.checkTimeBetween(oldRule2.getDay(), leaveParam.getStart(), leaveParam.getEnd())
                || !Objects.equals(oldRule2.getSchedulesType(), 0) && leaveParam.getStartTimeType() > oldRule2.getSchedulesType() && oldRule2.getDay().compareTo(leaveParam.getStart()) == 0
                || !Objects.equals(oldRule2.getSchedulesType(), 0) && leaveParam.getEndTimeType() < oldRule2.getSchedulesType() && oldRule2.getDay().compareTo(leaveParam.getEnd()) == 0;
    }

    /**
     * 计算半天请假全天班中间临界请假时间
     *
     * @param ftbAttendanceDailyRule
     * @return
     */
    private Date getLeaveDate(FtbAttendanceDailyRule ftbAttendanceDailyRule) {
        int ruleMinute = DateDetail.calculateMinuteDiff(ftbAttendanceDailyRule.getOriginInPoint(), ftbAttendanceDailyRule.getOriginOutPoint());
        return cn.hutool.core.date.DateUtil.offsetMinute(ftbAttendanceDailyRule.getOriginInPoint(), ruleMinute / 2);
    }

    /**
     * 计算请假天数
     *
     * @param ordinaryRule
     * @param leaveRule
     */
    private void leaveDaysProcess(FtbAttendanceDailyRule ordinaryRule, FtbAttendanceDailyRule leaveRule) {
        //查询是否为全天班
        boolean isFullDay = Objects.equals(ordinaryRule.getSchedulesType(), 0);
        //是否为半天请假
        if (Objects.equals(leaveRule.getApplyUnit(), 3)) {
            //如果为全天班且当天请假时长为多个半天则设置为1
            if (isFullDay && leaveRule.getLeaveDay().compareTo(BigDecimal.valueOf(0.5)) > 0) {
                leaveRule.setLeaveDay(BigDecimal.ONE);
                leaveRule.setPayrollHours(ordinaryRule.getPayrollHours());
            } else {
                leaveRule.setLeaveDay(ordinaryRule.getPeriodWorkDay());
                leaveRule.setPayrollHours(ordinaryRule.getPayrollHours());
            }
        }
        //是否为全天请假
        if (Objects.equals(leaveRule.getApplyUnit(), 2)) {
            leaveRule.setLeaveDay(BigDecimal.ONE);
            if (!isFullDay) {
                //如果为半天班且班次数量大于1则设置为0.5
                leaveRule.setLeaveDay(ordinaryRule.getPeriodWorkDay());
                leaveRule.setPayrollHours(ordinaryRule.getPayrollHours());
            }
        }
    }

    /**
     * 新增排班的休息时间处理
     *
     * @param leaveRule 原请假规则
     * @param ordinaryRule    新增正常排班规则
     */
    private void getBreakTimeByOrdinary(FtbAttendanceDailyRule leaveRule, FtbAttendanceDailyRule ordinaryRule) {
        leaveRule.insertTrue();
        if (!Objects.equals(ordinaryRule.getBreakEnable(), 1) || Objects.isNull(ordinaryRule.getBreakStartPoint())) {
            return;
        }
        leaveRule.setBreakStartPoint(leaveRule.getInPoint().after(ordinaryRule.getBreakEndPoint())|| leaveRule.getOutPoint().before(ordinaryRule.getBreakStartPoint()) ? null : leaveRule.getInPoint().after(ordinaryRule.getBreakStartPoint()) ? leaveRule.getInPoint() : ordinaryRule.getBreakStartPoint());
        leaveRule.setBreakEndPoint(leaveRule.getInPoint().after(ordinaryRule.getBreakEndPoint()) || leaveRule.getOutPoint().before(ordinaryRule.getBreakStartPoint()) ? null : leaveRule.getOutPoint().before(ordinaryRule.getBreakEndPoint()) ? leaveRule.getOutPoint() : ordinaryRule.getBreakEndPoint());
        //休息结束时间小于排班上班时间，或者休息开始时间大于排班下班时间
        if (ordinaryRule.getBreakEndPoint().compareTo(ordinaryRule.getInPoint()) <= 0 || ordinaryRule.getBreakStartPoint().compareTo(ordinaryRule.getOutPoint()) >= 0) {
            ordinaryRule.setBreakStartPoint(null);
            ordinaryRule.setBreakEndPoint(null);
            ordinaryRule.setBreakEnable(0);
            return;
        }
        //请假时间完全覆盖原来休息时段
        if (DateDetail.checkTimeBetween(ordinaryRule.getBreakStartPoint(), leaveRule.getApplyStart(), leaveRule.getApplyEnd())
                && DateDetail.checkTimeBetween(ordinaryRule.getBreakEndPoint(), leaveRule.getApplyStart(), leaveRule.getApplyEnd())) {
            ordinaryRule.setBreakStartPoint(null);
            ordinaryRule.setBreakEndPoint(null);
            ordinaryRule.setBreakEnable(0);
            return;
        }
        //休息时间完全覆盖请假时间
        if (DateDetail.checkTimeBetween(leaveRule.getApplyStart(), ordinaryRule.getBreakStartPoint(), ordinaryRule.getBreakEndPoint())
                && DateDetail.checkTimeBetween(leaveRule.getApplyEnd(), ordinaryRule.getBreakStartPoint(), ordinaryRule.getBreakEndPoint())) {
            if (leaveRule.getApplyStart().compareTo(ordinaryRule.getBreakStartPoint()) >= 0) {
                ordinaryRule.setBreakEndPoint(leaveRule.getApplyStart());
                leaveRule.setBreakStartPoint(leaveRule.getApplyStart());
            }
            if (leaveRule.getApplyEnd().compareTo(ordinaryRule.getBreakEndPoint()) <= 0) {
                leaveRule.setBreakEndPoint(leaveRule.getApplyEnd());
                ordinaryRule.setBreakEndPoint(leaveRule.getApplyEnd());
            }
            return;
        }
        //部分覆盖
        //开始部分覆盖
        if (DateDetail.checkTimeBetween(leaveRule.getApplyEnd(), ordinaryRule.getBreakStartPoint(), ordinaryRule.getBreakEndPoint())) {
            leaveRule.setBreakEndPoint(leaveRule.getApplyEnd());
            ordinaryRule.setBreakStartPoint(leaveRule.getApplyEnd());
            return;
        }
        //结束部分覆盖
        if (DateDetail.checkTimeBetween(leaveRule.getApplyStart(), ordinaryRule.getBreakStartPoint(), ordinaryRule.getBreakEndPoint())) {
            ordinaryRule.setBreakEndPoint(leaveRule.getApplyStart());
            leaveRule.setBreakStartPoint(leaveRule.getApplyStart());
            return;
        }
    }

    /**
     * 新增排休
     *
     * @param hisDailyRules           历史规则
     * @param ftbAttendanceDailyRules 新增规则集合
     * @param rule                    当前规则
     */
    private Boolean restHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
        //新增排休
        if (!Objects.equals(AttendanceTypeEnum.REST.getCode(), rule.getAttendanceType())
                && !Objects.equals(AttendanceTypeEnum.DEDUCTION_HOLIDAYS.getCode(), rule.getAttendanceType())
                && !Objects.equals(AttendanceTypeEnum.EXCHANGE_HOLIDAYS.getCode(), rule.getAttendanceType())) {
            return Boolean.FALSE;
        }
        ftbAttendanceDailyRules.forEach(oldRule -> {
            //新加入数据不做处理
            if (oldRule.getIsInsert()) {
                return;
            }
            rule.setShiftId(oldRule.getShiftId());
            rule.setPeriodId(oldRule.getPeriodId());
            if (Objects.nonNull(rule.getOutPoint()) && (rule.getOutPoint().before(oldRule.getInPoint()) || oldRule.getInPoint().before(rule.getOutPoint()))) {
                //完全没交集
                rule.insertTrue();
                hisDailyRules.add(rule);
                log.error("新增排休与原来请假时段完全没交集{}", JSON.toJSONString(rule));
                resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
                return;
            }
            log.error(AttendanceConstant.getSchedulingResult(rule.getUserId(), rule.getDay(), AttendanceConstant.LEAVE, AttendanceTypeEnum.getMsg(rule.getAttendanceType())));
            resultList.add(DailyRuleResultVo.build(rule, AttendanceTypeEnum.LEAVE.getCode(), rule.getAttendanceType(), oldRule.getFixedMark()));
        });
        return Boolean.TRUE;
    }

    /**
     * 新增加班
     *
     * @param hisDailyRules           历史规则
     * @param ftbAttendanceDailyRules 新增规则集合
     * @param rule                    当前规则
     */
    private Boolean workOvertimeHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
        //新增加班
        if (!Objects.equals(AttendanceTypeEnum.WORKOVERTIME.getCode(), rule.getAttendanceType())) {
            return Boolean.FALSE;
        }
        ftbAttendanceDailyRules.forEach(oldRule -> {
            //新加入数据不做处理
            if (oldRule.getIsInsert()) {
                return;
            }
            rule.setShiftId(oldRule.getShiftId());
            rule.setPeriodId(oldRule.getPeriodId());
            //完全覆盖
            //加班时间完全覆盖原来请假时段
            if (DateDetail.checkTimeBetween(oldRule.getInPoint(), rule.getInPoint(), rule.getOutPoint())
                    && DateDetail.checkTimeBetween(oldRule.getOutPoint(), rule.getInPoint(), rule.getOutPoint())) {
                oldRule.setInPoint(oldRule.getApplyStart());
                oldRule.setOutPoint(oldRule.getApplyEnd());
                oldRule.setApplyViewEnable(0);
                if (!hisDailyRules.contains(rule)) {
                    rule.insertTrue();
                    hisDailyRules.add(rule);
                }
                log.error("新增加班时间完全覆盖原来请假时段{}", JSON.toJSONString(rule));
                resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
                return;
            }
            //部分覆盖
            //开始部分覆盖
            if (DateDetail.checkTimeBetweenR(rule.getOutPoint(), oldRule.getInPoint(), oldRule.getOutPoint())) {
                oldRule.setInPoint(rule.getApplyEnd());
                oldRule.setApplyViewEnable(1);
                if (!hisDailyRules.contains(rule)) {
                    rule.insertTrue();
                    hisDailyRules.add(rule);
                }
                log.error("新增加班时间完全开始部分覆盖原来请假时段{}", JSON.toJSONString(rule));
                resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
                return;
            }
            //结束部分覆盖
            if (DateDetail.checkTimeBetweenL(rule.getInPoint(), oldRule.getInPoint(), oldRule.getOutPoint())) {
                oldRule.setOutPoint(rule.getApplyStart());
                rule.setApplyViewEnable(1);
                if (!hisDailyRules.contains(rule)) {
                    rule.insertTrue();
                    hisDailyRules.add(rule);
                }
                log.error("新增加班时间完全结束部分覆盖原来请假时段{}", JSON.toJSONString(rule));
                resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
                return;
            }
            //请假完全覆盖加班
            if (DateDetail.checkTimeBetween(rule.getInPoint(), oldRule.getInPoint(), oldRule.getOutPoint())
                    && DateDetail.checkTimeBetween(rule.getOutPoint(), oldRule.getInPoint(), oldRule.getOutPoint())) {
                FtbAttendanceDailyRule oldRule1 = BeanUtil.toBean(oldRule, FtbAttendanceDailyRule.class);
                oldRule.setOutPoint(rule.getApplyStart());
                oldRule1.setInPoint(rule.getApplyEnd());
                oldRule1.setId(RandomUtil.uuId());
                oldRule1.setApplyViewEnable(1);
                oldRule1.insertTrue();
                hisDailyRules.add(oldRule1);
                if (!hisDailyRules.contains(rule)) {
                    rule.insertTrue();
                    hisDailyRules.add(rule);
                }
                log.error("原来请假时段完全覆盖新增加班时间{}", JSON.toJSONString(rule));
                resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
                return;
            }
            //完全没交集
            if (!hisDailyRules.contains(rule)) {
                rule.insertTrue();
                hisDailyRules.add(rule);
            }
            log.error("新增加班时间与原来请假时段完全没交集{}", JSON.toJSONString(rule));
            resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
        });
        return Boolean.TRUE;
    }

}
