package jnpf.attendance.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Maps;
import jnpf.attendance.mapper.AttendanceFixedClassMapper;
import jnpf.attendance.mapper.AttendanceGroupMapper;
import jnpf.attendance.mapper.AttendanceQuickTemplateMapper;
import jnpf.attendance.mapper.AttendanceShiftNameSettingMapper;
import jnpf.attendance.service.*;
import jnpf.base.ActionResult;
import jnpf.base.UserInfo;
import jnpf.base.service.SuperServiceImpl;
import jnpf.entity.AttendanceGroup;
import jnpf.entity.attendance.AttendanceFixedClassEntity;
import jnpf.entity.attendance.AttendanceShiftNameEntity;
import jnpf.entity.attendance.AttendanceShiftSettingEntity;
import jnpf.entity.attendance.AttendanceShiftSettingPeriodEntity;
import jnpf.enums.attendance.CautionEnum;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.*;
import jnpf.model.attendance.vo.AttendanceShiftSettingPeriodVo;
import jnpf.model.attendance.vo.AttendanceShiftSettingVo;
import jnpf.model.attendance.vo.SecondmentDateVo;
import jnpf.model.attendance.vo.attendance.FixedClassShiftVo;
import jnpf.model.attendance.vo.attendance.QuickTemVo;
import jnpf.model.attendance.vo.attendance.ShiftNameListVo;
import jnpf.model.attendance.vo.attendance.ShiftNameVo;
import jnpf.util.*;
import jnpf.util.context.ThreadContext;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import static jnpf.constants.RedisConstant.*;

/**
 * @Author huanglinpan
 * @Date 2024/5/9 10:06
 * @Version 1.0 （版本号）
 */
@Service
public class AttendanceShiftNameSettingServiceImpl extends SuperServiceImpl<AttendanceShiftNameSettingMapper, AttendanceShiftNameEntity> implements AttendanceShiftNameSettingService {


    @Resource
    private ThreadPoolExecutor attendanceRuleThreadPool;
    @Resource
    private ThreadPoolExecutor cpuIntensiveThreadPool;
    @Resource
    private AttendanceShiftNameSettingMapper attendanceShiftNameSettingMapper;
    @Autowired
    private AttendanceShiftSettingPeriodService attendanceShiftSettingPeriodService;
    @Resource
    private AttendanceFixedClassMapper attendanceFixedClassMapper;
    @Autowired
    private AttendanceShiftSettingService attendanceShiftSettingService;
    @Autowired
    private AttendanceGroupService attendeesGroupService;
    @Autowired
    private AttendanceDailyRuleService attendanceDailyRuleService;
    @Resource
    private AttendanceGroupMapper attendanceGroupMapper;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private AttendanceFixedClassService attendanceFixedClassService;
    @Autowired
    private AttendanceQuickTemplateService attendanceQuickTemplateService;
    @Resource
    private AttendanceQuickTemplateMapper attendanceQuickTemplateMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ActionResult save(ShiftNameDto dto) {
        RLock lock = redissonClient.getLock(String.format(ATTENDANCE_UPDATE_SHIFT_CONFIG, UserProvider.getUser().getTenantId(), dto.getGroupId()));
        Assert.isFalse(lock.isLocked(), "当前考勤组班次信息正在变更中，请稍后再试");
        try {
            Assert.isFalse(!lock.tryLock(5, 5, TimeUnit.SECONDS), "当前考勤组班次信息正在变更中，请稍后再试");
            UserInfo user = UserProvider.getUser();
            dto.setUserId(user.getUserId());
            AttendanceShiftSettingVo allByGroupId = attendanceShiftSettingService.findAllByGroupId(dto.getGroupId());
            if (Objects.isNull(allByGroupId)) {
                attendanceShiftSettingService.save(AttendanceShiftSettingEntity.builder().groupId(dto.getGroupId()).systemType(2).enable(1).id(RandomUtil.uuId()).enableTime(new Date()).creatorTime(new Date()).creatorUserId(user.getUserId()).build());
            }
            // 校验名称不能重复
            Integer num = attendanceShiftNameSettingMapper.checkName(dto);
            Assert.isFalse(num > 0, "班次名称不能重复");
            // 设置班制：1 全天制 2半天制
            dto.setShiftType((null == dto.getPeriods() || dto.getPeriods().size() < 2) ? 1 : 2);
            if (null == dto.getId() || dto.getId().isEmpty()) {
                // 新增班次名称信息
                dto.setId(FtbUtil.getId());
                attendanceShiftNameSettingMapper.save(dto);
            } else {
                // 保存班次名称信息
                attendanceShiftNameSettingMapper.update(dto);
                // 先删除原来的关联班次时段信息
                attendanceShiftNameSettingMapper.deletePeriodByShiftId(dto.getId());
            }
            if (CollUtil.isEmpty(dto.getPeriods())) {
                return ActionResult.success();
            }
            // 保存时段信息
            List<AttendanceShiftSettingPeriodEntity> periodEntities = BeanUtil.copyToList(dto.getPeriods(), AttendanceShiftSettingPeriodEntity.class);
            // 时段交叉校验 9:00 -- 18:00    10:00 -- 19:00
            Assert.isTrue(fixedPeriodConflict(periodEntities), "班次时段存在交叉");
            periodEntities.forEach(v -> {
                v.setShiftId(dto.getId());
                v.setLateEnable(1);
            });
            if (periodEntities.size() > 1) {
                AttendanceShiftSettingPeriodEntity oneEntity = periodEntities.get(0);
                AttendanceShiftSettingPeriodEntity twoEntity = periodEntities.get(1);
                // 上班开始时间在前面的排第一
                Date date = new Date();
                Date oneTime = DateDetail.getDateByPoint(date, oneEntity.getInPoint(), oneEntity.getInType());
                Date twoTime = DateDetail.getDateByPoint(date, twoEntity.getInPoint(), twoEntity.getInType());
                if (oneTime != null) {
                    oneEntity.setType(oneTime.before(twoTime) ? 1 : 2);
                }
                if (twoTime != null) {
                    twoEntity.setType(twoTime.before(oneTime) ? 1 : 2);
                }
                Assert.isFalse(check24H(periodEntities), "下班时间不可超过上班时间的24小时");
            }
            // 保存
            attendanceShiftSettingPeriodService.saveOrUpdateBatch(periodEntities);
            Boolean isConflict = fixedConfigPeriodConflict(dto.getGroupId(), dto.getId());
            // 固定班次排班冲突校验
            List<String> enableGroupIds = attendeesGroupService.getEnableGroupIds(dto.getGroupId());
            enableGroupIds.remove(dto.getGroupId());
            try {
                Integer result = attendanceDailyRuleService.setSchedulesForShiftConfigUpdate(dto.getGroupId(), dto.getMark(), periodEntities.stream().map(period -> PeriodConfig.builder().shiftId(period.getShiftId()).type(Objects.isNull(period.getType()) ? 0 : period.getType()).build()).collect(Collectors.toList()), periodEntities);
                if (Objects.nonNull(allByGroupId) && Objects.equals(allByGroupId.getSystemType(), 1) && !isConflict) {
                    result = CautionEnum.Caution_202.getCode();
                }
                adjustmentOfSubordinateScheduling(enableGroupIds, dto, periodEntities);
                return ActionResult.success(result);
            } catch (HandleException e) {
                throw new RuntimeException("变更排班规则失败！");
            }

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
    }

    private void adjustmentOfSubordinateScheduling(List<String> enableGroupIds, ShiftNameDto dto, List<AttendanceShiftSettingPeriodEntity> periodEntities) {
        CompletableFuture.runAsync(ThreadContext.wrap(() -> {

            for (String groupId : enableGroupIds) {
                try {
                    attendanceDailyRuleService.setSchedulesForShiftConfigUpdate(groupId, dto.getMark(), periodEntities.stream().map(period -> PeriodConfig.builder().shiftId(period.getShiftId()).type(Objects.isNull(period.getType()) ? 0 : period.getType()).build()).collect(Collectors.toList()), periodEntities);
                } catch (HandleException e) {
                    throw new RuntimeException(e);
                }
            }
            // 快捷班次排班冲突校验
            quickTemplatePeriodConflict(dto.getGroupId(), dto.getId());
            for (String groupId : enableGroupIds) {
                quickTemplatePeriodConflict(groupId, dto.getId());
            }
        }), attendanceRuleThreadPool);
    }

    private Boolean check24H(List<AttendanceShiftSettingPeriodEntity> periodEntities) {
        // 一个时段的时候不可能超过24小时不做校验 校验上班时间不超过24小时 规则:第二个时段的下班时间有没有超过第一个上班时间的24小时    并校验  下班时间不可超过上班时间的24小时！
        // 9:00 -- 18:00    19:00 -- 次日 9:59
        Date date = new Date();
        AttendanceShiftSettingPeriodEntity upEntity = periodEntities.stream().filter(entity -> 1 == entity.getType()).findFirst().orElse(null);
        AttendanceShiftSettingPeriodEntity downEntity = periodEntities.stream().filter(entity -> 2 == entity.getType()).findFirst().orElse(null);
        Date inPoint = DateDetail.getDateByPoint(date, Objects.requireNonNull(upEntity).getInPoint(), upEntity.getOutType());
        Date outPoint = DateDetail.getDateByPoint(date, Objects.requireNonNull(downEntity).getOutPoint(), downEntity.getOutType());
        if (Objects.requireNonNull(outPoint).getTime() - Objects.requireNonNull(inPoint).getTime() > 86400000L) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    private void quickTemplatePeriodConflict(String groupId, String shiftId) {
        List<QuickTemVo> quickTemVos = attendanceQuickTemplateService.findNewList(groupId);
        if (CollUtil.isEmpty(quickTemVos)) {
            return;
        }
        List<SecondmentDateVo> list = CollUtil.newArrayList();
        for (QuickTemVo quickTemVo : quickTemVos) {
            Date date = new Date();
            int index = 0;
            if (CollUtil.isEmpty(quickTemVo.getList())) {
                continue;
            }
            for (FixedClassShiftVo fixedClassShiftVo : quickTemVo.getList()) {
                List<ShiftNameVo> shiftNameVos = fixedClassShiftVo.getShiftNameVos();
                DateTime dateTime = cn.hutool.core.date.DateUtil.offsetDay(date, ++index);
                boolean isConflictItem = shiftNameVos.stream().anyMatch(shiftNameVo -> Objects.isNull(shiftNameVo) || Objects.isNull(shiftNameVo.getPeriods()) ? Boolean.FALSE : shiftNameVo.getPeriods().stream().anyMatch(period -> !fixedPeriodSingleConflict(dateTime, list, period)));
                if (isConflictItem) {
                    attendanceQuickTemplateMapper.deleteTemplateItem(quickTemVo.getId(), shiftId, List.of(index, index - 1));
                }
            }
        }
    }

    /**
     * 冲突清除固定班配置数据
     * <p>根据考勤组配置检查固定班次排班周期冲突，自动清理无冲突的排班记录</p>
     *
     * @param groupId 考勤组ID（用于关联考勤班次配置）
     * @return Boolean 冲突状态检查结果：
     * TRUE-存在冲突或配置为空（默认状态）
     * FALSE-检测到无冲突配置并执行了清理操作
     */
    private Boolean fixedConfigPeriodConflict(String groupId, String shiftId) {
        // 获取考勤班次配置基础数据
        AttendanceShiftSettingVo setting = attendanceShiftSettingService.findByGroupId(groupId);
        if (setting == null || CollUtil.isEmpty(setting.getFixedPeriods()) || StringUtil.isEmpty(shiftId)) {
            return Boolean.TRUE;
        }
        List<FixedClassShiftVo> fixedPeriods = setting.getFixedPeriods();

        // 初始化排班日期比对容器
        List<SecondmentDateVo> list = CollUtil.newArrayList();
        Date date = new Date();
        int index = 0;
        boolean isConflict = Boolean.TRUE;

        /* 遍历处理每个固定周期配置 */
        for (FixedClassShiftVo period : fixedPeriods) {
            // 生成偏移日期：按索引递增天数偏移基准日期
            DateTime dateTime = cn.hutool.core.date.DateUtil.offsetDay(date, ++index);

            /* 冲突检测逻辑：
               1. 获取当前周期的所有班次配置
               2. 检查是否存在与历史排班冲突的班次
               3. 有冲突班次时执行清理操作 */
            List<ShiftNameVo> shiftNameVos = period.getShiftNameVos();
            boolean isConflictItem = shiftNameVos.stream().anyMatch(
                    shiftNameVo -> Objects.isNull(shiftNameVo) || Objects.isNull(shiftNameVo.getPeriods()) ? Boolean.FALSE : shiftNameVo.getPeriods().stream().anyMatch(period1 -> !fixedPeriodSingleConflict(dateTime, list, period1)));

            // 有冲突时清理对应排班记录
            if (isConflictItem) {
                attendanceFixedClassService.update(new LambdaUpdateWrapper<AttendanceFixedClassEntity>()
                        .set(AttendanceFixedClassEntity::getShiftNameId, null)
                        .set(AttendanceFixedClassEntity::getType, 0)
                        .in(AttendanceFixedClassEntity::getNum, index, index - 1)
                        .eq(AttendanceFixedClassEntity::getShiftNameId, shiftId)
                        .eq(AttendanceFixedClassEntity::getGroupId, groupId));
                isConflict = Boolean.FALSE;
            }
        }
        return isConflict;
    }


    private Boolean fixedPeriodConflict(List<AttendanceShiftSettingPeriodEntity> periodEntities) {

        List<SecondmentDateVo> list = CollUtil.newArrayList();
        for (AttendanceShiftSettingPeriodEntity period : periodEntities) {
            if (!fixedPeriodSingleConflict(list, period)) {
                return Boolean.FALSE;
            }
        }
        return Boolean.TRUE;
    }

    @Override
    public Boolean fixedPeriodSingleConflict(Date date, List<SecondmentDateVo> list, AttendanceShiftSettingPeriodVo period) {
        Date inPoint = DateDetail.getDateByPoint(date, period.getInPoint(), period.getInType());
        Date outPoint = DateDetail.getDateByPoint(date, period.getOutPoint(), period.getOutType());
        if (CollUtil.isEmpty(list)) {
            list.add(SecondmentDateVo.builder().startTime(inPoint).endTime(outPoint).build());
            return Boolean.TRUE;
        }
        for (SecondmentDateVo vo : list) {
            if (DateDetail.checkTimeBetween(inPoint, vo.getStartTime(), vo.getEndTime()) || DateDetail.checkTimeBetween(Objects.requireNonNull(outPoint), vo.getStartTime(), vo.getEndTime()) || DateDetail.checkTimeBetween(vo.getStartTime(), inPoint, outPoint) || DateDetail.checkTimeBetween(vo.getEndTime(), inPoint, outPoint)) {
                return Boolean.FALSE;
            }
        }
        list.add(SecondmentDateVo.builder().startTime(inPoint).endTime(outPoint).build());
        return Boolean.TRUE;
    }

    private Boolean fixedPeriodSingleConflict(List<SecondmentDateVo> list, AttendanceShiftSettingPeriodEntity period) {
        Date date = new Date();
        Date inPoint = DateDetail.getDateByPoint(date, period.getInPoint(), period.getInType());
        Date outPoint = DateDetail.getDateByPoint(date, period.getOutPoint(), period.getOutType());
        if (CollUtil.isEmpty(list)) {
            list.add(SecondmentDateVo.builder().startTime(inPoint).endTime(outPoint).build());
            return Boolean.TRUE;
        }
        for (SecondmentDateVo vo : list) {
            if (DateDetail.checkTimeBetween(inPoint, vo.getStartTime(), vo.getEndTime()) || DateDetail.checkTimeBetween(Objects.requireNonNull(outPoint), vo.getStartTime(), vo.getEndTime()) || DateDetail.checkTimeBetween(vo.getStartTime(), inPoint, outPoint) || DateDetail.checkTimeBetween(vo.getEndTime(), inPoint, outPoint)) {
                return Boolean.FALSE;
            }
        }
        list.add(SecondmentDateVo.builder().startTime(inPoint).endTime(outPoint).build());
        return Boolean.TRUE;
    }

    /**
     * 启停班次
     *
     * @param shiftNameId 班次名称Id
     * @param enable      状态（1启用 2停用）
     * @param updateShift 是否修改之前班次（1 ： 保持之前班次 2：修改之前的班次）
     */
    @Override
    public ActionResult changeStatus(String shiftNameId, Integer enable, Integer updateShift) {
        AttendanceShiftNameEntity byId = getById(shiftNameId);
        RLock lock = redissonClient.getLock(String.format(ATTENDANCE_CHANGE_SHIFT_STATUS, UserProvider.getUser().getTenantId(), byId.getGroupId()));
        Assert.isFalse(lock.isLocked(), "当前考勤组启停班次操作正在执行中，请稍后再试");
        try {
            if(lock.tryLock(10, 60, TimeUnit.SECONDS)){

            }
            String userId = UserProvider.getUser().getUserId();
            // 修改班次的启停标识
            attendanceShiftNameSettingMapper.updateEnable(shiftNameId, enable, userId);
            //固定班变更
            if (1 == enable && 2 == updateShift) {
                fixedPeriodChange(byId.getGroupId());
            }
            return ActionResult.success();
        } catch (InterruptedException e) {
            return ActionResult.fail("当前考勤组启停班次操作正在执行中，请稍后再试");
        } finally {
            if(lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    private void fixedPeriodChange(String groupId) {
        CompletableFuture.runAsync(ThreadContext.wrap(() -> {
            // 变更现有排班规则
            attendanceDailyRuleService.fixedPeriodChange(attendeesGroupService.getEnableGroupIds(groupId), attendanceShiftSettingService.findByGroupId(groupId), DateUtil.getDayBegin());
        }), cpuIntensiveThreadPool);
    }

    @Override
    public ActionResult delete(String shiftNameId) {
        String userId = UserProvider.getUser().getUserId();
        //  校验当前班次是否正在使用  快速模板   固定排班  用户排班
        Integer fixedNum = attendanceFixedClassMapper.getUseBYShiftNameId(shiftNameId);
        if (fixedNum > 0) {
            return ActionResult.fail("该班次正在被固定排班使用不可删除！");
        }
        Integer ruleNum = attendanceFixedClassMapper.getRuleUseBYShiftNameId(shiftNameId);
        if (ruleNum > 0) {
            return ActionResult.fail("该班次正在被排班使用不可删除！");
        }
        Integer quickNum = attendanceFixedClassMapper.getQuickUseBYShiftNameId(shiftNameId);
        if (quickNum > 0) {
            return ActionResult.fail("该班次正在被快速排班使用不可删除！");
        }
        attendanceShiftNameSettingMapper.delete(shiftNameId, userId);
        return ActionResult.success();
    }

    @Override
    public ShiftNameVo getDetail(String shiftNameId) {
        ShiftNameVo shiftNameVo = attendanceShiftNameSettingMapper.getDetail(shiftNameId);
        // 组装时间段
        List<AttendanceShiftSettingPeriodEntity> list = attendanceShiftSettingPeriodService.list(new LambdaQueryWrapper<AttendanceShiftSettingPeriodEntity>().in(AttendanceShiftSettingPeriodEntity::getShiftId, shiftNameId).eq(AttendanceShiftSettingPeriodEntity::getDeleteMark, Boolean.FALSE));
        List<AttendanceShiftSettingPeriodVo> periodEntities = BeanUtil.copyToList(list, AttendanceShiftSettingPeriodVo.class);
        shiftNameVo.setPeriods(periodEntities);
        return shiftNameVo;
    }

    @Override
    public Map<String, ShiftNameVo> getDetailList(List<String> shiftIds) {
        Map<String, ShiftNameVo> map = new HashMap<>();
        List<AttendanceShiftNameEntity> shiftNameVos = this.getBaseMapper().selectBatchIds(shiftIds);
        if (CollUtil.isEmpty(shiftNameVos)) {
            return map;
        }
        List<ShiftNameVo> shiftNameVoList = BeanUtil.copyToList(shiftNameVos, ShiftNameVo.class);
        Map<String, ShiftNameVo> shiftNameVoMap = shiftNameVoList.stream().collect(Collectors.toMap(ShiftNameVo::getId, t -> t));
        return shiftIds.stream().map(shiftNameVoMap::get).filter(Objects::nonNull).collect(Collectors.toMap(ShiftNameVo::getId, t -> t));
    }

    @Override
    public List<FixedClassShiftVo> getFixedClass(String groupId) {
        List<FixedClassShiftVo> fixedList = new ArrayList<>();
        List<ShiftNameVo> shiftNameVos = attendanceShiftNameSettingMapper.getFixedClass(groupId);
        if (null != shiftNameVos && !shiftNameVos.isEmpty()) {
            List<ShiftNameVo> workMap = shiftNameVos.stream().filter(t -> 2 == t.getType()).collect(Collectors.toList());
            // 组装时间段
            List<String> shiftIds = workMap.stream().distinct().map(ShiftNameVo::getId).collect(Collectors.toList());
            List<AttendanceShiftSettingPeriodEntity> list = attendanceShiftSettingPeriodService.list(new LambdaQueryWrapper<AttendanceShiftSettingPeriodEntity>().in(AttendanceShiftSettingPeriodEntity::getShiftId, shiftIds).eq(AttendanceShiftSettingPeriodEntity::getDeleteMark, Boolean.FALSE));
            Map<String, List<AttendanceShiftSettingPeriodEntity>> shiftMap = list.stream().collect(Collectors.groupingBy(AttendanceShiftSettingPeriodEntity::getShiftId));
            workMap.forEach(v -> {
                List<AttendanceShiftSettingPeriodEntity> attendanceShiftSettingPeriodEntities = shiftMap.get(v.getId());
                if (null != attendanceShiftSettingPeriodEntities && !attendanceShiftSettingPeriodEntities.isEmpty()) {
                    // 排序
                    List<AttendanceShiftSettingPeriodEntity> shiftList = attendanceShiftSettingPeriodEntities.stream().sorted(Comparator.comparing(AttendanceShiftSettingPeriodEntity::getType)).collect(Collectors.toList());
                    List<AttendanceShiftSettingPeriodVo> periodEntities = BeanUtil.copyToList(shiftList, AttendanceShiftSettingPeriodVo.class);
                    v.setPeriods(periodEntities);
                }
            });
            // 组装数据
            Map<Integer, List<ShiftNameVo>> numMap = shiftNameVos.stream().collect(Collectors.groupingBy(ShiftNameVo::getNum));
            for (Map.Entry<Integer, List<ShiftNameVo>> integerListEntry : numMap.entrySet()) {
                FixedClassShiftVo fixedClassShiftVo = new FixedClassShiftVo();
                fixedClassShiftVo.setNum(integerListEntry.getKey());
                fixedClassShiftVo.setFixedType(integerListEntry.getValue().get(0).getFixedType());
                fixedClassShiftVo.setShiftNameVos(integerListEntry.getValue());
                fixedList.add(fixedClassShiftVo);
            }
            fixedList = fixedList.stream().sorted(Comparator.comparing(FixedClassShiftVo::getNum)).collect(Collectors.toList());
        }
        return fixedList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ActionResult saveOrUpdateFixedClass(FixedClassGroupDto dto) {
        RLock lock = redissonClient.getLock(String.format(ATTENDANCE_UPDATE_FIXED_CLASS, UserProvider.getUser().getTenantId(), dto.getGroupId()));
        Assert.isFalse(lock.isLocked(), "当前考勤组编辑固定班操作正在执行中，请稍后再试");
        Date date = new Date();
        List<SecondmentDateVo> dateList = CollUtil.newArrayList();
        try {
            Assert.isFalse(!lock.tryLock(5, 60, TimeUnit.SECONDS), "当前考勤组编辑固定班操作正在执行中，请稍后再试");
            String userId = UserProvider.getUser().getUserId();
            AttendanceShiftSettingVo byGroupId = attendanceShiftSettingService.findAllByGroupId(dto.getGroupId());
            List<ShiftNameVo> schedulingPeriods = Objects.isNull(byGroupId) ? List.of() : byGroupId.getSchedulingPeriods();
            Map<String, ShiftNameVo> collect = schedulingPeriods.stream().collect(Collectors.toMap(ShiftNameVo::getId, Function.identity()));
            // 修改setting
            attendanceShiftSettingService.changeSystemType(dto.getGroupId(), dto.getSystemType());
            attendanceShiftNameSettingMapper.updateByGroupId(dto.getGroupId(), dto.getSystemType(), userId);

            // 删除之前绑定的班次信息
            attendanceShiftNameSettingMapper.deleteFixedClass(dto.getGroupId());
            if (null != dto.getFixedClassDtos() && !dto.getFixedClassDtos().isEmpty()) {
                List<FixedClassSaveDto> list = new ArrayList<>();
                int index = 0;
                for (FixedClassDto v : dto.getFixedClassDtos()) {
                    // 生成偏移日期：按索引递增天数偏移基准日期
                    DateTime dateTime = cn.hutool.core.date.DateUtil.offsetDay(date, ++index);
                    if (CollUtil.isEmpty(v.getFixedBases())) {
                        FixedClassSaveDto fixedClassSaveDto = new FixedClassSaveDto(FtbUtil.getId(), v.getNum(), v.getShiftType(), dto.getGroupId(), 0, null, 1);
                        list.add(fixedClassSaveDto);
                    } else {
                        v.getFixedBases().forEach(value -> {
                            FixedClassSaveDto fixedClassSaveDto = new FixedClassSaveDto(FtbUtil.getId(), v.getNum(), v.getShiftType(), dto.getGroupId(), value.getType(), value.getShiftNameId(), value.getSort());
                            list.add(fixedClassSaveDto);
                        });
                    }
                    for (FixedBaseDto fixedClassSaveDto : v.getFixedBases()) {
                        if (StringUtil.isNotEmpty(fixedClassSaveDto.getShiftNameId()) && collect.containsKey(fixedClassSaveDto.getShiftNameId())) {
                            ShiftNameVo shiftNameVo = collect.get(fixedClassSaveDto.getShiftNameId());
                            if (Objects.equals(v.getShiftType(), 0)) {
                                for (AttendanceShiftSettingPeriodVo periodVo : shiftNameVo.getPeriods()) {
                                    Assert.isTrue(fixedPeriodSingleConflict(dateTime, dateList, periodVo), "班次时间段冲突");
                                }
                            } else {
                                Assert.isTrue(fixedPeriodSingleConflict(dateTime, dateList, shiftNameVo.getPeriods().get(fixedClassSaveDto.getSort() - 1)), "班次时间段冲突");
                            }
                        }
                    }

                }
                if (!list.isEmpty()) {
                    // 保存本次传入的内容
                    attendanceShiftNameSettingMapper.saveFixedClass(list);
                }
            }
            // 变更现有排班规则
            fixedChange(attendanceShiftSettingService.findAllByGroupId(dto.getGroupId()), byGroupId);
            if (Objects.equals(dto.getSystemType(), 2)) {
                return ActionResult.success();
            }
            return ActionResult.success();
        } catch (Exception e) {
            return ActionResult.fail(e.getMessage());
        } finally {
            if(lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    private void fixedChange(AttendanceShiftSettingVo shiftSettingVo, AttendanceShiftSettingVo oldShiftSetting) {
        //过滤班制为排班数据
        if (Objects.isNull(shiftSettingVo) || Objects.equals(shiftSettingVo.getSystemType(), 2)) {
            return;
        }
        //判断固定排班星期几数据是否调整
        List<FixedClassShiftVo> fixedPeriods = shiftSettingVo.getFixedPeriods();
        List<FixedClassShiftVo> oldFixedPeriods = oldShiftSetting.getFixedPeriods();
        Map<Integer, List<ShiftNameVo>> fixedPeriodsMap = CollUtil.isEmpty(fixedPeriods) ? Maps.newHashMap() : fixedPeriods.stream().collect(Collectors.toMap(FixedClassShiftVo::getNum, FixedClassShiftVo::getShiftNameVos));
        Map<Integer, List<ShiftNameVo>> oldFixedPeriodsMap = CollUtil.isEmpty(oldFixedPeriods) ? Maps.newHashMap() : oldFixedPeriods.stream().collect(Collectors.toMap(FixedClassShiftVo::getNum, FixedClassShiftVo::getShiftNameVos));
        //判断星期几的排班id是否有调整
        boolean isUpdate = fixedPeriodsMap.entrySet().stream().anyMatch(entry -> {
            Integer num = entry.getKey();
            List<ShiftNameVo> shiftNames = entry.getValue();
            List<String> shiftIds = shiftNames.stream().map(ShiftNameVo::getId).collect(Collectors.toList());
            List<Integer> shiftTypes = shiftNames.stream().map(ShiftNameVo::getType).collect(Collectors.toList());
            List<ShiftNameVo> oldShiftNames = oldFixedPeriodsMap.getOrDefault(num, CollUtil.newArrayList());
            List<String> oldShiftIds = oldShiftNames.stream().map(ShiftNameVo::getId).collect(Collectors.toList());
            List<Integer> oldShiftTypes = oldShiftNames.stream().map(ShiftNameVo::getType).collect(Collectors.toList());
            return !shiftIds.equals(oldShiftIds) || !shiftTypes.equals(oldShiftTypes);
        });
        if (isUpdate) {
            fixedPeriodChange(shiftSettingVo.getGroupId());
        }
    }

    @Override
    public PageInfo<ShiftNameListVo> getList(ShiftNameQueryDto queryDto) throws HandleException {
        // 通过考勤组id 获取考勤组详情信息
        AttendanceGroup groupDetail = attendanceGroupMapper.getGroupDetail(queryDto.getGroupId());
        // 通过查看本组的班次开关有没有打开
        if (null == groupDetail) {
            log.error("未找到该考勤组");
            throw new HandleException("未找到该考勤组");
        }
        // 打开展示本组配置的班次配置信息 班次设置 1.开启 0.关闭
        if (1 != groupDetail.getAttendanceClassSetting()) {
            queryDto.setGroupId(null);
            // 没有打开 去查询考勤组 F_LevelCode层级中的 上级是否打开 查到最近的一个上级查询对应的配置
            List<String> list = new ArrayList<>(Arrays.asList(groupDetail.getLevelCode().split("#")));
            List<AttendanceGroup> groupDetails = attendanceGroupMapper.getGroupDetailList(list);
            Map<String, AttendanceGroup> groupMap = groupDetails.stream().collect(Collectors.toMap(AttendanceGroup::getId, Function.identity()));
            String groupId = null;
            for (String gId : list) {
                AttendanceGroup attendanceGroup = groupMap.get(gId);
                if (null != attendanceGroup && attendanceGroup.getAttendanceClassSetting() == 1) {
                    groupId = attendanceGroup.getId();
                    break;
                }
            }
            if (null != groupId) {
                queryDto.setGroupId(groupId);
            }
        }
        PageHelper.startPage(queryDto.getCurrentPage(), queryDto.getPageSize());
        PageInfo<ShiftNameListVo> shiftNameListVoList = new PageInfo<>();
        if (null == queryDto.getGroupId()) {
            return shiftNameListVoList;
        }
        shiftNameListVoList = new PageInfo<>(attendanceShiftNameSettingMapper.getListByGroupId(queryDto));
        if (null != shiftNameListVoList.getList() && !shiftNameListVoList.getList().isEmpty()) {
            // 组装时间段
            List<String> shiftIds = shiftNameListVoList.getList().stream().map(ShiftNameListVo::getId).collect(Collectors.toList());
            List<AttendanceShiftSettingPeriodEntity> list = attendanceShiftSettingPeriodService.list(new LambdaQueryWrapper<AttendanceShiftSettingPeriodEntity>().in(AttendanceShiftSettingPeriodEntity::getShiftId, shiftIds).eq(AttendanceShiftSettingPeriodEntity::getDeleteMark, Boolean.FALSE));
            Map<String, List<AttendanceShiftSettingPeriodEntity>> shiftMap = list.stream().collect(Collectors.groupingBy(AttendanceShiftSettingPeriodEntity::getShiftId));
            shiftNameListVoList.getList().forEach(v -> {
                List<AttendanceShiftSettingPeriodEntity> attendanceShiftSettingPeriodEntities = shiftMap.getOrDefault(v.getId(), CollUtil.newArrayList());
                if (CollUtil.isNotEmpty(attendanceShiftSettingPeriodEntities)) {
                    // 排序
                    List<AttendanceShiftSettingPeriodEntity> shiftList = attendanceShiftSettingPeriodEntities.stream().sorted(Comparator.comparing(AttendanceShiftSettingPeriodEntity::getType)).collect(Collectors.toList());
                    //拼接时段 08：00-14：00        16：00-次日07：58
                    StringBuilder timeStr = new StringBuilder();
                    for (int i = 0; i < shiftList.size(); i++) {
                        AttendanceShiftSettingPeriodEntity entity = shiftList.get(i);
                        if (i > 0) {
                            timeStr.append(",");
                        }
                        timeStr.append(Objects.equals(entity.getInType(), 2) ? "次日" + entity.getInPoint() : entity.getInPoint()).append("-");
                        timeStr.append(Objects.equals(entity.getInType(), 2) ? "次日" + entity.getOutPoint() : entity.getOutPoint());
                    }
                    v.setTimeStr(timeStr.toString());
                }
            });
        }
        return shiftNameListVoList;
    }
}
