package com.yida.data.attendance.service.impl;

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yida.data.attendance.dto.AddAttendanceRecordDTO;
import com.yida.data.attendance.dto.AddAttendanceRuleTimeDTO;
import com.yida.data.attendance.dto.PageAttendanceRecordDTO;
import com.yida.data.attendance.dto.RemoveFaceDTO;
import com.yida.data.attendance.mapper.AttendanceRecordMapper;
import com.yida.data.attendance.mapper.AttendanceRuleWifiMapper;
import com.yida.data.attendance.service.*;
import com.yida.data.attendance.vo.AttendanceRecordExcelVO;
import com.yida.data.attendance.vo.AttendanceRuleVO;
import com.yida.data.attendance.vo.DownLoadAttendanceResultVO;
import com.yida.data.attendance.vo.StudentDormAttendanceResultExcelVO;
import com.yida.data.common.core.entity.CurrentUser;
import com.yida.data.common.core.entity.attendance.EduAttendanceDevice;
import com.yida.data.common.core.entity.attendance.EduAttendanceRecord;
import com.yida.data.common.core.entity.attendance.EduAttendanceStaffRecord;
import com.yida.data.common.core.entity.attendance.attendance.AttendanceRecord;
import com.yida.data.common.core.entity.attendance.attendance.AttendanceResult;
import com.yida.data.common.core.entity.attendance.attendance.AttendanceRuleAddress;
import com.yida.data.common.core.entity.attendance.attendance.AttendanceRuleWifi;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.system.enums.RoleEnum;
import com.yida.data.common.core.entity.user.EduStaff;
import com.yida.data.common.core.entity.user.EduStudent;
import com.yida.data.common.core.enums.MsgChannel;
import com.yida.data.common.core.enums.UserTypeEnum;
import com.yida.data.common.core.enums.attendance.AttendanceModeTypeEnum;
import com.yida.data.common.core.enums.attendance.AttendanceNextDayEnum;
import com.yida.data.common.core.enums.attendance.AttendanceResultEnum;
import com.yida.data.common.core.enums.attendance.AttendanceTypeEnum;
import com.yida.data.common.core.enums.attendance.AttendanceUserTypeEnum;
import com.yida.data.common.core.utils.FebsUtil;
import com.yida.data.common.core.utils.FileUtil;
import com.yida.data.common.service.CommonService;
import com.yida.data.user.dto.ListStudentDTO;
import com.yida.data.user.feign.RemoteStaffService;
import com.yida.data.user.feign.RemoteStudentService;

import java.io.File;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.regexp.RE;
import org.apache.tomcat.jni.User;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;

/**
 * 进出记录 Service实现
 *
 * @date 2023-08-09 11:37:25
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class AttendanceRecordServiceImpl extends ServiceImpl
    <AttendanceRecordMapper, AttendanceRecord> implements AttendanceRecordService {

    private final RedisService redisService;
    private final AttendanceRuleService attendanceRuleService;
    private final EduAttendanceDeviceService eduAttendanceDeviceService;
    private final RemoteStudentService remoteStudentService;
    private final AttendanceRuleWifiMapper attendanceRuleWifiMapper;
    private final AttendanceRuleAddressService attendanceRuleAddressService;
    private final AttendanceResultService attendanceResultService;
    private final AttendanceRuleTimeService attendanceRuleTimeService;
    private final CommonService commonService;
    private final NoticeService noticeService;
    private final ErrorRecordMsgService errorRecordMsgService;
    private final RemoteStaffService remoteStaffService;
    @Value("${febs.uploadUrl}")
    private String uploadUrl;

    @Autowired
    ApplicationContext applicationContext;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AttendanceRecord addRecord(AddAttendanceRecordDTO dto) {
        AttendanceRecord erecord = getOne(Wrappers.lambdaQuery(new AttendanceRecord())
            .eq(AttendanceRecord::getUserId, dto.getUserId())
            .eq(AttendanceRecord::getUserType, dto.getUserType())
            .eq(AttendanceRecord::getCreateTime, dto.getCreateTime()));
        if (ObjectUtil.isNotNull(erecord)) {
            log.error("用户：{}，类型：{}，通行时间数据：{}已存在，不加入数据库", dto.getUserType(), dto.getUserId(), dto.getCreateTime());
            return null;
        }

        LocalTime now = dto.getCreateTime().toLocalTime();
        AttendanceRecord record = new AttendanceRecord();
        BeanUtils.copyProperties(dto, record);
        EduStaff staff = null;
        EduStudent student = null;
        EduAttendanceDevice device = null;
        //查设备
        if (ObjectUtil.isNotEmpty(dto.getDeviceSn())) {
            device = (EduAttendanceDevice) redisService
                .hget(CachePrefixConstant.DEVICE_DATA, dto.getDeviceSn());
            if (ObjectUtil.isNull(device)) {
                device = eduAttendanceDeviceService.getOne(Wrappers.lambdaQuery(new EduAttendanceDevice())
                    .eq(EduAttendanceDevice::getSn, dto.getDeviceSn()));
            }
            if (ObjectUtil.isNull(device)) {
                return null;
            } else {
                redisService.hset(CachePrefixConstant.DEVICE_DATA, dto.getDeviceSn(), device);
            }
        }

        //判断记录数据是否已存在
//        if (ObjectUtil.isNotNull(dto.getOriginalRecordId())) {
//            if (MsgChannel.MQTT.equals(dto.getMsgChannel())) {
//                AttendanceRecord erecord = getOne(Wrappers.lambdaQuery(new AttendanceRecord())
//                    .eq(AttendanceRecord::getOriginalRecordId, dto.getOriginalRecordId())
//                    .eq(AttendanceRecord::getDeviceId,device.getId()));
//                if (ObjectUtil.isNotNull(erecord)) {
//                    log.error("通行数据：【{}】已存在，不加入数据库", dto.getOriginalRecordId());
//                    return null;
//                }
//            }
//        }

        if (ObjectUtil.equals(AttendanceUserTypeEnum.STAFF.getValue(), dto.getUserType())) {
            staff = commonService.getStaffById(dto.getUserId());
            if (ObjectUtil.isNull(staff)) {
                //反向删除人脸机数据
                if (!MsgChannel.ACTIVE.equals(dto.getMsgChannel()) && ObjectUtil.isNotNull(device)) {
                    log.error("教职工{}数据为空，删除面板机{}消息", dto.getUserId(), device.getId());
                    RemoveFaceDTO removeFaceDTO = new RemoveFaceDTO();
                    removeFaceDTO
                        .setDeviceFactoryUserId(
                            Collections.singletonList(dto.getUserId() + "1"));
                    removeFaceDTO.setDeviceList(Collections.singletonList(device.getId()));
                    eduAttendanceDeviceService.removeFace(removeFaceDTO);
                }
                return null;
            }
        } else {
            student = commonService.getStudentById(dto.getUserId());
            if (ObjectUtil.isNull(student)) {
                //反向删除人脸机数据t
                if (!MsgChannel.ACTIVE.equals(dto.getMsgChannel()) && ObjectUtil.isNotNull(device)) {
                    log.error("学生{}数据为空，删除面板机{}消息", dto.getUserId(), device.getId());
                    RemoveFaceDTO removeFaceDTO = new RemoveFaceDTO();
                    removeFaceDTO
                        .setDeviceFactoryUserId(
                            Collections.singletonList(dto.getUserId() + "0"));
                    removeFaceDTO.setDeviceList(Collections.singletonList(device.getId()));
                    eduAttendanceDeviceService.removeFace(removeFaceDTO);
                }
                return null;
            }
        }

        //查看匹配的考勤规则
        AttendanceRuleVO userMatchRule = new AttendanceRuleVO();
        if (ObjectUtil.isNotEmpty(dto.getRuleId())) {
            userMatchRule = (AttendanceRuleVO) redisService
                .hget(CachePrefixConstant.ATTENDANCE_RULE_DATA, String.valueOf(dto.getRuleId()));
            if (ObjectUtil.isNull(userMatchRule)) {
                userMatchRule = attendanceRuleService.getRule(dto.getRuleId());
                if (ObjectUtil.isNotNull(userMatchRule)) {
                    redisService.hset(CachePrefixConstant.ATTENDANCE_RULE_DATA, String.valueOf(dto.getRuleId()), userMatchRule);
                }
            }
        } else {
            userMatchRule = attendanceRuleService
                .findUserMatchRule(dto.getUserType(), dto.getUserId(), dto.getDeviceSn(), dto.getWifiName(), dto.getWifiBssid(),
                    dto.getCreateTime().toLocalDate(), dto.getSchoolId());
        }

        if (ObjectUtil.isNotNull(userMatchRule)) {
            //匹配考勤时段
            AddAttendanceRuleTimeDTO addAttendanceRuleTimeDTO = new AddAttendanceRuleTimeDTO();
            if (ObjectUtil.isNotEmpty(dto.getRuleTimeId())) {
//                addAttendanceRuleTimeDTO = attendanceRuleTimeService.get(dto.getRuleTimeId());
                addAttendanceRuleTimeDTO = userMatchRule.getTimeDTOList().stream().filter(t -> t.getId()
                    .equals(dto.getRuleTimeId()))
                    .collect(Collectors.toList()).get(0);
            } else {
                addAttendanceRuleTimeDTO = MatchAttendanceTime(userMatchRule.getTimeDTOList(),
                    dto.getCreateTime(), userMatchRule.getType(), dto.getUserId(), dto.getUserType(),
                    userMatchRule.getUserType());
            }

            record.setRuleId(userMatchRule.getId());
            if (ObjectUtil.isNotNull(addAttendanceRuleTimeDTO)) {
                record.setRuleTimeId(addAttendanceRuleTimeDTO.getId());
                if (ObjectUtil.equals(AttendanceModeTypeEnum.FREE.getValue(), userMatchRule.getType())) {
                    if (ObjectUtil.equals(AttendanceUserTypeEnum.STUDENT_TO_DORM.getValue(), userMatchRule.getUserType())) {
                        //宿舍考勤
                        if (dto.getCreateTime().toLocalTime().isAfter(addAttendanceRuleTimeDTO.getStartTime()) &&
                            dto.getCreateTime().toLocalTime().isBefore(addAttendanceRuleTimeDTO.getEndTime())) {
                            record.setStatus(AttendanceResultEnum.NORMAL.getValue());
                        } else if (dto.getCreateTime().toLocalTime().isAfter(addAttendanceRuleTimeDTO.getEndTime()) &&
                            dto.getCreateTime().toLocalTime().isBefore(addAttendanceRuleTimeDTO.getLastTime())) {
                            record.setStatus(AttendanceResultEnum.LATE_DORM.getValue());
                        } else if (dto.getCreateTime().toLocalTime().isAfter(addAttendanceRuleTimeDTO.getLastTime()) &&
                            dto.getCreateTime().toLocalTime().isBefore(addAttendanceRuleTimeDTO.getEndEffectiveEndTime())) {
                            record.setStatus(AttendanceResultEnum.AB_LATE_DORM.getValue());
                        } else {
                            record.setStatus(AttendanceResultEnum.ABNORMAL.getValue());
                        }
                    } else {
                        if (dto.getCreateTime().toLocalTime().isAfter(addAttendanceRuleTimeDTO.getStartTime()) &&
                            dto.getCreateTime().toLocalTime().isBefore(addAttendanceRuleTimeDTO.getEndTime())) {
                            record.setStatus(AttendanceResultEnum.NORMAL.getValue());
                        } else {
                            record.setStatus(AttendanceResultEnum.ABNORMAL.getValue());
                        }
                    }
                    record.setRuleTimeType(AttendanceTypeEnum.WORK_ON.getValue());
                    record.setStiTime(addAttendanceRuleTimeDTO.getStartTime());
                } else {
                    //固定时间段打卡模式
                    //判断是上班打卡还是下班打卡
                    if (now.isAfter(addAttendanceRuleTimeDTO.getStartEffectiveStartTime()) && now
                        .isBefore(addAttendanceRuleTimeDTO.getStartEffectiveEndTime())) {
                        //在上班打卡时间段，并且上班未打卡，表示此次打卡未
                        List<AttendanceRecord> recordList = this.list(Wrappers.lambdaQuery(new AttendanceRecord())
                            .eq(AttendanceRecord::getUserId, dto.getUserId())
                            .eq(AttendanceRecord::getRuleId, userMatchRule.getId())
                            .eq(AttendanceRecord::getRuleTimeId, addAttendanceRuleTimeDTO.getId())
                            .eq(AttendanceRecord::getRuleTimeType, 0));
                        if (CollUtil.isNotEmpty(recordList)) {
                            record.setStiTime(addAttendanceRuleTimeDTO.getEndTime());
                            record.setRuleTimeType(AttendanceTypeEnum.WORK_OFF.getValue());
                            //下班打卡，计算考勤结果
                            if (now.isBefore(addAttendanceRuleTimeDTO.getEndTime())) {
                                record.setStatus(AttendanceResultEnum.ABNORMAL.getValue());
                            } else {
                                record.setStatus(AttendanceResultEnum.NORMAL.getValue());
                            }
                        } else {
                            record.setStiTime(addAttendanceRuleTimeDTO.getStartTime());
                            record.setRuleTimeType(AttendanceTypeEnum.WORK_ON.getValue());
                            //上班打卡，计算考勤结果
                            if (now.isBefore(addAttendanceRuleTimeDTO.getStartTime())) {
                                record.setStatus(AttendanceResultEnum.NORMAL.getValue());
                            } else {
                                record.setStatus(AttendanceResultEnum.ABNORMAL.getValue());
                            }
                        }
                    } else if (now.isAfter(addAttendanceRuleTimeDTO.getEndEffectiveStartTime())) {
                        record.setRuleTimeType(AttendanceTypeEnum.WORK_OFF.getValue());
                        LocalDateTime endDateTime = null;
                        //大于下班 开始打卡时间
                        record.setStiTime(addAttendanceRuleTimeDTO.getEndTime());
                        if (dto.getCreateTime()
                            .isAfter(dto.getCreateTime().toLocalDate().atTime(addAttendanceRuleTimeDTO.getEndTime())) &&
                            dto.getCreateTime().isBefore(
                                dto.getCreateTime().toLocalDate().atTime(addAttendanceRuleTimeDTO.getEndEffectiveEndTime()))) {
                            //正常
                            record.setStatus(AttendanceResultEnum.NORMAL.getValue());
                        } else {
                            record.setStatus(AttendanceResultEnum.ABNORMAL.getValue());
                        }
                    }
                }
            }
        }
        //增加辅助字段

        if (ObjectUtil.isNotEmpty(dto.getPicUrl())) {
            record.setPicUrl(dto.getPicUrl());
        }
        if (ObjectUtil.isNotEmpty(dto.getDeviceSn())) {
            if (ObjectUtil.isNotNull(device)) {
                record.setScope(device.getZoneScope());
                record.setDeviceName(device.getName());
                record.setZone(device.getType());
                record.setDeviceId(device.getId());
            }
        }
        if (ObjectUtil.isNotEmpty(dto.getWifiId())) {
            AttendanceRuleWifi wifi = attendanceRuleWifiMapper.selectById(dto.getWifiId());
            if (ObjectUtil.isNotNull(wifi)) {
                record.setWifiName(wifi.getWifiName());
            }
        }

        if (ObjectUtil.isNotEmpty(dto.getWifiBssid())) {
            List<AttendanceRuleWifi> wifiList = attendanceRuleWifiMapper.listRuleWifi(dto.getRuleId(), dto.getWifiBssid());
            AttendanceRuleWifi wifi = wifiList.get(0);
            if (ObjectUtil.isNotNull(wifi)) {
                record.setWifiName(wifi.getWifiName());
                record.setWifiId(wifi.getId());
            }
        }
        if (ObjectUtil.isNotEmpty(dto.getAddressId())) {
            AttendanceRuleAddress address = attendanceRuleAddressService.getById(dto.getAddressId());
            if (ObjectUtil.isNotNull(address)) {
                record.setAddressName(address.getAddressName());
            }
        }
        if (ObjectUtil.equals(AttendanceUserTypeEnum.STAFF.getValue(), dto.getUserType())) {
            //TODO 教职工 辅助信息
            if (ObjectUtil.isNotNull(staff)) {
                record.setSchoolId(staff.getSchoolId());
                if (CollUtil.isNotEmpty(staff.getStaffDept())) {
                    record.setCampusId(staff.getStaffDept().get(0).getId());
                    record.setCampusName(staff.getStaffDept().get(0).getDeptName());
                }
                record.setUserName(staff.getName());
            }

        } else if (ObjectUtil.equals(AttendanceUserTypeEnum.STUDENT_TO_SCHOOL.getValue(), dto.getUserType())) {
            if (ObjectUtil.isNotNull(student)) {
                record.setSchoolId(student.getSchoolId());
                record.setUserName(student.getStuName());
                record.setCampusId(student.getCampusId());
                record.setCampusName(student.getCampusName());
                record.setSectionId(student.getSectionId());
                record.setSectionName(student.getSectionName());
                record.setGradeId(student.getGradeId());
                record.setGradeName(student.getGradeName());
                record.setClassId(student.getClassId());
                record.setClassName(student.getClassName());
            }
        } else {
            if (ObjectUtil.isNotNull(student)) {
                record.setUserName(student.getStuName());
                record.setCampusId(student.getCampusId());
                record.setCampusName(student.getCampusName());
                record.setSectionId(student.getSectionId());
                record.setSectionName(student.getSectionName());
                record.setGradeId(student.getGradeId());
                record.setGradeName(student.getGradeName());
                record.setClassId(student.getClassId());
                record.setClassName(student.getClassName());
                record.setDormId(student.getDormId());
                record.setDormName(student.getDormName());
                record.setDormRoomId(student.getDormRoomId());
                record.setDormRoomName(student.getDormRoomName());
                record.setSchoolId(student.getSchoolId());
            }
        }

        //保存记录
        save(record);
        //生成结果
        if (ObjectUtil.isNotEmpty(record.getStatus())) {
            attendanceResultService.addResult(record);
        }
        //TODO 推送通行记录
        noticeService.sendAttendanceNotice(record);

        if (StrUtil.isNotBlank(dto.getEsRecordId())) {
            errorRecordMsgService.batchDeleteErrorRecord(new String[]{dto.getEsRecordId()});
        }
        return record;
    }

    @Override
    public IPage<AttendanceRecord> listRecordPage(PageAttendanceRecordDTO dto) {
        // 先查询出人员
        List<Long> userIdList = new ArrayList<>();
        if (ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), dto.getUserType())) {
            ListStudentDTO listStudentDTO = new ListStudentDTO();
            if (ObjectUtil.isNotNull(dto.getStudentName())) {
                listStudentDTO.setStuName(dto.getStudentName());
            }
            if (ObjectUtil.isNotNull(dto.getSectionId()) && ObjectUtil.isNull(dto.getClassId())) {
                listStudentDTO.setSectionId(dto.getSectionId());
            }
            if (ObjectUtil.isNotNull(listStudentDTO.getStuName()) || ObjectUtil.isNotNull(listStudentDTO.getSectionId())) {
                userIdList = remoteStudentService.listStudent(listStudentDTO).getData().stream().map(EduStudent::getId).collect(
                    Collectors.toList());
            }
            dto.setUserIdList(userIdList);
            String rolePerms = FebsUtil.getCurrentUser().getRolePerms();
            //学校管理员
            if (rolePerms.contains(RoleEnum.ROLE_SCHOOL_PRINCIPAL.getValue())) {
                dto.setSchoolId(FebsUtil.getTopDeptId());
            } else {
                if (ObjectUtil.isNull(dto.getClassId())) {
                    dto.setClassIdList(remoteStaffService.listClassIdByStaffId().getData());
                } else {
                    dto.setClassIdList(Collections.singletonList(dto.getClassId()));
                }
            }
        }
        return baseMapper
            .listRecordPage(dto.toPage(), dto);
    }

    /**
     * 匹配考勤时段
     *
     * @param timeDTOList
     * @param createTime  打卡时间
     * @return
     */
    @Override
    public AddAttendanceRuleTimeDTO MatchAttendanceTime(List<AddAttendanceRuleTimeDTO> timeDTOList, LocalDateTime createTime,
        Integer attendanceType, Long userId, Integer userType, Integer attendanceUserType) {
        //根据当前打卡时间与打卡时间段对应打卡时间。
        LocalDateTime now = createTime;
        LocalDate nowDate = createTime.toLocalDate();
        if (ObjectUtil.equals(AttendanceModeTypeEnum.FREE.getValue(), attendanceType)) {
            //自由打卡模式
            for (AddAttendanceRuleTimeDTO addAttendanceRuleTimeDTO : timeDTOList) {
                if (now.toLocalTime().isAfter(addAttendanceRuleTimeDTO.getStartEffectiveStartTime()) && now.toLocalTime()
                    .isBefore(addAttendanceRuleTimeDTO.getEndEffectiveEndTime())) {
                    return addAttendanceRuleTimeDTO;
                }
            }
        } else {
            for (AddAttendanceRuleTimeDTO addAttendanceRuleTimeDTO : timeDTOList) {

                AttendanceResult result = attendanceResultService.getOne(Wrappers.lambdaQuery(new AttendanceResult())
                    .eq(AttendanceResult::getRuleId, addAttendanceRuleTimeDTO.getRuleId())
                    .eq(AttendanceResult::getRuleTimeId, addAttendanceRuleTimeDTO.getId())
                    .eq(AttendanceResult::getUserId, userId)
                    .eq(AttendanceResult::getUserType, userType)
                    .eq(AttendanceResult::getAttendanceDate, createTime.toLocalDate()));

                if (ObjectUtil.isNotNull(result) && ObjectUtil.isNotNull(result.getStartStatus())) {
                    if (now.isAfter(nowDate.atTime(addAttendanceRuleTimeDTO.getEndEffectiveStartTime())) && now
                        .isBefore(nowDate.atTime(addAttendanceRuleTimeDTO.getEndEffectiveEndTime()))) {
                        return addAttendanceRuleTimeDTO;
                    }
                } else {
                    if (now.isAfter(nowDate.atTime(addAttendanceRuleTimeDTO.getStartEffectiveStartTime())) && now
                        .isBefore(nowDate.atTime(addAttendanceRuleTimeDTO.getStartEffectiveEndTime()))) {
                        return addAttendanceRuleTimeDTO;
                    }
                    if (now.isAfter(nowDate.atTime(addAttendanceRuleTimeDTO.getEndEffectiveStartTime())) && now
                        .isBefore(nowDate.atTime(addAttendanceRuleTimeDTO.getEndEffectiveEndTime()))) {
                        return addAttendanceRuleTimeDTO;
                    }
                }
            }
        }
        return null;
    }

    @Override
    public void downloadAttendanceRecord(PageAttendanceRecordDTO dto, String uuid) {
        // 先查询出人员
        List<Long> userIdList = new ArrayList<>();
        if (ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), dto.getUserType())) {
            ListStudentDTO listStudentDTO = new ListStudentDTO();
            if (ObjectUtil.isNotNull(dto.getStudentName())) {
                listStudentDTO.setStuName(dto.getStudentName());
            }
            if (ObjectUtil.isNotNull(dto.getSectionId()) && ObjectUtil.isNull(dto.getClassId())) {
                listStudentDTO.setSectionId(dto.getSectionId());
            }
            if (ObjectUtil.isNotNull(listStudentDTO.getStuName()) || ObjectUtil.isNotNull(listStudentDTO.getSectionId())) {
                userIdList = remoteStudentService.listStudent(listStudentDTO).getData().stream().map(EduStudent::getId).collect(
                    Collectors.toList());
            }
            dto.setUserIdList(userIdList);
            String rolePerms = FebsUtil.getCurrentUser().getRolePerms();
            //学校管理员
            if (rolePerms.contains(RoleEnum.ROLE_SCHOOL_PRINCIPAL.getValue())) {
                dto.setSchoolId(FebsUtil.getTopDeptId());
            } else {
                if (ObjectUtil.isNull(dto.getClassId())) {
                    dto.setClassIdList(remoteStaffService.listClassIdByStaffId().getData());
                } else {
                    dto.setClassIdList(Collections.singletonList(dto.getClassId()));
                }
            }
        }
        AttendanceRecordServiceImpl bean = applicationContext
            .getBean(AttendanceRecordServiceImpl.class);
        bean.dealDownRecordData(dto, uuid);
    }


    @Async
    void dealDownRecordData(PageAttendanceRecordDTO dto, String uuid) {
        String fileName = FileUtil.getLocalUploadAddress() + uuid + ".xls";
        File file = new File(fileName);
        try {
            log.info("开始处理下载通行数据");
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            IPage<AttendanceRecord> attendanceRecordIPage = baseMapper.listRecordPage(new Page(1, -1), dto);
            List<AttendanceRecord> records = attendanceRecordIPage.getRecords();
            List<List<String>> exportDataList = new ArrayList<>();
            for (int i = 0; i < records.size(); i++) {
                AttendanceRecord record = records.get(i);
                //更新进度缓存
                redisService
                    .hset(CachePrefixConstant.ATTENDANCE_RECORD_DOWNLOAD, uuid,
                        DownLoadAttendanceResultVO.builder()
                            .key(uuid)
                            .finish(0)
                            .totalNum(records.size())
                            .currentNum(i + 1).build());
                //封装单行数据
                List<String> singleDataList = new ArrayList<>();
                singleDataList.add(record.getUserName());
                if (ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), dto.getUserType())) {
                    EduStudent student = commonService.getStudentById(record.getUserId());
                    if (ObjectUtil.isNotNull(student)) {
                        singleDataList.add(student.getStuNumber());
                    } else {
                        singleDataList.add("");
                    }
                } else {
                    EduStaff staff = commonService.getStaffById(record.getUserId());
                    if (ObjectUtil.isNotNull(staff)) {
                        singleDataList.add(staff.getMobile());
                    } else {
                        singleDataList.add("");
                    }
                }
                singleDataList.add(record.getCampusName());
                singleDataList.add(record.getSectionName());
                singleDataList.add(record.getGradeName());
                singleDataList.add(record.getClassName());
                singleDataList.add(LocalDateTimeUtil.format(record.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
                singleDataList.add(record.getDeviceName());
                exportDataList.add(singleDataList);
            }
            EasyExcel.write(file)
                .excelType(ExcelTypeEnum.XLSX)
                // 这里放入动态头
                .head(AttendanceRecordExcelVO.class).sheet("通行记录")
                // 当然这里数据也可以用 List<List<String>> 去传入
                .doWrite(exportDataList);

            // 上传文件到媒资
            String fileUrl = com.yida.data.common.core.utils.FileUtil.uploadFileToMediaServer(uploadUrl, file);
            redisService
                .hset(CachePrefixConstant.ATTENDANCE_RECORD_DOWNLOAD, uuid, DownLoadAttendanceResultVO.builder()
                    .key(uuid)
                    .finish(1)
                    .filePath(fileUrl)
                    .totalNum(CollUtil.isEmpty(records) ? 100 : records.size())
                    .currentNum(CollUtil.isEmpty(records) ? 100 : records.size()).build());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //删除本地文件
            if (cn.hutool.core.io.FileUtil.exist(file)) {
                cn.hutool.core.io.FileUtil.del(file);
            }
        }
    }

    @Override
    public void resetOldData(Long schoolId, LocalDateTime startDateTime, Integer userType) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        Boolean isEnd = false;
        Integer pageNum = 1;
        while (!isEnd) {
            log.info("开始处理第【{}】页数据", pageNum);
            //每次查询1000调数据
            //学生数据
            List<AttendanceRecord> addRecordList = new ArrayList<>();
            List<AttendanceResult> addResultList = new ArrayList<>();

            if (!isEnd) {
                if (ObjectUtil.equals(UserTypeEnum.STAFF_USER_TYPE.getType(), userType)) {
                    List<EduAttendanceStaffRecord> staffRecords = baseMapper
                        .listStaffOldDataPage(new Page(pageNum, 1000), schoolId, startDateTime).getRecords();
                    for (EduAttendanceStaffRecord record : staffRecords) {
                        //判断记录是否存在
                        List<AttendanceRecord> list = list(Wrappers.lambdaQuery(new AttendanceRecord())
                            .eq(AttendanceRecord::getCreateTime, record.getCreateTime())
                            .eq(AttendanceRecord::getUserId, record.getStaffId())
                            .eq(AttendanceRecord::getUserType, UserTypeEnum.STAFF_USER_TYPE.getType()));
                        if (CollUtil.isEmpty(list)) {
                            EduStaff staff = commonService.getStaffById(record.getStaffId());
                            AttendanceRecord attendanceRecord = new AttendanceRecord();
                            attendanceRecord.setDeviceId(record.getDeviceId());
                            attendanceRecord.setCreateTime(record.getCreateTime());
                            attendanceRecord.setUserId(record.getStaffId());
                            attendanceRecord.setUserType(0);
                            attendanceRecord.setPicUrl(record.getPicUrl());
                            attendanceRecord.setUserName(commonService.getStaffById(record.getStaffId()).getName());
                            attendanceRecord.setSchoolId(record.getSchoolId());
                            attendanceRecord.setCampusId(staff.getStaffDept().get(0).getId());
                            attendanceRecord.setCampusName(staff.getStaffDept().get(0).getDeptName());
                            addRecordList.add(attendanceRecord);

                            //考勤结果

                        }
                    }
                    if (staffRecords.size() < 1000) {
                        isEnd = true;
                    }
                } else {
                    List<EduAttendanceRecord> records = baseMapper
                        .listOldDataPage(new Page(pageNum, 1000), schoolId, startDateTime)
                        .getRecords();
                    for (EduAttendanceRecord record : records) {
                        List<AttendanceRecord> list = list(Wrappers.lambdaQuery(new AttendanceRecord())
                            .eq(AttendanceRecord::getCreateTime, record.getCreateTime())
                            .eq(AttendanceRecord::getUserId, record.getStudentId())
                            .eq(AttendanceRecord::getUserType, UserTypeEnum.PARENT_USER_TYPE.getType()));

                        if (CollUtil.isEmpty(list)) {
                            EduAttendanceDevice device = eduAttendanceDeviceService.getById(record.getDeviceId());
                            AddAttendanceRecordDTO dto = new AddAttendanceRecordDTO();
                            dto.setDeviceSn(device.getSn());
                            dto.setCreateTime(record.getCreateTime());
                            dto.setUserId(record.getStudentId());
                            dto.setUserType(1);
                            dto.setPicUrl(record.getPicUrl());
                            addRecord(dto);
                        }
                    }
                    if (records.size() < 1000) {
                        isEnd = true;
                    }
                }
            }
            pageNum++;
        }

        stopWatch.stop();
        log.info("迁移结束，总共耗时：[{}]", stopWatch.getTotalTimeSeconds() + "秒");
    }

}
