package jnpf.personnels.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import jnpf.attendance.service.AttendanceDailyRuleService;
import jnpf.base.ActionResult;
import jnpf.base.vo.PageListVO;
import jnpf.database.util.TenantDataSourceUtil;
import jnpf.engine.FlowTaskApi;
import jnpf.engine.entity.FlowTaskEntity;
import jnpf.model.attendance.vo.DailyApprovalVo;
import jnpf.model.cultivate.CultivatePage;
import jnpf.model.enums.FtbPersonnelsAuditTaskEnum;
import jnpf.model.personnels.dto.audit.FtbPersonnelsAuditDto;
import jnpf.model.personnels.dto.base.PersonnelsQueryDTO;
import jnpf.model.personnels.dto.salary.FtbPersonnelsSalaryInfo;
import jnpf.model.personnels.dto.secondment.FtbHandleSecondmentDTO;
import jnpf.model.personnels.dto.secondment.FtbSecondMentQueryDTO;
import jnpf.model.personnels.dto.secondment.msg.SecondmentMsgUserInfo;
import jnpf.model.personnels.po.FtbPersonnelsSecondmentManagement;
import jnpf.model.personnels.po.FtbPersonnelsStaffRoster;
import jnpf.model.personnels.vo.salary.UserInfoWithSalary;
import jnpf.model.personnels.vo.secondment.FtbPersonnelsSecondmentInfoVO;
import jnpf.model.personnels.vo.secondment.FtbPersonnelsSecondmentVO;
import jnpf.permission.V2GradesApi;
import jnpf.permission.V2OrganizeApi;
import jnpf.permission.V2PositionApi;
import jnpf.permission.V2UserApi;
import jnpf.permission.vo.v2.grades.GradeVO;
import jnpf.permission.vo.v2.organzie.OrganizeGeneralDetailVO;
import jnpf.permission.vo.v2.position.PositionVO;
import jnpf.permission.vo.v2.user.UserBoundVO;
import jnpf.personnels.mapper.FtbPersonnelsSecondmentManagementMapper;
import jnpf.personnels.mapper.FtbPersonnelsStaffRosterMapper;
import jnpf.personnels.msg.PersonnelsConsumerSourceMsg;
import jnpf.personnels.service.FtbPersonnelsAuditRunTaskService;
import jnpf.personnels.service.FtbPersonnelsSalaryService;
import jnpf.personnels.service.FtbPersonnelsSecondmentManagementService;
import jnpf.personnels.service.FtbPersonnelsStaffRosterService;
import jnpf.salary.QuerySalaryApi;
import jnpf.util.UserProvider;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 *
 *
 *@Author: peng.hao
 *@create: 2025/9/11
 *
 */
@Slf4j
@Service
public class FtbPersonnelsSecondmentManagementServiceImpl extends ServiceImpl<FtbPersonnelsSecondmentManagementMapper, FtbPersonnelsSecondmentManagement> implements FtbPersonnelsSecondmentManagementService{

    @Resource
    PersonnelsConsumerSourceMsg secondmentConsumerSourceMsg;


    @Resource
    FtbPersonnelsStaffRosterMapper ftbPersonnelsStaffRosterMapper;

    @Resource
    V2OrganizeApi v2OrganizeApi;
    @Resource
    V2PositionApi v2PositionApi;
    @Resource
    V2GradesApi v2GradesApi;

    @Autowired
    FtbPersonnelsSalaryService salaryService;

    @Autowired
    FlowTaskApi flowTaskApi;

    @Resource
    private FtbPersonnelsStaffRosterService staffRosterService;

    @Autowired
    FtbPersonnelsAuditRunTaskService ftbPersonnelsAuditRunTaskService;

    @Autowired
    QuerySalaryApi querySalaryApi;

    @Autowired
    V2UserApi v2UserApi;

    @Autowired
    AttendanceDailyRuleService attendanceDailyRuleService;

    @Override
    public PageListVO<FtbPersonnelsSecondmentVO> pageList(PersonnelsQueryDTO dto, CultivatePage page) {
        Page<FtbPersonnelsSecondmentVO> cultivatePage = page.coverCultivatePage();
        if (dto.getMyApprovalFlag().equals("2")) {
            dto.setUserId(UserProvider.getUser().getUserId());
        }
        Page<FtbPersonnelsSecondmentVO> pageListVO = baseMapper.pageList(cultivatePage, dto);
        List<FtbPersonnelsSecondmentVO> list = pageListVO.getRecords();
        String userId = UserProvider.getUser().getUserId();
        list.forEach(item -> {
            if (StringUtils.isNotEmpty(item.getTaskInfoId())) {
                FlowTaskEntity byTaskId = flowTaskApi.findByTaskId(item.getTaskInfoId());
                if (ObjectUtil.isNotEmpty(byTaskId) &&  byTaskId.getCreatorUserId().equals(userId)) {
                    item.setCurrentSponsor(1);
                } else {
                    item.setCurrentSponsor(0);
                }
            }
        });
        return CultivatePage.coverPageList(pageListVO);
    }

    @Override
    public FtbPersonnelsSecondmentInfoVO details(String id) {
        FtbPersonnelsSecondmentManagement selectById = baseMapper.selectById(id);
        FtbPersonnelsSecondmentInfoVO convert = FtbPersonnelsSecondmentInfoVO.convert(selectById);
        // 创建人名称
        String creatorUserId = selectById.getCreatorUserId();
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(List.of(creatorUserId, selectById.getUserId()), UserProvider.getUser().getTenantId());
        Map<String, UserBoundVO> stringMap = new HashMap<>();
        if (actionResult != null && actionResult.getData() != null) {
            stringMap = actionResult.getData().stream().collect(Collectors.toMap(UserBoundVO::getId, Function.identity(), (k1, k2) -> k1));
        }
        convert.setCreatorUserName(stringMap.containsKey(creatorUserId) ? stringMap.get(creatorUserId).getUserName() : "");
        LambdaQueryWrapper<FtbPersonnelsStaffRoster> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(FtbPersonnelsStaffRoster::getUserId, selectById.getUserId());
        FtbPersonnelsStaffRoster ftbPersonnelsStaffRoster = ftbPersonnelsStaffRosterMapper.selectOne(wrapper);
        if (ftbPersonnelsStaffRoster != null) {
            convert.setEmployeeId(ftbPersonnelsStaffRoster.getSystemWokerId());
            convert.setUserName(ftbPersonnelsStaffRoster.getName());
        }
        return convert;
    }

    @Override
    @Transactional
    public String handleSecondment(FtbHandleSecondmentDTO ftbHandleSecondmentDTO) {
        List<Map<String, Object>> maps = salaryService.querySalaryIntersectionWithOtherBusiness(ftbHandleSecondmentDTO.getUserId(),
                ftbHandleSecondmentDTO.getSecondmentStartTime(), ftbHandleSecondmentDTO.getSecondmentEndTime());
        if (CollUtil.isNotEmpty(maps) ) return "5";
        checkWhetherItIsInTheProcessOfApproval(ftbHandleSecondmentDTO.getUserId());
        // 提交时，需校验借调起止时间是否与该员工未开始的借调时间交叉重合
        checkTheSecondmentTime(ftbHandleSecondmentDTO.getUserId(), ftbHandleSecondmentDTO.getSecondmentStartTime(),
                ftbHandleSecondmentDTO.getSecondmentEndTime());
        FtbPersonnelsSecondmentManagement ftbPersonnelsSecondmentManagement =
                FtbPersonnelsSecondmentManagement.covert(ftbHandleSecondmentDTO);
        ftbPersonnelsSecondmentManagement.setTransferStatus(FtbPersonnelsAuditTaskEnum.MANUAL_CONTROL.getCode());
        // 修改
        if (StringUtils.isNotEmpty(ftbPersonnelsSecondmentManagement.getId())){
            baseMapper.updateById(ftbPersonnelsSecondmentManagement);
        }else {
            baseMapper.insert(ftbPersonnelsSecondmentManagement);
        }
        // 考勤人员通知
        SecondmentMsgUserInfo msgUserInfo = FtbHandleSecondmentDTO.convert(ftbHandleSecondmentDTO);
        msgUserInfo.setTenantId(UserProvider.getUser().getTenantId());
        secondmentConsumerSourceMsg.sendMessage(JSONObject.toJSONString(msgUserInfo));

        //  薪酬保存
        if (ftbPersonnelsSecondmentManagement.getIsResetSalary() == 1
                && StringUtils.isNotEmpty(ftbPersonnelsSecondmentManagement.getSalaryStructureList())){
            extracted(ftbPersonnelsSecondmentManagement);
        }
        return null;
    }

    /**
     *校验是否在审批中
     * @param userId
     */
    public void  checkWhetherItIsInTheProcessOfApproval(String userId){
        LambdaQueryWrapper<FtbPersonnelsSecondmentManagement> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FtbPersonnelsSecondmentManagement::getUserId, userId);
        queryWrapper.eq(FtbPersonnelsSecondmentManagement::getTransferStatus, FtbPersonnelsAuditTaskEnum.UNDER_REVIEW.getCode());
        queryWrapper.eq(FtbPersonnelsSecondmentManagement::getEnableMark,0);
        boolean b = baseMapper.selectCount(queryWrapper) > 0;
        if (b) throw new RuntimeException("该员工存在借调审批中，请勿重复操作!");
        LambdaQueryWrapper<FtbPersonnelsStaffRoster> queryWrapper1 = Wrappers.lambdaQuery();
        queryWrapper1.eq(FtbPersonnelsStaffRoster::getWorkerStatus,"304");
        queryWrapper1.eq(FtbPersonnelsStaffRoster::getUserId, userId);
        queryWrapper1.eq(FtbPersonnelsStaffRoster::getEnabledMark,0);
        long count = staffRosterService.count(queryWrapper1);
        if (count > 0) throw new RuntimeException("该员工处于待离职,不允许办理借调!");
        String checkIsInTheProcessForOA = ftbPersonnelsAuditRunTaskService.checkWhetherTheCheckIsInTheProcessForOA(userId);
        if (StrUtil.isNotBlank(checkIsInTheProcessForOA)) {
            throw new RuntimeException(checkIsInTheProcessForOA);
        }
    }


    /**
     * 校验借调时间
     * @param userId
     * @param secondedStartTime
     * @param secondedEndTime
     */
    private void checkTheSecondmentTime(String userId, Date secondedStartTime, Date secondedEndTime){
        if(secondedStartTime.equals(secondedEndTime)) throw new RuntimeException("借调开始时间和结束时间不能相同!");
        if(secondedStartTime.before(new Date())) throw new RuntimeException("借调开始时间不能早于当前时间!");
        if(secondedEndTime.before(secondedStartTime)) throw new RuntimeException("借调结束时间不能早于借调开始时间!");
        int count  =   baseMapper.checkTheSecondmentTime(userId, secondedStartTime, secondedEndTime);
        if (count > 0){
            throw new RuntimeException("借调时间存在交叉且其中包含未结束的借调记录,不能重复发起");
        }
        // 外出审批中校验
        Integer userWorkByTimeSlot =  baseMapper.getUserGoOut(userId, null, null);
        Integer goOutForDay =  baseMapper.getUserGoOutForDay(userId, null, null);
        if ((null != userWorkByTimeSlot && userWorkByTimeSlot > 0) || (null != goOutForDay && goOutForDay > 0)) {
            throw  new RuntimeException("该员工当前处于外出申请审批流程中，不可办理其他业务！");
        }
        // 外出校验
        userWorkByTimeSlot =  baseMapper.getUserGoOut(userId, secondedStartTime, secondedEndTime);
        goOutForDay =  baseMapper.getUserGoOutForDay(userId, secondedStartTime, secondedEndTime);
        if ((null != userWorkByTimeSlot && userWorkByTimeSlot > 0) || (null != goOutForDay && goOutForDay > 0)) {
            throw  new RuntimeException("申请时间段内已有申请通过的外出申请，请重新选择！");
        }
        // 出差审批中校验
        Integer businessTrip =  baseMapper.getBusinessTrip(userId, null, null);
        if (null != businessTrip && businessTrip > 0) {
            throw  new RuntimeException("该员工当前处于出差申请审批流程中，不可办理其他业务！");
        }
        // 出差校验
        businessTrip =  baseMapper.getBusinessTrip(userId, secondedStartTime, secondedEndTime);
        if (null != businessTrip && businessTrip > 0) {
            throw  new RuntimeException("申请时间段内已有申请通过的出差申请，请重新选择！");
        }
        String lockedCheck = salaryService.lochCheck(userId, null, null);
        if (StringUtils.isNotEmpty(lockedCheck)) {
            throw new RuntimeException("当前人员存在审批中的调薪,不允许办理借调！");
        }
    }
    /**
     * 校验借调时间
     * @param userId
     * @param secondedStartTime
     * @param secondedEndTime
     */
    private void checkTheSecondmentDelayTime(String userId, Date secondedStartTime, Date secondedEndTime){
        if(secondedStartTime.equals(secondedEndTime)) throw new RuntimeException("借调开始时间和结束时间不能相同!");
        if(secondedStartTime.before(new Date())) throw new RuntimeException("借调开始时间不能早于当前时间!");
        if(secondedEndTime.before(secondedStartTime)) throw new RuntimeException("借调结束时间不能早于借调开始时间!");
        int count  =   baseMapper.checkTheSecondmentTime(userId, secondedStartTime, secondedEndTime);
        if (count > 0){
            throw new RuntimeException("借调时间存在交叉且其中包含未结束的借调记录,延长失败!");
        }
        // 外出审批中校验
        Integer userWorkByTimeSlot =  baseMapper.getUserGoOut(userId, null, null);
        Integer goOutForDay =  baseMapper.getUserGoOutForDay(userId, null, null);
        if ((null != userWorkByTimeSlot && userWorkByTimeSlot > 0) || (null != goOutForDay && goOutForDay > 0)) {
            throw  new RuntimeException("申请时间段内已有申请中的外出申请，延长失败！");
        }
        // 外出校验
        userWorkByTimeSlot =  baseMapper.getUserGoOut(userId, secondedStartTime, secondedEndTime);
        goOutForDay =  baseMapper.getUserGoOutForDay(userId, secondedStartTime, secondedEndTime);
        if ((null != userWorkByTimeSlot && userWorkByTimeSlot > 0) || (null != goOutForDay && goOutForDay > 0)) {
            throw  new RuntimeException("申请时间段内已有申请通过的外出申请，延长失败！");
        }
        // 出差审批中校验
        Integer businessTrip =  baseMapper.getBusinessTrip(userId, null, null);
        if (null != businessTrip && businessTrip > 0) {
            throw  new RuntimeException("申请时间段内已有申请中的出差申请，延长失败！");
        }
        // 出差校验
        businessTrip =  baseMapper.getBusinessTrip(userId, secondedStartTime, secondedEndTime);
        if (null != businessTrip && businessTrip > 0) {
            throw  new RuntimeException("申请时间段内已有申请通过的出差申请，延长失败！");
        }
        String lockedCheck = salaryService.lochCheck(userId, null, null);
        if (StringUtils.isNotEmpty(lockedCheck)) {
            throw new RuntimeException("当前人员存在审批中的调薪,延长失败！");
        }
    }

    @Override
    @Transactional
    public void delete(String id) {
        LambdaUpdateWrapper<FtbPersonnelsSecondmentManagement> wrapper = Wrappers.lambdaUpdate();
        wrapper.eq(FtbPersonnelsSecondmentManagement::getId, id);
        wrapper.set(FtbPersonnelsSecondmentManagement::getEnableMark, 1);
        baseMapper.update(new FtbPersonnelsSecondmentManagement(), wrapper);
    }

    @Override
    @GlobalTransactional
    public void handleSecondmentForOA(FtbHandleSecondmentDTO ftbHandleSecondmentDTO) {
        FtbPersonnelsSecondmentManagement secondmentManagement = FtbHandleSecondmentDTO.convertSecondmentManagement(ftbHandleSecondmentDTO);
        if (secondmentManagement.getOriginalPositionId().equals(secondmentManagement.getSecondedPositionId())
                && secondmentManagement.getSecondedOrganizationId().equals(secondmentManagement.getOriginalOrganizationId()))  throw new RuntimeException("原岗位和借调岗位不能相同!");
        // 薪资校验oa
        verifyTheSalary(
                secondmentManagement.getSecondmentStartTime(),
                secondmentManagement.getSecondmentEndTime(),
                secondmentManagement.getUserId());
        ActionResult<OrganizeGeneralDetailVO> result = v2OrganizeApi.organizeInfoById(null,
                secondmentManagement.getSecondedOrganizationId());
        // 组织
        checkWhetherItIsInTheProcessOfApproval(secondmentManagement.getUserId());
        // 提交时，需校验借调起止时间是否与该员工未开始的借调时间交叉重合
        checkTheSecondmentTime(secondmentManagement.getUserId(),
                secondmentManagement.getSecondmentStartTime(),
                secondmentManagement.getSecondmentEndTime());
        if (result!= null && result.getCode() == 200) {
            secondmentManagement.setSecondedOrganization(result.getData().getName());
        }
        // 岗位
        ActionResult<PositionVO> voActionResult = v2PositionApi.infoPosition(secondmentManagement.getSecondedPositionId());
        if (voActionResult!= null && voActionResult.getCode() == 200) {
            secondmentManagement.setSecondedPosition(voActionResult.getData().getFullName());
        }
        //  职级
        if (StringUtils.isNotEmpty(secondmentManagement.getSecondedRankId())) {
            ActionResult<GradeVO> gradeVOActionResult = v2GradesApi.infoGrade(secondmentManagement.getSecondedRankId());
            if (gradeVOActionResult!= null && gradeVOActionResult.getCode() == 200) {
                secondmentManagement.setSecondedRank(gradeVOActionResult.getData().getName());
            }
        }
        String originalOrganizationId = secondmentManagement.getOriginalOrganizationId();
        ActionResult<OrganizeGeneralDetailVO> result2 = v2OrganizeApi.organizeInfoById(null,
                originalOrganizationId);
        if (result2!= null && result2.getCode() == 200) {
            secondmentManagement.setOriginalOrganization(result2.getData().getName());
        }
        ActionResult<PositionVO> voActionResult2 = v2PositionApi.infoPosition(secondmentManagement.getOriginalPositionId());
        if (voActionResult2!= null && voActionResult2.getCode() == 200) {
            secondmentManagement.setOriginalPosition(voActionResult2.getData().getFullName());
        }
        if (StringUtils.isNotEmpty(secondmentManagement.getOriginalRankId())) {
            ActionResult<GradeVO> gradeVOActionResult2 = v2GradesApi.infoGrade(secondmentManagement.getOriginalRankId());
            if (gradeVOActionResult2!= null && gradeVOActionResult2.getCode() == 200) {
                secondmentManagement.setOriginalRank(gradeVOActionResult2.getData().getName());
            }
        }
        secondmentManagement.setTransferStatus(FtbPersonnelsAuditTaskEnum.UNDER_REVIEW.getCode());
        // 修改
        if (StringUtils.isNotEmpty(secondmentManagement.getId())){
            baseMapper.updateById(secondmentManagement);
        }else {
            baseMapper.insert(secondmentManagement);
        }
    }

    public void verifyTheSalary(Date startTime,Date endTime,String userId){
        List<Map<String, Object>> maps = salaryService.querySalaryIntersectionWithOtherBusiness(userId, startTime, endTime);
        if (maps.isEmpty()) return;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String str =  maps.stream()
                .map(v-> v.get("type")+"业务(于"+simpleDateFormat.format(v.get("time"))+"生效)")
                .collect(Collectors.joining(";"));
        throw new RuntimeException("当前办理借调的起止时间为" +
                simpleDateFormat.format(startTime) + "～" +
                simpleDateFormat.format(endTime) + "；" +
                "检测到当前人员有（" + (str) + "）" +
                "与当前办理借调的日期重叠，请重新选择借调起止日期！");
    }

    @Override
    @GlobalTransactional
    public void secondmentApproval(FtbPersonnelsAuditDto ftbPersonnelsAuditDto) {
        // 审批状态 0 否 1是
        String dtoFlag = ftbPersonnelsAuditDto.getFlag();
        FtbPersonnelsAuditTaskEnum em =  dtoFlag.equals("1") ?
                FtbPersonnelsAuditTaskEnum.EXAMINATION_PASSED :
                FtbPersonnelsAuditTaskEnum.AUDIT_NOT_PASSED;
        LambdaUpdateWrapper<FtbPersonnelsSecondmentManagement> wrapper = Wrappers.lambdaUpdate();
        wrapper.eq(FtbPersonnelsSecondmentManagement::getTaskInfoId, ftbPersonnelsAuditDto.getTaskId());
        wrapper.set(FtbPersonnelsSecondmentManagement::getTransferStatus, em.getCode());
        if (dtoFlag.equals("1")) {
            // 最终审批字段
            wrapper.set(FtbPersonnelsSecondmentManagement::getApprovalTime, new Date());
            wrapper.set(FtbPersonnelsSecondmentManagement::getLastApprovalUserId, UserProvider.getUser().getUserId());

        }
        baseMapper.update(new FtbPersonnelsSecondmentManagement(),wrapper);
        LambdaQueryWrapper<FtbPersonnelsSecondmentManagement> wrapper2 = Wrappers.lambdaQuery();
        wrapper2.eq(FtbPersonnelsSecondmentManagement::getTaskInfoId, ftbPersonnelsAuditDto.getTaskId());
        FtbPersonnelsSecondmentManagement selectOne = baseMapper.selectOne(wrapper2);
        if (dtoFlag.equals("1")){
            // 考勤人员通知
            SecondmentMsgUserInfo msgUserInfo = FtbHandleSecondmentDTO.convert(selectOne);
            msgUserInfo.setTenantId(UserProvider.getUser().getTenantId());
            secondmentConsumerSourceMsg.sendMessage(JSONObject.toJSONString(msgUserInfo));
        }
        //  薪酬保存
        if (dtoFlag.equals("1") && selectOne.getIsResetSalary() == 1
                && StringUtils.isNotEmpty(selectOne.getSalaryStructureList())){
            extracted(selectOne);
        }
    }

    private void extracted(FtbPersonnelsSecondmentManagement selectOne) {
        List<FtbPersonnelsSalaryInfo> salaryInfos = JSONObject.parseArray(selectOne.getSalaryStructureList(), FtbPersonnelsSalaryInfo.class);
        UserInfoWithSalary userInfoWithSalary = getUserInfoWithSalary(selectOne);
        LambdaQueryWrapper<FtbPersonnelsStaffRoster> queryWrapper2 = Wrappers.lambdaQuery();
        queryWrapper2.eq(FtbPersonnelsStaffRoster::getUserId, selectOne.getUserId());
        FtbPersonnelsStaffRoster staffRoster = staffRosterService.getOne(queryWrapper2);
        userInfoWithSalary.setUserTypeId(staffRoster.getWorkerType());
        userInfoWithSalary.setEntryDate(staffRoster.getActualStartDate());
        userInfoWithSalary.setBeComeDate(staffRoster.getActualProbationaryDate() == null ? staffRoster.getActualStartDate() : staffRoster.getActualProbationaryDate());
        userInfoWithSalary.setTaskId(selectOne.getTaskInfoId());
        List<FtbPersonnelsSalaryInfo> personSSalary = salaryService.getTheCurrentPersonSSalary(selectOne.getUserId(),
                selectOne.getOriginalPositionId(), selectOne.getOriginalRankId());
        LambdaUpdateWrapper<FtbPersonnelsSecondmentManagement> wrapper = Wrappers.lambdaUpdate();
        if (CollUtil.isNotEmpty(personSSalary)){
            wrapper.set(FtbPersonnelsSecondmentManagement::getBeforeSalaryStructureList,
                    JSONObject.toJSONString(personSSalary));
        }
        String recordId = salaryService.saveTheChangePayInformation(salaryInfos,
                selectOne.getUserId(),
                selectOne.getSecondmentStartTime(),
                userInfoWithSalary,
                "1",
                selectOne.getSecondmentRemarks(),
                "9",
                0,
                selectOne.getSalaryType(),
                selectOne.getPayrollSequenceId(), UserProvider.getUser().getTenantId());
        wrapper.set(FtbPersonnelsSecondmentManagement::getSalaryRecordId, recordId);
        wrapper.eq(FtbPersonnelsSecondmentManagement::getId, selectOne.getId());
        baseMapper.update(null, wrapper);
    }

    @Override
    @GlobalTransactional
    public void secondmentWithdrawal(FtbPersonnelsAuditDto ftbPersonnelsAuditDto) {
        // 撤销
        LambdaUpdateWrapper<FtbPersonnelsSecondmentManagement> wrapper = Wrappers.lambdaUpdate();
        wrapper.eq(StringUtils.isNotEmpty(ftbPersonnelsAuditDto.getTaskId()) ,FtbPersonnelsSecondmentManagement::getTaskInfoId, ftbPersonnelsAuditDto.getTaskId());
        wrapper.eq(StringUtils.isNotEmpty(ftbPersonnelsAuditDto.getBusinessId()) ,FtbPersonnelsSecondmentManagement::getId, ftbPersonnelsAuditDto.getBusinessId());
        wrapper.set(FtbPersonnelsSecondmentManagement::getTransferStatus, FtbPersonnelsAuditTaskEnum.CANCEL.getCode());
        baseMapper.update(null, wrapper);
        LambdaQueryWrapper<FtbPersonnelsSecondmentManagement> wrapper1 = Wrappers.lambdaQuery();
        wrapper1.eq(StringUtils.isNotEmpty(ftbPersonnelsAuditDto.getTaskId()) ,FtbPersonnelsSecondmentManagement::getTaskInfoId, ftbPersonnelsAuditDto.getTaskId());
        wrapper1.eq(StringUtils.isNotEmpty(ftbPersonnelsAuditDto.getBusinessId()) ,FtbPersonnelsSecondmentManagement::getId, ftbPersonnelsAuditDto.getBusinessId());
        FtbPersonnelsSecondmentManagement vo = baseMapper.selectOne(wrapper1);
        // 如果使用了薪酬模版 需要 进行数据撤销回滚
        if (1  == vo.getIsResetSalary()) {
            // 撤销成功
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String format = sdf.format(vo.getSecondmentStartTime());
            salaryService.voidSalary(vo.getUserId(),format,vo.getSalaryRecordId());
        }
        // 考勤人员通知
        SecondmentMsgUserInfo msgUserInfo = FtbHandleSecondmentDTO.convert(vo);
        msgUserInfo.setTenantId(UserProvider.getUser().getTenantId());
        secondmentConsumerSourceMsg.sendMessageSecondmentWithdrawal(JSONObject.toJSONString(msgUserInfo));
    }

    @Override
    @Transactional
    public void earlyEnd(Map<String, Object> map) {
        Date endTime = getEndTime(map);
        // 提前结束
        LambdaUpdateWrapper<FtbPersonnelsSecondmentManagement> wrapper = Wrappers.lambdaUpdate();
        wrapper.eq(FtbPersonnelsSecondmentManagement::getId, map.get("id"));
        wrapper.set(FtbPersonnelsSecondmentManagement::getAdvanceEndTime,endTime);
        baseMapper.update(new FtbPersonnelsSecondmentManagement(),wrapper );

        LambdaQueryWrapper<FtbPersonnelsSecondmentManagement> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FtbPersonnelsSecondmentManagement::getId, map.get("id"));
        FtbPersonnelsSecondmentManagement secondmentManagement = baseMapper.selectOne(queryWrapper);

        // 考勤人员通知
        SecondmentMsgUserInfo msgUserInfo = FtbHandleSecondmentDTO.convert(secondmentManagement);
        msgUserInfo.setTenantId(UserProvider.getUser().getTenantId());
        secondmentConsumerSourceMsg.sendMessageEarlyEnd(JSONObject.toJSONString(msgUserInfo));
    }

    @Override
    @Transactional
    public void delayTime(Map<String, Object> map) {
        Date endTime = getEndTime(map);
        // 延迟时间校验
        LambdaQueryWrapper<FtbPersonnelsSecondmentManagement> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FtbPersonnelsSecondmentManagement::getId, map.get("id"));
        FtbPersonnelsSecondmentManagement secondmentManagement = baseMapper.selectOne(queryWrapper);
        String userId = secondmentManagement.getUserId();
        checkTheSecondmentDelayTime(userId,secondmentManagement.getSecondmentEndTime(),endTime);
        // 延长时间
        LambdaUpdateWrapper<FtbPersonnelsSecondmentManagement> wrapper = Wrappers.lambdaUpdate();
        wrapper.eq(FtbPersonnelsSecondmentManagement::getId, map.get("id"));
        wrapper.set(FtbPersonnelsSecondmentManagement::getSecondmentEndTime, endTime);
        baseMapper.update(new FtbPersonnelsSecondmentManagement(),wrapper);

        // 考勤人员通知
        SecondmentMsgUserInfo msgUserInfo = FtbHandleSecondmentDTO.convert(secondmentManagement);
        msgUserInfo.setTenantId(UserProvider.getUser().getTenantId());
        secondmentConsumerSourceMsg.sendMessageExtend(JSONObject.toJSONString(msgUserInfo));
    }

    /**
     * 时间校验
     * @param map
     * @return
     */
    @NotNull
    private Date getEndTime(Map<String, Object> map) {
        return DateUtil.parse(String.valueOf(map.get("endTime")), DatePattern.NORM_DATETIME_MINUTE_PATTERN);
    }

    @Override
    public Boolean checkIsInTheProcess(String userId, Date startTime, Date endTime) {
        checkTheSecondmentTime(userId,startTime,endTime);
        return true;
    }

    @Override
    public void endByUserConfirm(String userId, Date leaveTime) {
        List<FtbPersonnelsSecondmentManagement> list = getIdList(userId, leaveTime);
        if (!list.isEmpty()) {
            list.forEach(secondmentManagement -> {
                LambdaUpdateWrapper<FtbPersonnelsSecondmentManagement> updateWrapper = Wrappers.lambdaUpdate();
                updateWrapper.eq(FtbPersonnelsSecondmentManagement::getId, secondmentManagement.getId());
                updateWrapper.set(FtbPersonnelsSecondmentManagement::getSecondmentEndTime, leaveTime);
                baseMapper.update(new FtbPersonnelsSecondmentManagement(),updateWrapper);
            });
        }
        // 并删除离职时间之后的调动数据
        LambdaUpdateWrapper<FtbPersonnelsSecondmentManagement> wrapper = Wrappers.lambdaUpdate();
        wrapper.gt(FtbPersonnelsSecondmentManagement::getSecondmentEndTime,leaveTime);
        wrapper.eq(FtbPersonnelsSecondmentManagement::getUserId,userId);
        wrapper.in(FtbPersonnelsSecondmentManagement::getTransferStatus,2,6);
        baseMapper.delete(wrapper);
        // 离职删除借调数据
        LambdaUpdateWrapper<FtbPersonnelsSecondmentManagement> wrapper1 = Wrappers.lambdaUpdate();
        wrapper1.eq(FtbPersonnelsSecondmentManagement::getUserId,userId);
        wrapper1.set(FtbPersonnelsSecondmentManagement::getEnableMark,1);
        baseMapper.update(new FtbPersonnelsSecondmentManagement(),wrapper1);
    }
    @Override
    public int checkWhetherThereIsASecondmentRecord(String userId, Date leaveTime) {
        return getIdList(userId, leaveTime).size();
    }

    @Override
    public List<FtbPersonnelsSecondmentVO> getSecondmentRecord(String userId, String startLeaveTime, String endLeaveTime) {
        return baseMapper.getSecondmentRecord(userId,startLeaveTime,endLeaveTime);
    }

    @Override
    public List<FtbPersonnelsSecondmentVO> getSecondmentRecordBath(FtbSecondMentQueryDTO dto) {
        return baseMapper.getSecondmentRecordBath(dto);
    }

    @Override
    @SneakyThrows
    public void checkSecondmentEnd(String tenantId) {
        TenantDataSourceUtil.switchTenant(tenantId);
        List<FtbPersonnelsSecondmentManagement> list = baseMapper.checkSecondmentEnd( DateUtil.date());
        // 批量处理, 薪资数据进行处理
        List<String> stringList = list.stream().map(secondmentManagement -> {
            List<FtbPersonnelsSalaryInfo> salaryInfos = JSONObject.parseArray(secondmentManagement.getBeforeSalaryStructureList(), FtbPersonnelsSalaryInfo.class);
            UserInfoWithSalary userInfoWithSalary = new UserInfoWithSalary();
            userInfoWithSalary.setRankName(secondmentManagement.getOriginalRank());
            userInfoWithSalary.setRankId(secondmentManagement.getOriginalRankId());
            userInfoWithSalary.setFOrgId(secondmentManagement.getOriginalOrganizationId());
            userInfoWithSalary.setFOrgName(secondmentManagement.getOriginalOrganization());
            userInfoWithSalary.setPostId(secondmentManagement.getOriginalPositionId());
            userInfoWithSalary.setPostName(secondmentManagement.getOriginalPosition());
            LambdaQueryWrapper<FtbPersonnelsStaffRoster> queryWrapper2 = Wrappers.lambdaQuery();
            queryWrapper2.eq(FtbPersonnelsStaffRoster::getUserId, secondmentManagement.getUserId());
            FtbPersonnelsStaffRoster staffRoster = staffRosterService.getOne(queryWrapper2);
            userInfoWithSalary.setBeComeDate(staffRoster.getActualProbationaryDate() == null ? staffRoster.getActualStartDate() : staffRoster.getActualProbationaryDate());
            userInfoWithSalary.setEntryDate(staffRoster.getActualStartDate());
            userInfoWithSalary.setUserTypeId(staffRoster.getWorkerType());
            try {
                Date date = secondmentManagement.getAdvanceEndTime() != null ? secondmentManagement.getAdvanceEndTime() : secondmentManagement.getSecondmentEndTime();
                // 将时间推迟一天 并格式为 yyyy-MM-dd 00:00:00
                date = DateUtil.offsetDay(date, 1);
                date = DateUtil.beginOfDay(date);
                salaryService.saveTheChangePayInformation(salaryInfos,
                        secondmentManagement.getUserId(),
                        date,
                        userInfoWithSalary,
                        "1",
                        "借调返岗",
                        "10",// 借调返岗
                        0,
                        secondmentManagement.getSalaryType(),
                        secondmentManagement.getPayrollSequenceId(), UserProvider.getUser().getTenantId());
            }catch (Exception e) {
                e.printStackTrace();
                return  null;
            }
            return secondmentManagement.getId();
        }).filter(Objects::nonNull).collect(Collectors.toList());
        if (stringList.isEmpty()) {
            return;
        }
        LambdaUpdateWrapper<FtbPersonnelsSecondmentManagement> wrapper = Wrappers.lambdaUpdate();
        wrapper.in(FtbPersonnelsSecondmentManagement::getId, stringList);
        wrapper.set(FtbPersonnelsSecondmentManagement::getBeforeSalaryStructureList,null);
        baseMapper.update(new FtbPersonnelsSecondmentManagement(),wrapper);
        log.error("定时任务借调返岗执行成功：{}", DateUtil.formatDate(new Date()));
    }

    @Override
    public List<FtbPersonnelsSecondmentManagement> getIdList(String userId, Date leaveTime){
        return baseMapper.getIdList(userId,leaveTime);
    }

    @Override
    public List<FtbPersonnelsSecondmentManagement> salarySecondmentCrossover(String userId, Date leaveTime) {
        List<FtbPersonnelsSecondmentManagement> idList = baseMapper.getIdList(userId, leaveTime);
        if (idList != null && !idList.isEmpty()) {
            return idList;
        }
        return new ArrayList<>();
    }

    @Override
    public List<DailyApprovalVo> queryListApproval(FtbSecondMentQueryDTO dto) {
        return baseMapper.queryListApproval(dto);
    }

    @Override
    @GlobalTransactional
    public void cancel(String id) {
        FtbPersonnelsSecondmentManagement vo = baseMapper.selectById(id);
        Date secondedStartTime = vo.getSecondmentStartTime();
        Date secondedEndTime = vo.getSecondmentEndTime();
        String userId = vo.getUserId();
        boolean byUserIdAndTime = attendanceDailyRuleService.hasRuleByUserIdAndTime(userId, secondedStartTime, secondedEndTime);
        if (byUserIdAndTime) {
            throw new RuntimeException("在借调考勤组已产生申请记录或排班记录；无法作废！");
        }
        // 直接删除记录
        baseMapper.deleteById(id);
        // 撤销薪资
        if (1  == vo.getIsResetSalary()) {
            // 撤销成功
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String format = sdf.format(secondedStartTime);
            salaryService.voidSalary(userId,format, vo.getSalaryRecordId());
        }
        // 考勤人员通知
        SecondmentMsgUserInfo msgUserInfo = FtbHandleSecondmentDTO.convert(vo);
        msgUserInfo.setTenantId(UserProvider.getUser().getTenantId());
        secondmentConsumerSourceMsg.sendMessageSecondmentWithdrawal(JSONObject.toJSONString(msgUserInfo));
    }

    @NotNull
    private  UserInfoWithSalary getUserInfoWithSalary(FtbPersonnelsSecondmentManagement secondmentManagement) {
        UserInfoWithSalary userInfoWithSalary = new UserInfoWithSalary();
        userInfoWithSalary.setRankName(secondmentManagement.getSecondedRank());
        userInfoWithSalary.setRankId(secondmentManagement.getSecondedRankId());
        userInfoWithSalary.setFOrgId(secondmentManagement.getSecondedOrganizationId());
        userInfoWithSalary.setFOrgName(secondmentManagement.getSecondedOrganization());
        userInfoWithSalary.setPostId(secondmentManagement.getSecondedPositionId());
        userInfoWithSalary.setPostName(secondmentManagement.getSecondedPosition());
        return userInfoWithSalary;
    }
}
