package jnpf.attendance.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jnpf.attendance.mapper.AttendanceClockInMapper;
import jnpf.attendance.mapper.AttendanceClockInResultMapper;
import jnpf.attendance.service.AttendanceClockInResultService;
import jnpf.base.service.SuperServiceImpl;
import jnpf.entity.attendance.AttendanceClockInResult;
import jnpf.entity.workflow.ApplyAttendanceChange;
import jnpf.entity.workflow.ApplyAttendanceRepair;
import jnpf.model.attendance.vo.ApplyResultVo;
import jnpf.model.attendance.vo.UserDayVo;
import jnpf.util.ConstantUtil;
import jnpf.workflow.mapper.ApplyAttendanceChangeMapper;
import jnpf.workflow.mapper.ApplyAttendanceRepairMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 打卡结果服务实现
 *
 * @author yanwenfu
 * @create 2023-11-29
 */
@Slf4j
@Service
public class AttendanceClockInResultServiceImpl extends SuperServiceImpl<AttendanceClockInResultMapper, AttendanceClockInResult> implements AttendanceClockInResultService {

    @Resource
    private AttendanceClockInMapper attendanceClockInMapper;
    @Resource
    private AttendanceClockInResultMapper attendanceClockInResultMapper;
    @Resource
    private ApplyAttendanceChangeMapper applyAttendanceChangeMapper;
    @Resource
    private ApplyAttendanceRepairMapper applyAttendanceRepairMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void dbMatchDeal(String requestId, List<AttendanceClockInResult> resultList, List<UserDayVo> userDayList, String updateUserId) {
        // 申请中的打卡记录直接删除
        attendanceClockInMapper.deleteBatchByUserDay(userDayList, ConstantUtil.PASS_APPROVAL);
        log.error("用户打卡重新匹配 - {} - 申请中的打卡记录直接删除", requestId);
        // 根据userId删除原本的打卡结果
        List<String> userIdList = userDayList.stream().map(UserDayVo::getUserId).collect(Collectors.toList());
        attendanceClockInResultMapper.deleteRecordByRuleBatch(userIdList, updateUserId);
        log.error("用户打卡重新匹配 - {} - 根据userId删除原本的打卡结果", requestId);
        // 新增新生成的打卡结果 筛选出缺勤记录和普通记录
        if (!resultList.isEmpty()) {
            // 查询有审批记录(变更、补卡)的打卡结果, 更新为新的结果id
            Map<String, AttendanceClockInResult> oldResultMap = resultList.stream()
                    .filter(v -> StringUtils.isNotEmpty(v.getOldResultId()))
                    .collect(Collectors.toMap(AttendanceClockInResult::getOldResultId, Function.identity()));
            updateOldResultChangeList(oldResultMap);
            log.error("用户打卡重新匹配 - {} - updateOldResultChangeList: {}", requestId, oldResultMap);
            updateOldResultRepairList(oldResultMap);
            log.error("用户打卡重新匹配 - {} - updateOldResultRepairList", requestId);
            // 判断已存在记录, 将存在的记录删除
            List<AttendanceClockInResult> existList = new ArrayList<>();
            int batchSize = 500;
            int total = resultList.size();
            // 分段查询
            for (int i = 0; i < total; i += batchSize) {
                int end = Math.min(i + batchSize, total);
                List<AttendanceClockInResult> subList = resultList.subList(i, end);
                // 每次查 500 条以内
                List<AttendanceClockInResult> partList = attendanceClockInResultMapper.selectExistRecord(subList, ConstantUtil.NUM_FALSE);
                existList.addAll(partList);
            }
            if (!existList.isEmpty()) {
                List<String> existIds = existList.stream().map(AttendanceClockInResult::getId).collect(Collectors.toList());
                this.removeBatchByIds(existIds);
            }
            log.error("用户打卡重新匹配 - {} - selectExistRecord", requestId);
            this.saveBatch(resultList);
            log.error("用户打卡重新匹配 - {} - 落库结束", requestId);
        }
    }

    @Override
    public void updateOldResultChangeList(Map<String, AttendanceClockInResult> map) {

        if (!map.isEmpty()) {
            LambdaQueryWrapper<ApplyAttendanceChange> queryWrapper = new LambdaQueryWrapper<ApplyAttendanceChange>()
                    .in(ApplyAttendanceChange::getClockInResultId, map.keySet());
            List<ApplyAttendanceChange> applyChangeList = applyAttendanceChangeMapper.selectList(queryWrapper);
            if (!applyChangeList.isEmpty()) {
                List<ApplyResultVo> list = new ArrayList<>();
                applyChangeList.forEach(v -> {
                    AttendanceClockInResult clockInResult = map.get(v.getClockInResultId());
                    if (null != clockInResult) {
                        list.add(new ApplyResultVo(v.getId(), clockInResult.getId()));
                    }
                });
                if (list.isEmpty()) {
                    return;
                }
                applyAttendanceChangeMapper.updateBatchOldResult(list);
            }
        }
    }

    @Override
    public void updateOldResultRepairList(Map<String, AttendanceClockInResult> map) {

        if (!map.isEmpty()) {
            LambdaQueryWrapper<ApplyAttendanceRepair> queryWrapper = new LambdaQueryWrapper<ApplyAttendanceRepair>()
                    .in(ApplyAttendanceRepair::getClockInResultId, map.keySet());
            List<ApplyAttendanceRepair> applyRepairList = applyAttendanceRepairMapper.selectList(queryWrapper);
            List<ApplyResultVo> list = new ArrayList<>();
            applyRepairList.forEach(v -> {
                AttendanceClockInResult clockInResult = map.get(v.getClockInResultId());
                if (null != clockInResult) {
                    list.add(new ApplyResultVo(v.getId(), clockInResult.getId()));
                }
            });
            if (list.isEmpty()) {
                return;
            }
            applyAttendanceRepairMapper.updateBatchOldResult(list);
        }
    }
}
