package com.sundot.airport.attendance.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.sundot.airport.attendance.domain.AttendanceCheckRecord;
import com.sundot.airport.attendance.domain.AttendancePostRecord;
import com.sundot.airport.attendance.domain.AttendanceRecord;
import com.sundot.airport.attendance.domain.AttendanceTeamUserRecord;
import com.sundot.airport.attendance.enums.CheckInTypeEnum;
import com.sundot.airport.attendance.mapper.AttendanceCheckRecordMapper;
import com.sundot.airport.attendance.mapper.AttendanceRecordMapper;
import com.sundot.airport.attendance.service.IAttendancePostRecordService;
import com.sundot.airport.attendance.service.IAttendanceRecordService;
import com.sundot.airport.attendance.service.IAttendanceTeamUserRecordService;
import com.sundot.airport.common.core.domain.entity.SysRole;
import com.sundot.airport.common.core.domain.entity.SysUser;
import com.sundot.airport.common.dto.AttendanceRecordDTO;
import com.sundot.airport.common.dto.AttendanceRecordRep;
import com.sundot.airport.common.dto.AttendanceRecordReq;
import com.sundot.airport.common.dto.UserInfo;
import com.sundot.airport.common.enums.RoleTypeEnum;
import com.sundot.airport.common.exception.ServiceException;
import com.sundot.airport.common.utils.DateUtils;
import com.sundot.airport.common.utils.SecurityUtils;
import com.sundot.airport.exam.event.ClockInEvent;
import com.sundot.airport.system.service.ISysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 考勤记录Service业务层处理
 *
 * @author wangchong
 * @date 2025-07-10
 */
@Slf4j
@Service
public class AttendanceRecordServiceImpl implements IAttendanceRecordService {
    @Autowired
    private IAttendancePostRecordService attendancePostRecordService;
    @Autowired
    private IAttendanceTeamUserRecordService attendanceTeamUserRecordService;
    @Autowired
    private AttendanceRecordMapper attendanceRecordMapper;

    @Autowired
    private AttendanceCheckRecordMapper attendanceCheckRecordMapper;

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    // 梭班时间窗口(2小时内)
    private static final long SHUTTLE_TIME_WINDOW = 2 * 60 * 60 * 1000;


    @Autowired
    private ISysConfigService configService;

    /**
     * 查询考勤记录
     *
     * @param id 考勤记录主键
     * @return 考勤记录
     */
    @Override
    public AttendanceRecord selectAttendanceRecordById(Long id) {
        return attendanceRecordMapper.selectAttendanceRecordById(id);
    }

    /**
     * 查询考勤记录列表
     *
     * @param attendanceRecord 考勤记录
     * @return 考勤记录
     */
    @Override
    public List<AttendanceRecord> selectAttendanceRecordList(AttendanceRecord attendanceRecord) {
        return attendanceRecordMapper.selectAttendanceRecordList(attendanceRecord);
    }

    /**
     * 新增考勤记录
     *
     * @param attendanceRecord 考勤记录
     * @return 结果
     */
    @Override
    public int insertAttendanceRecord(AttendanceRecord attendanceRecord) {
        attendanceRecord.setCreateTime(DateUtils.getNowDate());
        return attendanceRecordMapper.insertAttendanceRecord(attendanceRecord);
    }

    /**
     * 修改考勤记录
     *
     * @param attendanceRecord 考勤记录
     * @return 结果
     */
    @Override
    public int updateAttendanceRecord(AttendanceRecord attendanceRecord) {
        attendanceRecord.setUpdateTime(DateUtils.getNowDate());
        return attendanceRecordMapper.updateAttendanceRecord(attendanceRecord);
    }

    /**
     * 批量删除考勤记录
     *
     * @param ids 需要删除的考勤记录主键
     * @return 结果
     */
    @Override
    public int deleteAttendanceRecordByIds(Long[] ids) {
        return attendanceRecordMapper.deleteAttendanceRecordByIds(ids);
    }

    /**
     * 删除考勤记录信息
     *
     * @param id 考勤记录主键
     * @return 结果
     */
    @Override
    public int deleteAttendanceRecordById(Long id) {
        return attendanceRecordMapper.deleteAttendanceRecordById(id);
    }

    /**
     * 打卡签到
     *
     * @param dto      打卡信息
     * @param userInfo 登录用户
     * @return 今日打卡历史
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<AttendanceCheckRecord> record(AttendanceRecordDTO dto, UserInfo userInfo) {
        // 考勤记录数据检查
        checkData(dto, userInfo);
        //确定打卡时间
//        if (ObjectUtil.isNotEmpty(dto.getCheckInDate())) {
//            String startTime = configService.selectConfigByKey("attendance.record.start.time");
//            String endTime = configService.selectConfigByKey("attendance.record.end.time");
//            Date checkInTime = this.calculateAttendanceDate(new Date(), startTime, endTime, dto.getCheckInType());
//            dto.setCheckInDate(checkInTime);
//        }
        //如果下班卡，直接取最近一条上班打卡记录
        if (StrUtil.equals("2", dto.getCheckInType())) {
            AttendanceRecordReq dtoReq = new AttendanceRecordReq();
            dtoReq.setUserId(userInfo.getUserId());
            List<AttendanceRecord> attendanceRecords = queryRecordListNew(dtoReq);
            if (CollectionUtil.isNotEmpty(attendanceRecords)) {
                AttendanceRecord lastRecord = attendanceRecords.get(0);
                dto.setCheckInDate(lastRecord.getAttendanceDate());
            }

        }
        // 处理打卡记录
        AttendanceCheckRecord checkRecord = new AttendanceCheckRecord();
        checkRecord.setRevision(1L);
        checkRecord.setUserId(userInfo.getUserId());
        checkRecord.setCheckInTime(new Date());
        checkRecord.setCheckInDate(dto.getCheckInDate());
        checkRecord.setCheckInType(StrUtil.equals("1", dto.getCheckInType()) ? CheckInTypeEnum.CLOCK_IN.getValue() : CheckInTypeEnum.CLOCK_OUT.getValue());
        checkRecord.setCheckInPosition(dto.getCheckInPosition());
        checkRecord.setUserName(userInfo.getNickName());
        checkRecord.setRemark(dto.getRemark());
        checkRecord.setCheckInTypeDesc(StrUtil.equals("1", dto.getCheckInType()) ? CheckInTypeEnum.CLOCK_IN.getName() : CheckInTypeEnum.CLOCK_OUT.getName());
        checkRecord.setCreateBy(userInfo.getUserId().toString());
        checkRecord.setCreateTime(new Date());

        // 处理梭班
//        processShuttleShiftLogic(checkRecord, userInfo);
        // 保存打卡记录
        attendanceCheckRecordMapper.insertAttendanceCheckRecord(checkRecord);

        // 如果是上班打卡,发布打卡事件,触发每日答题任务生成
        if (StrUtil.equals("1", dto.getCheckInType())) {
            try {
                ClockInEvent event = new ClockInEvent(
                        this,
                        userInfo.getUserId(),
                        userInfo.getDepartmentId()
                );
                eventPublisher.publishEvent(event);
            } catch (Exception e) {
                // 事件发布失败不影响打卡主流程
                // 仅记录日志
            }
        }

        // 处理考勤记录
        if (StrUtil.equals("1", dto.getCheckInType())) {
            AttendanceRecord attendanceRecord = getAttendanceRecord(dto, userInfo);
            attendanceRecordMapper.insertAttendanceRecord(attendanceRecord);
        } else {
            AttendanceRecord search = new AttendanceRecord();
            search.setUserId(userInfo.getUserId());
            search.setAttendanceDate(dto.getCheckInDate());
            List<AttendanceRecord> attendanceCheckRecords = attendanceRecordMapper.selectAttendanceRecordList(search);
            AttendanceRecord attendanceRecord = getAttendanceRecord(userInfo, attendanceCheckRecords);
            attendanceRecord.setRemark(attendanceRecord.getRemark() + "\n" + dto.getRemark());
            attendanceRecordMapper.updateAttendanceRecord(attendanceRecord);
        }

        // 签退处理上岗记录表+考勤班组成员表
        if (StrUtil.equals("2", dto.getCheckInType())) {
            List<SysRole> roles = SecurityUtils.getLoginUser().getUser().getRoles();
            if (CollectionUtil.isNotEmpty(roles)) {
                List<String> roleKeyList = roles.stream().map(SysRole::getRoleKey).collect(Collectors.toList());
                if (roleKeyList.contains(RoleTypeEnum.banzuzhang.getCode()) || roleKeyList.contains(RoleTypeEnum.kezhang.getCode())) {
                    // 处理上岗记录表
                    // 查询在该时间段内未签退的记录
                    AttendancePostRecord queryParam = new AttendancePostRecord();
                    queryParam.setCreateBy(SecurityUtils.getUserId().toString());
                    queryParam.setCheckOutTimeType(1); // 未签退的记录
                    List<AttendancePostRecord> records = attendancePostRecordService.selectAttendancePostRecordList(queryParam);
                    // 自动签退这些记录
                    Date autoCheckOutTime = DateUtils.getNowDate();
                    int count = 0;
                    for (AttendancePostRecord record : records) {
                        try {
                            record.setCheckOutTime(autoCheckOutTime);
                            record.setWorkDuration((autoCheckOutTime.getTime() - record.getCheckInTime().getTime()) / 1000 / 60);
                            record.setUpdateBy(SecurityUtils.getUserId().toString());
                            record.setUpdateTime(new Date());
                            record.setRemark((record.getRemark() != null ? record.getRemark() : "") + " 系统自动签退");
                            record.setLocked(false);
                            attendancePostRecordService.updateAttendancePostRecord(record);
                            count++;
                        } catch (Exception e) {
                            log.error("自动签退记录失败，ID: " + record.getId(), e);
                        }
                    }
                    log.info("自动下通道任务执行完成，共处理 {} 条记录", count);

                    // 处理考勤班组成员表
                    AttendanceTeamUserRecord queryAttendanceTeamUserRecord = new AttendanceTeamUserRecord();
                    queryAttendanceTeamUserRecord.setCreateBy(SecurityUtils.getUsername());
                    queryAttendanceTeamUserRecord.setCheckInType("1");
                    List<AttendanceTeamUserRecord> attendanceTeamUserRecordList = attendanceTeamUserRecordService.selectAttendanceTeamUserRecordList(queryAttendanceTeamUserRecord, true);
                    attendanceTeamUserRecordList.forEach(attendanceTeamUserRecord -> {
                        attendanceTeamUserRecord.setUpdateBy(SecurityUtils.getUsername());
                        attendanceTeamUserRecord.setCheckInType("2");
                        attendanceTeamUserRecordService.updateAttendanceTeamUserRecord(attendanceTeamUserRecord);
                    });
                }
            }
        }

        AttendanceCheckRecord checkSearch = new AttendanceCheckRecord();
        checkSearch.setUserId(userInfo.getUserId());
        checkRecord.setCheckInDate(dto.getCheckInDate());
        return attendanceCheckRecordMapper.selectAttendanceCheckRecordList(checkSearch);
    }

    private static AttendanceRecord getAttendanceRecord(AttendanceRecordDTO dto, UserInfo userInfo) {
        AttendanceRecord attendanceRecord = new AttendanceRecord();
        attendanceRecord.setRevision(1L);
        attendanceRecord.setOverDuration(0L);
        attendanceRecord.setUserId(userInfo.getUserId());
        if (Objects.nonNull(userInfo.getTeamsId())) {
            attendanceRecord.setTeamCode(userInfo.getTeamsId().toString());
        }
        attendanceRecord.setTeamName(userInfo.getTeamsName());
        if (Objects.nonNull(userInfo.getDepartmentId())) {
            attendanceRecord.setDepartmentCode(userInfo.getDepartmentId().toString());
        }
        attendanceRecord.setDepartmentName(userInfo.getDepartmentName());
        if (Objects.nonNull(userInfo.getBrigadeId())) {
            attendanceRecord.setBrigadeCode(userInfo.getBrigadeId().toString());
        }
        attendanceRecord.setBrigadeName(userInfo.getBrigadeName());
        if (Objects.nonNull(userInfo.getStationId())) {
            attendanceRecord.setStationCode(userInfo.getStationId().toString());
        }
        attendanceRecord.setStationName(userInfo.getStationName());
        attendanceRecord.setUserName(userInfo.getNickName());
        attendanceRecord.setWorkDuration(0L);
        attendanceRecord.setAttendanceDate(dto.getCheckInDate());
        attendanceRecord.setCreateBy(userInfo.getUserId().toString());
        attendanceRecord.setCreateTime(new Date());
        attendanceRecord.setCheckInTime(new Date());
        attendanceRecord.setRemark(dto.getRemark());
        return attendanceRecord;
    }

    private static AttendanceRecord getAttendanceRecord(UserInfo userInfo, List<AttendanceRecord> attendanceCheckRecords) {
        AttendanceRecord attendanceRecord = attendanceCheckRecords.get(0);
        // 如果有记录则默认按照签退
        attendanceRecord.setCheckOutTime(new Date());
        attendanceRecord.setWorkDuration((attendanceRecord.getCheckOutTime().getTime() - attendanceRecord.getCheckInTime().getTime()) / 1000 / 60);
        attendanceRecord.setUpdateBy(userInfo.getUserId().toString());
        attendanceRecord.setUpdateTime(new Date());
        attendanceRecord.setRevision(attendanceRecord.getRevision() + 1);
        return attendanceRecord;
    }

    /**
     * 获取打卡记录
     *
     * @param dto 打卡记录参数
     * @return 打卡记录
     */
    @Override
    public List<AttendanceRecordRep> recordList(AttendanceRecordReq dto) {
        List<AttendanceRecordRep> result = Lists.newArrayList();
//        AttendanceRecord recordSearch = new AttendanceRecord();
//        recordSearch.setUserId(dto.getUserId());
//        if (StrUtil.equals("1", dto.getType())) {
//            // 单日查询场景
//            Date targetAttendanceDate = dto.getCheckInDate();
//            // 计算查询时间范围
//            Date yesterday = DateUtils.addDays(targetAttendanceDate, -1);
//            // 设置查询条件
//            recordSearch.setAttendanceDateStart(yesterday);
//            recordSearch.setAttendanceDateEnd(targetAttendanceDate);
//        } else {
//            recordSearch.setAttendanceDateStart(dto.getStartDate());
//            recordSearch.setAttendanceDateEnd(dto.getEndDate());
//        }
//        List<AttendanceRecord> attendanceRecords = attendanceRecordMapper.selectAttendanceRecordList(recordSearch);
//        if (CollectionUtil.isEmpty(attendanceRecords)) {
//            return result;
//        }
        List<AttendanceRecord> attendanceRecords;
        if (StrUtil.equals("1", dto.getType())) {
            AttendanceRecord recordSearch = new AttendanceRecord();
            recordSearch.setUserId(dto.getUserId());
            attendanceRecords = attendanceRecordMapper.selectAttendanceRecordList(recordSearch);
            if (CollectionUtil.isEmpty(attendanceRecords)) {
                return result;
            }
            List<AttendanceRecord> tempList = attendanceRecords.stream().filter(record -> record.getAttendanceDate().equals(dto.getCheckInDate())).collect(Collectors.toList());
            if (CollectionUtil.isEmpty(tempList)) {
                Date attendanceDate = attendanceRecords.get(0).getAttendanceDate();
                Date checkOutTime = attendanceRecords.get(0).getCheckOutTime();
                if (checkOutTime != null) {
                    return result;
                }
                attendanceRecords = attendanceRecords.stream().filter(record -> record.getAttendanceDate().equals(attendanceDate)).collect(Collectors.toList());
            } else {
                attendanceRecords = tempList;
            }
        } else {
            AttendanceRecord recordSearch = new AttendanceRecord();
            recordSearch.setUserId(dto.getUserId());
            recordSearch.setAttendanceDateStart(dto.getStartDate());
            recordSearch.setAttendanceDateEnd(dto.getEndDate());
            attendanceRecords = attendanceRecordMapper.selectAttendanceRecordList(recordSearch);
        }
        if (CollectionUtil.isEmpty(attendanceRecords)) {
            return result;
        }
        AttendanceCheckRecord checkSearch = new AttendanceCheckRecord();
        checkSearch.setUserId(dto.getUserId());
        if (StrUtil.equals("1", dto.getType())) {
            checkSearch.setCheckInDate(attendanceRecords.get(0).getAttendanceDate());
        } else {
            checkSearch.setCheckInDateStart(dto.getStartDate());
            checkSearch.setCheckInDateEnd(dto.getEndDate());
        }
        List<AttendanceCheckRecord> attendanceCheckRecords = attendanceCheckRecordMapper.selectAttendanceCheckRecordList(checkSearch);

        attendanceRecords.forEach(record -> {
            AttendanceRecordRep main = new AttendanceRecordRep();
            BeanUtil.copyProperties(record, main);
            List<AttendanceCheckRecord> collect = attendanceCheckRecords.stream().filter(x -> Objects.equals(x.getCheckInDate(), record.getAttendanceDate())).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(collect)) {
                collect.forEach(c -> {
                    AttendanceRecordRep.RecordItem item = new AttendanceRecordRep.RecordItem();
                    BeanUtil.copyProperties(c, item);
                    main.getItems().add(item);
                });
            }
            result.add(main);
        });
        return result;
    }


    /**
     * 根据实际打卡时间和班次时间计算所属考勤日期
     *
     * @param checkInTime    实际打卡时间，即员工实际进行打卡操作的时间点
     * @param shiftStartTime 班次开始时间，格式为 "HH:mm"
     * @param shiftEndTime   班次结束时间，格式为 "HH:mm"
     * @param checkInType    打卡类型：1-上班打卡，2-下班打卡
     * @return 计算出的考勤日期，该次打卡记录应归属的考勤周期日期
     */
    @Override
    public Date calculateAttendanceDate(Date checkInTime, String shiftStartTime, String shiftEndTime, String checkInType) {
        // 参数校验
        if (checkInTime == null || shiftStartTime == null || shiftEndTime == null) {
            throw new ServiceException("参数不能为空: checkInTime, shiftStartTime, shiftEndTime");
        }

        final String DATE_FORMAT = "yyyy-MM-dd";
        final String TIME_FORMAT = "HH:mm";

        try {
            String checkInDateStr = DateUtils.parseDateToStr(DATE_FORMAT, checkInTime);
            Date checkInDateTime = DateUtils.parseDate(checkInDateStr + " " + DateUtils.parseDateToStr(TIME_FORMAT, checkInTime));

            // 构造昨天的班次时间段
            Date yesterday = DateUtils.addDays(checkInTime, -1);
            String yesterdayStr = DateUtils.parseDateToStr(DATE_FORMAT, yesterday);
            Date yesterdayShiftStart = DateUtils.parseDate(yesterdayStr + " " + shiftStartTime);
            Date todayShiftEnd = DateUtils.parseDate(checkInDateStr + " " + shiftEndTime);

            boolean isWithinYesterdayShift = checkInDateTime.compareTo(yesterdayShiftStart) >= 0 &&
                    checkInDateTime.compareTo(todayShiftEnd) <= 0;

            if (StrUtil.isBlank(checkInType)) {
                // 默认规则：若在昨天班次时间内，则归属昨天
                if (isWithinYesterdayShift) {
                    return DateUtils.parseDate(yesterdayStr);
                }
                return DateUtils.parseDate(checkInDateStr);
            } else {
                if (StrUtil.equals("1", checkInType)) {
                    // 类型1：如果早于昨天班次开始时间，则归属昨天
                    if (checkInDateTime.before(yesterdayShiftStart)) {
                        return DateUtils.parseDate(yesterdayStr);
                    }
                    return DateUtils.parseDate(checkInDateStr);
                } else {
                    // 如果早于今日班次结束时间，则归属昨天
                    if (checkInDateTime.before(todayShiftEnd)) {
                        return DateUtils.parseDate(yesterdayStr);
                    }
                    return DateUtils.parseDate(checkInDateStr);
                }
            }

        } catch (Exception e) {
            throw new ServiceException("日期解析失败: " + e.getMessage());
        }
    }


    /**
     * 处理梭班
     *
     * @param checkRecord 打卡记录
     * @param userInfo    用户信息
     */
    private void processShuttleShiftLogic(AttendanceCheckRecord checkRecord, UserInfo userInfo) {
        // 获取用户最近一次打卡记录
        AttendanceCheckRecord lastRecord = getLastCheckRecord(userInfo.getUserId());

        // 判断是否为梭班场景（先下后上且在时间窗口内）
        if (isShuttleShiftScenario(lastRecord, checkRecord)) {
            // 标记为梭班打卡
            checkRecord.setShuttleShift(true);
            checkRecord.setShiftType("SHUTTLE");

            // 如果是上班卡，归属到第二天考勤（相对于上次考勤日期）
            if (checkRecord.getCheckInType().equals(CheckInTypeEnum.CLOCK_IN.getValue())) {
                Date nextDayAttendanceDate = calculateNextDayAttendanceDateForShuttleShift(lastRecord);
                checkRecord.setCheckInDate(nextDayAttendanceDate);
            }
        }

    }


    /**
     * 判断是否为梭班场景
     *
     * @param lastRecord    最近打卡记录
     * @param currentRecord 当前打卡记录
     * @return 是否为梭班场景
     */
    private boolean isShuttleShiftScenario(AttendanceCheckRecord lastRecord, AttendanceCheckRecord currentRecord) {
        // 需要满足以下条件：
        // 1. 存在上一次打卡记录
        // 2. 上次是下班卡，本次是上班卡
        // 3. 两次打卡时间间隔在梭班时间窗口内（2小时内）
        if (lastRecord == null) {
            return false;
        }

        boolean isSequenceValid = lastRecord.getCheckInType().equals(CheckInTypeEnum.CLOCK_OUT.getValue())
                && currentRecord.getCheckInType().equals(CheckInTypeEnum.CLOCK_IN.getValue());

        long timeDiff = currentRecord.getCheckInTime().getTime() - lastRecord.getCheckInTime().getTime();
        boolean isTimeValid = timeDiff > 0 && timeDiff <= SHUTTLE_TIME_WINDOW;

        return isSequenceValid && isTimeValid;
    }


    /**
     * 获取用户最近一次打卡记录
     *
     * @param userId 用户ID
     * @return 最近打卡记录
     */
    private AttendanceCheckRecord getLastCheckRecord(Long userId) {
        AttendanceCheckRecord search = new AttendanceCheckRecord();
        search.setUserId(userId);
        List<AttendanceCheckRecord> records = attendanceCheckRecordMapper.selectAttendanceCheckRecordList(search);

        if (CollectionUtil.isNotEmpty(records)) {
            // 返回最近的打卡记录
            return records.stream()
                    .sorted((r1, r2) -> r2.getCheckInTime().compareTo(r1.getCheckInTime()))
                    .findFirst()
                    .orElse(null);
        }
        return null;
    }


    /**
     * 计算梭班场景下的次日考勤日期（基于上次考勤日期）
     *
     * @param lastRecord 最近一次打卡日期
     * @return 次日考勤日期
     */
    private Date calculateNextDayAttendanceDateForShuttleShift(AttendanceCheckRecord lastRecord) {
        // 查询用户最近的考勤记录
        if (ObjectUtil.isNotEmpty(lastRecord)) {
            LocalDateTime lastAttendanceDate = lastRecord.getCheckInDate().toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime();

            // 返回上次考勤日期的次日
            return Date.from(
                    lastAttendanceDate.toLocalDate()
                            .plusDays(1)
                            .atStartOfDay(ZoneId.systemDefault())
                            .toInstant()
            );
        } else {
            // 如果没有历史记录，则使用当前日期
            return Date.from(
                    LocalDate.now()
                            .atStartOfDay(ZoneId.systemDefault())
                            .toInstant()
            );
        }
    }


    private List<AttendanceRecord> queryRecordList(AttendanceRecordReq dto) {
        AttendanceRecord recordSearch = new AttendanceRecord();
        recordSearch.setUserId(dto.getUserId());
        // 单日查询场景
        Date targetAttendanceDate = dto.getCheckInDate();
        // 计算查询时间范围
        Date yesterday = DateUtils.addDays(targetAttendanceDate, -1);
        // 设置查询条件
        recordSearch.setAttendanceDateStart(yesterday);
        recordSearch.setAttendanceDateEnd(targetAttendanceDate);
        return attendanceRecordMapper.selectAttendanceRecordList(recordSearch);
    }

    /**
     * 考勤记录数据检查
     *
     * @param dto
     * @param userInfo
     */
    private void checkData(AttendanceRecordDTO dto, UserInfo userInfo) {
        AttendanceRecordReq dtoReq = new AttendanceRecordReq();
        dtoReq.setUserId(userInfo.getUserId());
        List<AttendanceRecord> attendanceRecords = queryRecordListNew(dtoReq);
        if (StrUtil.equals("1", dto.getCheckInType())) {
            if (CollectionUtil.isNotEmpty(attendanceRecords) && attendanceRecords.get(0).getCheckOutTime() == null) {
                throw new ServiceException("请勿重复打上班卡");
            }
        } else if (StrUtil.equals("2", dto.getCheckInType())) {
            if (CollectionUtil.isEmpty(attendanceRecords) || attendanceRecords.get(0).getCheckOutTime() != null) {
                throw new ServiceException("请勿重复打下班卡");
            }
        } else {
            throw new ServiceException("打卡类型错误");
        }
    }

    /**
     * 查询考勤记录列表
     */
    private List<AttendanceRecord> queryRecordListNew(AttendanceRecordReq dto) {
        AttendanceRecord recordSearch = new AttendanceRecord();
        recordSearch.setUserId(dto.getUserId());
        return attendanceRecordMapper.selectAttendanceRecordList(recordSearch);
    }

    /**
     * 查询可打卡类型:1=签到,2=签退
     */
    @Override
    public String getRecordType() {
        AttendanceRecordReq dtoReq = new AttendanceRecordReq();
        dtoReq.setUserId(SecurityUtils.getUserId());
        List<AttendanceRecord> attendanceRecords = queryRecordListNew(dtoReq);
        if (CollectionUtil.isEmpty(attendanceRecords)) {
            return "1";
        }
        if (attendanceRecords.get(0).getCheckOutTime() != null) {
            return "1";
        }
        return "2";
    }

    /**
     * 根据角色标识查询今日打卡用户列表
     *
     * @param date 考勤日期
     * @param list 角色标识
     * @return 用户列表
     */
    @Override
    public List<SysUser> selectUserListByRoleKey(Date date, List<String> list) {
        return attendanceRecordMapper.selectUserListByRoleKey(date, "1", list);
    }
}
