package com.yifu.cloud.plus.v1.yifu.archives.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
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.fasc.open.api.exception.ApiException;
import com.yifu.cloud.plus.v1.yifu.admin.api.entity.SysUser;
import com.yifu.cloud.plus.v1.yifu.archives.config.WxConfig;
import com.yifu.cloud.plus.v1.yifu.archives.entity.*;
import com.yifu.cloud.plus.v1.yifu.archives.mapper.TEmployeeContractPreHistoryMapper;
import com.yifu.cloud.plus.v1.yifu.archives.mapper.TEmployeeContractPreMapper;
import com.yifu.cloud.plus.v1.yifu.archives.service.*;
import com.yifu.cloud.plus.v1.yifu.archives.vo.*;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.ClientNameConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.SecurityConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.*;
import com.yifu.cloud.plus.v1.yifu.common.core.vo.BaseSearchVO;
import com.yifu.cloud.plus.v1.yifu.common.core.vo.YifuUser;
import com.yifu.cloud.plus.v1.yifu.common.dapr.util.SocialDaprUtils;
import com.yifu.cloud.plus.v1.yifu.common.dapr.util.UpmsDaprUtils;
import com.yifu.cloud.plus.v1.yifu.common.security.util.SecurityUtils;
import com.yifu.cloud.plus.v1.yifu.social.vo.TEmployeeInsuranceWorkDayVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 合同待签订任务记录表
 *
 * @author huych
 * @date 2025-06-11 14:15:53
 */
@Log4j2
@Service
@RequiredArgsConstructor
public class TEmployeeContractPreServiceImpl extends ServiceImpl<TEmployeeContractPreMapper, TEmployeeContractPre> implements TEmployeeContractPreService {

	private final TEmployeeContractPreHistoryMapper tEmployeeContractPreHistoryMapper;
	private final TSettleDomainService tSettleDomainService;

	private final TEmployeeContractAuditService tEmployeeContractAuditService;

	private final FascService fascService;

	private final TContractAutoLogService contractAutoLogService;

	@Autowired
	private final TEmployeeContractInfoService contractInfoService;

	@Autowired
	private WxConfig wxConfig;

	@Autowired
	private UpmsDaprUtils upmsDaprUtils;

	@Lazy
	private final TAttaInfoService attaInfoService;
	
	@Autowired
	private SocialDaprUtils socialDaprUtils;

    /**
     * 合同待签订任务记录表简单分页查询
     * @param tEmployeeContractPre 合同待签订任务记录表
     * @return
     */
    @Override
    public IPage<TEmployeeContractPre> getTEmployeeContractPrePage(Page<TEmployeeContractPre> page, TEmployeeContractPreSearchVo tEmployeeContractPre){
		//权限赋值
		initSearchVo(tEmployeeContractPre);
		if (Common.isEmpty(tEmployeeContractPre.getProcessStatus()) && Common.isEmpty(tEmployeeContractPre.getStatusList())) {
			tEmployeeContractPre.setStatusList(Stream.of("0","1","2","3","4","5","6","7","8","11").collect(Collectors.toList()));
		}
		return baseMapper.getTEmployeeContractPrePage(page,tEmployeeContractPre);
    }

	/**
	 * 合同待签订任务记录表手机端不分页查询
	 * @param tEmployeeContractPre 合同待签订任务记录表
	 * @return
	 */
	@Override
	public List<TEmployeeContractPre> getTEmployeeContractPreNoPage(TEmployeeContractPreSearchVo tEmployeeContractPre) {
		//权限赋值
		tEmployeeContractPre.setType(CommonConstants.ONE_STRING);
		initSearchVo(tEmployeeContractPre);
		if (Common.isEmpty(tEmployeeContractPre.getStatusList())) {
			tEmployeeContractPre.setStatusList(Stream.of("0").collect(Collectors.toList()));
		}
		return baseMapper.getTEmployeeContractPreNoPage(tEmployeeContractPre);
	}

	/**
	 * 合同待签订数量查询
	 * @param tEmployeeContractPre 合同待签订任务记录表
	 * @return
	 */
	@Override
	public long getTEmployeeContractCount(TEmployeeContractPreSearchVo tEmployeeContractPre) {
		//权限赋值
		if (Common.isEmpty(tEmployeeContractPre.getType())) {
			tEmployeeContractPre.setType(CommonConstants.ONE_STRING);
		}
		initSearchVo(tEmployeeContractPre);
		if (Common.isEmpty(tEmployeeContractPre.getProcessStatus())&& Common.isEmpty(tEmployeeContractPre.getStatusList())) {
			tEmployeeContractPre.setStatusList(Stream.of("0","1","2","3","4","5","6","7","8","11").collect(Collectors.toList()));
		}
		return baseMapper.getTEmployeeContractPreExportCount(tEmployeeContractPre);
	}

	/**
     * 合同待签订任务记录表批量导出
     * @param searchVo 合同待签订任务记录表
     * @return
     */
    @Override
    public void listExport(HttpServletResponse response, TEmployeeContractPreSearchVo searchVo){
        String fileName = "合同待签订任务记录批量导出" + DateUtil.getThisTime() + ".xlsx";
        //获取要导出的列表
        List<TEmployeeContractPreExportVo> list = new ArrayList<>();
		//权限赋值
		initSearchVo(searchVo);
		if (Common.isEmpty(searchVo.getProcessStatus())&& Common.isEmpty(searchVo.getStatusList())) {
			searchVo.setStatusList(Stream.of("0","1","2","3","4","5","6","7","8","11").collect(Collectors.toList()));
		}
        long count = baseMapper.getTEmployeeContractPreExportCount(searchVo);
        try(ServletOutputStream out = response.getOutputStream();) {
            response.setContentType(CommonConstants.MULTIPART_FORM_DATA);
            response.setCharacterEncoding("utf-8");
            response.setHeader(CommonConstants.CONTENT_DISPOSITION, CommonConstants.ATTACHMENT_FILENAME + URLEncoder.encode(fileName  , CommonConstants.UTF8));
            //这里需要指定写用哪个class去写，然后写到第一个sheet，然后文件流会自动关闭
            ExcelWriter excelWriter = EasyExcel.write(out, TEmployeeContractPreExportVo.class).build();
            int index = 0;
            if (count > CommonConstants.ZERO_INT){
                for (int i = 0; i <= count; i += CommonConstants.EXCEL_EXPORT_LIMIT) {
                    // 获取实际记录
                    searchVo.setLimitStart(i);
                    searchVo.setLimitEnd(CommonConstants.EXCEL_EXPORT_LIMIT);
                    list = baseMapper.getTEmployeeContractPreExport(searchVo);
                    if (Common.isNotNull(list)){
                        WriteSheet writeSheet = EasyExcel.writerSheet("合同待签订任务记录"+index).build();
                        excelWriter.write(list,writeSheet);
                        index++;
                    }
                    if (Common.isNotNull(list)){
                        list.clear();
                    }
                }
            }else {
                WriteSheet writeSheet = EasyExcel.writerSheet("合同待签订任务记录"+index).build();
                excelWriter.write(list,writeSheet);
            }
            if (Common.isNotNull(list)){
                list.clear();
            }
            excelWriter.finish();
        }catch (Exception e){
            log.error("执行异常" ,e);
        }
    }

	/**
	 * 保存合同待签订
	 * @param preVo 合同待签订的视图对象，包含待保存的合同预信息
	 * @return 如果保存成功返回true，否则返回false或null
	 */
	@Override
	public Boolean saveContractPreInfo(TEmployeeContractPreVo preVo) {
		// 检查传入的视图对象是否不为空
		if (null != preVo) {
			try {
				// 判断是否存在合同待签订信息
				TEmployeeContractPre preExit = baseMapper.selectOne(Wrappers.<TEmployeeContractPre>query().lambda()
						.eq(TEmployeeContractPre::getRegisterId, preVo.getRegisterId())
						.eq(TEmployeeContractPre::getEmpIdcard, preVo.getEmpIdcard())
						.eq(TEmployeeContractPre::getDeptNo, preVo.getDeptNo())
						.last(CommonConstants.LAST_ONE_SQL));
				// 创建一个新的合同待签订对象
				TEmployeeContractPre pre = new TEmployeeContractPre();
				// 将视图对象中的属性复制到合同待签订对象中
				BeanUtils.copyProperties(preVo, pre);
				// 如果预期领取时间不为空，则将其转换为LocalDateTime类型并设置
				if (Common.isNotNull(preVo.getExpectedCollectionTime())) {
					pre.setExpectedCollectionTime(LocalDateTimeUtils.dateToLocalDateTime(preVo.getExpectedCollectionTime()));
				}
				// 如果预期确认时间不为空，则将其转换为LocalDateTime类型并设置
				if (Common.isNotNull(preVo.getExpectedConfirmTime())) {
					pre.setExpectedConfirmTime(LocalDateTimeUtils.dateToLocalDateTime(preVo.getExpectedConfirmTime()));
				}
				// 如果已存在合同预信息，则删除旧的信息并插入新的信息
				if (Common.isNotNull(preExit)) {
					baseMapper.deleteById(preExit);
					//附件信息清空
					LambdaUpdateWrapper<TAttaInfo> updateWrapperContract = new LambdaUpdateWrapper<>();
					// 设置更新条件和新值
					updateWrapperContract.eq(TAttaInfo::getDomainId, preExit.getId())
							.set(TAttaInfo::getDomainId, CommonConstants.EMPTY_STRING);
					// 执行更新操作，清空附件的关联ID
					attaInfoService.update(updateWrapperContract);
					pre.setId(preExit.getId());
					baseMapper.insert(pre);
				} else {
					// 如果不存在，则直接插入新的合同预信息
					baseMapper.insert(pre);
				}
				// 暂时不需要，先注释，后续可能会需要
				// if (Common.isNotNull(pre.getExpectedCollectionTime())) {
				//     // 事务提交后触发调度
				//     TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
				//         @Override
				//         public void afterCommit() {
				//             LocalDateTime now = LocalDateTime.now();
				//             if (pre.getExpectedCollectionTime().isEqual(now)) {
				//                 scheduleService.executeTask(pre.getId());
				//             } else if (preVo.getExpectedCollectionTime().compareTo(LocalDateTimeUtils.convertLDTToDate(now)) > 0){
				//                 scheduleService.scheduleTask(pre);
				//             }
				//         }
				//     });
				// }
			} catch (Exception e) {
				// 记录执行异常信息
				log.error("执行异常", e);
				// 异常情况下返回null
				return null;
			}
		}
		// 保存成功返回true
		return true;
	}


	/**
	 * 确认合同待签订列表
	 * 此方法用于将选定的合同待签订状态从"未处理"更新为"已处理"
	 * 它首先查询具有给定ID且处于未处理状态的合同预览如果找到符合条件的合同预览，它将它们的状态更新为已处理
	 * 如果没有找到任何符合条件的合同预览，它将返回一个失败的消息
	 *
	 * @param idList 合同待签订的ID列表，代表需要确认的合同
	 * @return 返回一个表示操作结果的R对象如果操作成功，返回R.ok()，否则返回R.failed()，包含错误消息
	 */
	@Override
	public R confirm(List<String> idList) {
		// 查询给定ID列表中所有未处理的合同待签订
		List<TEmployeeContractPre> contractPreList = baseMapper.selectList(Wrappers.<TEmployeeContractPre>query()
				.lambda().in(TEmployeeContractPre::getId, idList)
				.eq(TEmployeeContractPre::getProcessStatus, CommonConstants.ZERO_STRING));
		// 如果没有找到任何未处理的合合同待签订，返回失败消息
		if (Common.isEmpty(contractPreList)) {
			return R.failed(CommonConstants.NO_DATA_TO_HANDLE);
		}
		// 准备更新条件，将找到的合同待签订状态从"未处理"更新为"已处理"
		LambdaUpdateWrapper<TEmployeeContractPre> updateWrapper = new LambdaUpdateWrapper<>();
		updateWrapper.in(TEmployeeContractPre::getId, idList)
				.eq(TEmployeeContractPre::getProcessStatus, CommonConstants.ZERO_STRING)
				.set(TEmployeeContractPre::getProcessStatus, CommonConstants.ONE_STRING);
		// 执行更新操作
		this.update(updateWrapper);
		// 返回成功消息
		return R.ok();
	}

	@Override
	public R dispatcherContract(List<String> idList, String type) {
		List<TEmployeeContractPre> contractPreList;
		if ("2".equals(type)) {
			contractPreList = baseMapper.selectList(Wrappers.<TEmployeeContractPre>query()
					.lambda().in(TEmployeeContractPre::getId, idList)
					.in(TEmployeeContractPre::getProcessStatus, Arrays.asList("0","1","3","5","7","11")));
		} else {
			contractPreList = baseMapper.selectList(Wrappers.<TEmployeeContractPre>query()
					.lambda().in(TEmployeeContractPre::getId, idList)
					.in(TEmployeeContractPre::getProcessStatus, CommonConstants.contractDIsStatus));
		}
		// 如果没有找到任何未处理的合同待派单数据，返回失败消息
		if (Common.isEmpty(contractPreList)) {
			return R.failed(CommonConstants.NO_DATA_TO_HANDLE);
		}

		// 创建一个Map映射preId到TEmployeeContractPre对象
		Map<String, TEmployeeContractPre> preContractMap = contractPreList.stream()
				.collect(Collectors.toMap(TEmployeeContractPre::getId, pre -> pre));

		Map<String, String> loginNameMap = new HashMap<>();
		//发起派单
		List<ErrorMessage> errorMessageListAll = new ArrayList<>();
		List<EmployeeContractVO> excelVOList = baseMapper.getDisPatcherContractList(idList,Arrays.asList("0","1","3","5","7","11"),type);

		// 拆分电子签和线下签
		List<EmployeeContractVO> electronicSignList = new ArrayList<>();
		List<EmployeeContractVO> offlineSignList = new ArrayList<>();

		if (Common.isNotNull(excelVOList) && !excelVOList.isEmpty()) {
			for (EmployeeContractVO contractVO : excelVOList) {
				TEmployeeContractPre contractPre = preContractMap.get(contractVO.getPreId());
				if (contractPre != null && "0".equals(contractPre.getSignType())) {
					// 电子签
					electronicSignList.add(contractVO);
				} else {
					// 线下签
					offlineSignList.add(contractVO);
				}
			}
		}

		// 按前端客服分组统计
		Map<String, CustomerStatistics> customerStatisticsMap = new HashMap<>();

		// 处理电子签合同
		if (!electronicSignList.isEmpty()) {
			LocalDate currentDate = LocalDate.now();

			for (EmployeeContractVO contractVO : electronicSignList) {
				TEmployeeContractPre contractPre = preContractMap.get(contractVO.getPreId());
				if (contractPre != null && contractPre.getJoinLeaveDate() != null) {
					if ("2".equals(type) && Common.isNotNull(contractPre.getCustomerUserLoginname()) &&
							null == loginNameMap.get(contractPre.getCustomerUserLoginname())) {
						UUID uuid = UUID.randomUUID();
						loginNameMap.put(contractPre.getCustomerUserLoginname(), uuid.toString());
					}
					// 获取或创建客服统计信息
					String customerLoginName = contractPre.getCustomerUserLoginname();
					CustomerStatistics customerStats = customerStatisticsMap.computeIfAbsent(customerLoginName, k -> {
						CustomerStatistics stats = new CustomerStatistics();
						stats.setCustomerUserLoginname(customerLoginName);
						stats.setCustomerUsername(contractPre.getCustomerUsername());
						return stats;
					});
					customerStats.setInitiatedCount(customerStats.getInitiatedCount() + 1);

					LocalDate localDate = contractPre.getJoinLeaveDate().toInstant()
							.atZone(ZoneId.systemDefault())
							.toLocalDate();
					localDate = localDate.plusMonths(1)
							.minusDays(1);
					// 判断是否超过入职日期一个月
					if (currentDate.isAfter(localDate)) {
						// 超过一个月，算电子签发起失败
						customerStats.setFailedCount(customerStats.getFailedCount() + 1);
						customerStats.setElectronicSignFailedCount(customerStats.getElectronicSignFailedCount() + 1);

						// 更新processStatus为电子签发起失败
						LambdaUpdateWrapper<TEmployeeContractPre> updateWrapper = new LambdaUpdateWrapper<>();
						updateWrapper.eq(TEmployeeContractPre::getId, contractPre.getId())
								.set(TEmployeeContractPre::getProcessStatus, CommonConstants.FIVE_STRING)
								.set(TEmployeeContractPre::getErrorInfo, "电子签发起失败：已超过入职日期一个月")
								.set(TEmployeeContractPre::getChangeTypeUser, type.equals("1") ? "自动化手动—" + contractPre.getCustomerUsername()
										: "自动化自动—" + contractPre.getCustomerUsername() )
								.set(TEmployeeContractPre::getChangeTypeReason, "已超过入职日期一个月,自动转线下签")
								.set(TEmployeeContractPre::getChangeTypeTime, LocalDateTimeUtils.convertLDToDate(LocalDate.now()))
								.set(TEmployeeContractPre::getSignType, CommonConstants.ONE_STRING)
								.set(TEmployeeContractPre::getErrorTime, LocalDateTime.now());
						this.update(updateWrapper);

						if ("2".equals(type)) {
							//生成快照数据
							TContractAutoLog contractAutoLog = new TContractAutoLog();
							contractAutoLog.setContractId(loginNameMap.get(contractPre.getCustomerUserLoginname()));
							contractAutoLog.setEmpName(contractPre.getEmployeeName());
							contractAutoLog.setEmpIdcard(contractPre.getEmpIdcard());
							contractAutoLog.setMainId(contractPre.getId());
							contractAutoLog.setErrorInfo("电子签发起失败：已超过入职日期一个月");
							contractAutoLogService.save(contractAutoLog);
						}

						// 添加错误信息
						ErrorMessage<EmployeeContractVO> errorMessage = new ErrorMessage<>(contractVO.getRowIndex(), "电子签发起失败：已超过入职日期一个月");
						errorMessage.setData(contractVO);
						errorMessageListAll.add(errorMessage);
					} else {
						// 未超过一个月，先调用contractInfoService.importContract方法创建合同
						List<EmployeeContractVO> singleContractList = new ArrayList<>();
						singleContractList.add(contractVO);
						List<ErrorMessage> singleErrorMessageList = new ArrayList<>();
						// 调用合同导入方法
						contractInfoService.importContract(singleContractList, singleErrorMessageList);

						// 检查合同创建是否成功
						boolean contractCreateSuccess = singleErrorMessageList.stream()
								.allMatch(message -> message.getMessage().equals(CommonConstants.SAVE_SUCCESS));

						if (!contractCreateSuccess) {
							// 合同创建失败，统计错误并更新状态
							customerStats.setFailedCount(customerStats.getFailedCount() + 1);
							customerStats.setElectronicSignFailedCount(customerStats.getElectronicSignFailedCount() + 1);

							String errorMsg = singleErrorMessageList.isEmpty() ? "合同创建失败" : singleErrorMessageList.get(0).getMessage();
							// 更新processStatus为电子签发起失败
							LambdaUpdateWrapper<TEmployeeContractPre> updateWrapper = new LambdaUpdateWrapper<>();
							updateWrapper.eq(TEmployeeContractPre::getId, contractPre.getId())
									.set(TEmployeeContractPre::getProcessStatus, CommonConstants.FIVE_STRING)
									.set(TEmployeeContractPre::getErrorInfo, errorMsg)
									.set(TEmployeeContractPre::getErrorTime, LocalDateTime.now());
							this.update(updateWrapper);

							if ("2".equals(type)) {
								//生成快照数据
								TContractAutoLog contractAutoLog = new TContractAutoLog();
								contractAutoLog.setContractId(loginNameMap.get(contractPre.getCustomerUserLoginname()));
								contractAutoLog.setEmpName(contractPre.getEmployeeName());
								contractAutoLog.setEmpIdcard(contractPre.getEmpIdcard());
								contractAutoLog.setErrorInfo(errorMsg);
								contractAutoLog.setMainId(contractPre.getId());
								contractAutoLogService.save(contractAutoLog);
							}
							// 添加错误信息
							ErrorMessage<EmployeeContractVO> errorMessage = new ErrorMessage<>(contractVO.getRowIndex(), errorMsg);
							errorMessage.setData(contractVO);
							errorMessageListAll.add(errorMessage);
						} else {
							// 合同创建成功，继续调用FascService的submitContract方法
							R<String> result = null;
							TEmployeeContractPre contract = baseMapper.selectById(contractPre.getId());
							// 复制一份快照
							TEmployeeContractPreHistory contractHistory = new TEmployeeContractPreHistory();
							if (contract != null && Common.isNotNull(contract.getId())) {
								BeanUtil.copyProperties(contract, contractHistory);
								contractHistory.setId(null);
								tEmployeeContractPreHistoryMapper.insert(contractHistory);
							}
							try {
								result = fascService.submitContract(contractPre.getId() );
							} catch (Exception e) {
								// 更新合同：
								if (Common.isNotNull(contract.getContractId())) {
									TEmployeeContractInfo empContract = contractInfoService.getById(contract.getContractId());
									empContract.setDeleteFlag(CommonConstants.ONE_INT);
									contractInfoService.updateById(empContract);
								}
								log.error("法大大推送执行异常", e);
							}
							if (result == null || result.getCode() != CommonConstants.SUCCESS) {
								customerStats.setFailedCount(customerStats.getFailedCount() + 1);
								customerStats.setElectronicSignFailedCount(customerStats.getElectronicSignFailedCount() + 1);
								String errorMsg = result != null ? result.getMsg() : "电子签发起失败";
								// 更新processStatus为电子签发起失败
								LambdaUpdateWrapper<TEmployeeContractPre> updateWrapper = new LambdaUpdateWrapper<>();
								updateWrapper.eq(TEmployeeContractPre::getId, contractPre.getId())
										.set(TEmployeeContractPre::getProcessStatus, CommonConstants.FIVE_STRING)
										.set(TEmployeeContractPre::getErrorInfo, errorMsg)
										.set(TEmployeeContractPre::getErrorTime, LocalDateTime.now());
								this.update(updateWrapper);
								// 更新合同：
								if (Common.isNotNull(contract.getContractId())) {
									TEmployeeContractInfo empContract = contractInfoService.getById(contract.getContractId());
									empContract.setDeleteFlag(CommonConstants.ONE_INT);
									contractInfoService.updateById(empContract);
								}

								if ("2".equals(type)) {
									//生成快照数据
									TContractAutoLog contractAutoLog = new TContractAutoLog();
									contractAutoLog.setContractId(loginNameMap.get(contractPre.getCustomerUserLoginname()));
									contractAutoLog.setEmpName(contractPre.getEmployeeName());
									contractAutoLog.setEmpIdcard(contractPre.getEmpIdcard());
									contractAutoLog.setErrorInfo(errorMsg);
									contractAutoLog.setMainId(contractPre.getId());
									contractAutoLogService.save(contractAutoLog);
								}
								// 添加错误信息
								ErrorMessage<EmployeeContractVO> errorMessage = new ErrorMessage<>(contractVO.getRowIndex(), errorMsg);
								errorMessage.setData(contractVO);
								errorMessageListAll.add(errorMessage);
							} else {
								if (Common.isNotNull(contractHistory.getId()) && Common.isNotNull(result.getData())) {
									contractHistory.setRequestId(result.getData());
									tEmployeeContractPreHistoryMapper.updateById(contractHistory);
								}
								if (Common.isNotNull(contract.getContractId())) {
									TEmployeeContractAudit audit = new TEmployeeContractAudit();
									audit.setRootName("签署中");
									audit.setLinkId(contract.getContractId());
									audit.setLinkType(CommonConstants.ONE_INT);
									audit.setCreateName("法大大电子签");
									audit.setCreateBy("1");
									tEmployeeContractAuditService.save(audit);
									// 如果之前是发起失败状态，清空错误信息
									if (CommonConstants.FIVE_STRING.equals(contractPre.getProcessStatus())) {
										LambdaUpdateWrapper<TEmployeeContractPre> clearErrorWrapper = new LambdaUpdateWrapper<>();
										clearErrorWrapper.eq(TEmployeeContractPre::getId, contractPre.getId())
												.set(TEmployeeContractPre::getErrorInfo, null)
												.set(TEmployeeContractPre::getErrorTime, null);
										this.update(clearErrorWrapper);
									}
								}
							}
						}
					}
				}
			}
		}
		
		// 处理线下签合同（走原逻辑）
		if (!offlineSignList.isEmpty()) {
			
			// 统计线下签的发起数量
			for (EmployeeContractVO contractVO : offlineSignList) {
				TEmployeeContractPre contractPre = preContractMap.get(contractVO.getPreId());
				if (contractPre != null) {
					String customerLoginName = contractPre.getCustomerUserLoginname();
					CustomerStatistics customerStats = customerStatisticsMap.computeIfAbsent(customerLoginName, k -> {
						CustomerStatistics stats = new CustomerStatistics();
						stats.setCustomerUserLoginname(customerLoginName);
						stats.setCustomerUsername(contractPre.getCustomerUsername());
						return stats;
					});
					customerStats.setInitiatedCount(customerStats.getInitiatedCount() + 1);
				}
			}
			
			List<EmployeeContractVO> disList;
			int k = 0;
			int i = (int) Math.ceil((double) offlineSignList.size() / CommonConstants.INTEGER_HUNDRED);
			for (int j = 0; j < i; j++) {
				if (j == i - 1) {
					disList = offlineSignList.subList(k, offlineSignList.size());
				} else {
					disList = offlineSignList.subList(k, k + 100);
				}
				k = k + 100;
				if (Common.isNotNull(disList)) {
					//调用批量派单接口100条处理一次，同原合同派单保持一致
					List<ErrorMessage> errorMessageList = new ArrayList<>();
					contractInfoService.importContract(disList, errorMessageList);
					if (!errorMessageList.stream().allMatch(message -> message.getMessage().equals(CommonConstants.SAVE_SUCCESS))) {
						errorMessageListAll.addAll(errorMessageList);
						//更新合同状态为5发起失败
						for (ErrorMessage errorMessage : errorMessageList) {
							if (!errorMessage.getMessage().equals(CommonConstants.SAVE_SUCCESS)) {
								EmployeeContractVO contractVO = disList.stream().filter(vo -> Objects.equals(vo.getRowIndex(), errorMessage.getLineNum())).collect(Collectors.toList()).get(0);
								
								// 获取合同预签订信息以便统计
								TEmployeeContractPre contractPre = preContractMap.get(contractVO.getPreId());
								if ("2".equals(type) && Common.isNotNull(contractPre.getCustomerUserLoginname()) &&
										null == loginNameMap.get(contractPre.getCustomerUserLoginname())) {
									UUID uuid = UUID.randomUUID();
									loginNameMap.put(contractPre.getCustomerUserLoginname(), uuid.toString());
								}
								if (contractPre != null) {
									String customerLoginName = contractPre.getCustomerUserLoginname();
									CustomerStatistics customerStats = customerStatisticsMap.computeIfAbsent(customerLoginName, key -> {
										CustomerStatistics stats = new CustomerStatistics();
										stats.setCustomerUserLoginname(customerLoginName);
										stats.setCustomerUsername(contractPre.getCustomerUsername());
										return stats;
									});
									customerStats.setFailedCount(customerStats.getFailedCount() + 1);
									customerStats.setOfflineSignFailedCount(customerStats.getOfflineSignFailedCount() + 1);
								}
								if ("2".equals(type)) {
									//生成快照数据
									TContractAutoLog contractAutoLog = new TContractAutoLog();
									contractAutoLog.setContractId(loginNameMap.get(contractPre.getCustomerUserLoginname()));
									contractAutoLog.setEmpName(contractPre.getEmployeeName());
									contractAutoLog.setEmpIdcard(contractPre.getEmpIdcard());
									contractAutoLog.setErrorInfo(errorMessage.getMessage());
									contractAutoLog.setMainId(contractPre.getId());
									contractAutoLogService.save(contractAutoLog);
								}

								LambdaUpdateWrapper<TEmployeeContractPre> updateWrapper = new LambdaUpdateWrapper<>();
								updateWrapper.in(TEmployeeContractPre::getId, contractVO.getPreId())
										.in(TEmployeeContractPre::getProcessStatus, CommonConstants.contractDIsStatus)
										.set(TEmployeeContractPre::getProcessStatus, CommonConstants.FIVE_STRING)
										.set(TEmployeeContractPre::getSignType, CommonConstants.ONE_STRING)
										.set(TEmployeeContractPre::getErrorInfo, errorMessage.getMessage())
										.set(TEmployeeContractPre::getErrorTime, LocalDateTime.now());
								// 执行更新操作
								errorMessage.setData(contractVO);
								this.update(updateWrapper);
							}
						}
					}
				}
			}
		}

		if ("2".equals(type)) {
			// 为每个前端客服发送企微消息
			for (Map.Entry<String, CustomerStatistics> entry : customerStatisticsMap.entrySet()) {
				CustomerStatistics stats = entry.getValue();
				if (stats.getFailedCount() > 0 && Common.isNotNull(stats.getCustomerUserLoginname())) {
					// 生成客服个人的汇总信息
					String customerSummaryInfo = String.format("合同签署发起总数：%d份，失败总数：%d份;\n" +
									"电子签失败份数：%d份，线下签失败份数：%d份",
							stats.getInitiatedCount(), 
							stats.getFailedCount(), 
							stats.getElectronicSignFailedCount(), 
							stats.getOfflineSignFailedCount());
					// 发送企微消息
					sendFailueMessageToWx(stats.getCustomerUserLoginname(), customerSummaryInfo, loginNameMap);
				}
			}
		}
		
		return R.ok(errorMessageListAll);
	}

	@Override
	public R revokeSign(List<TEmployeeAutoRegistRevokeVo> registRevokeVoList) {
		if (Common.isNotNull(registRevokeVoList)) {
			List<String> idList = registRevokeVoList.stream().map(TEmployeeAutoRegistRevokeVo::getId).collect(Collectors.toList());
			List<TEmployeeContractPre> contractPreList = baseMapper.selectList(Wrappers.<TEmployeeContractPre>query()
					.lambda().in(TEmployeeContractPre::getId, idList)
					.ne(TEmployeeContractPre::getProcessStatus, CommonConstants.NINE_STRING)
					.ne(TEmployeeContractPre::getProcessStatus, CommonConstants.FOUR_STRING)
					.ne(TEmployeeContractPre::getProcessStatus, CommonConstants.TEN_STRING)
					.ne(TEmployeeContractPre::getProcessStatus, CommonConstants.ELEVEN_STRING)
					.ne(TEmployeeContractPre::getProcessStatus, CommonConstants.EIGHT_STRING));
			if (Common.isEmpty(contractPreList)) {
				return R.failed(CommonConstants.NO_DATA_TO_HANDLE);
			}
			TEmployeeContractPre pre;
			TEmployeeContractInfo contractInfo;
			R<String> result;
			for (TEmployeeAutoRegistRevokeVo registRevokeVo : registRevokeVoList) {
				pre = baseMapper.selectById(registRevokeVo.getId());
				if (pre != null) {
					if (Common.isNotNull(pre.getSignType()) && CommonConstants.ZERO_STRING.equals(pre.getSignType())
							&& Common.isNotNull(pre.getRequestId())) {
						try {
							result = fascService.cancelTask(pre.getId());
							if (!R.isSuccess(result)) {
								// 产品暂未设计失败了怎么做
								return result;
							}
						} catch (ApiException e) {
							// 产品暂未设计失败了怎么做
							return R.failed("推送法大大失败！" + e.getMessage());
						}
					}
					//电子待归档、线下签待归档、已完结的不能撤销签署
					if (Common.isNotNull(pre) && !CommonConstants.NINE_STRING.equals(pre.getProcessStatus()) &&
							!CommonConstants.FOUR_STRING.equals(pre.getProcessStatus()) &&
							!CommonConstants.EIGHT_STRING.equals(pre.getProcessStatus())) {
						//如果不是待确认和待发起，需要记录操作记录
						if (!CommonConstants.ZERO_STRING.equals(pre.getProcessStatus()) &&
								!CommonConstants.ONE_STRING.equals(pre.getProcessStatus()) &&
								Common.isNotNull(pre.getContractId())) {
							TEmployeeContractAudit audit = new TEmployeeContractAudit();
							audit.setRootName("撤销签署");
							audit.setLinkId(pre.getContractId());
							audit.setLinkType(CommonConstants.ONE_INT);
							audit.setRemark(registRevokeVo.getReason());
							tEmployeeContractAuditService.save(audit);
						}
						pre.setProcessStatus(CommonConstants.TEN_STRING);
						pre.setSignFlag(CommonConstants.ZERO_STRING);
						pre.setRevokeReason(registRevokeVo.getReason());
						baseMapper.updateById(pre);
					}
					if (Common.isNotNull(pre.getContractId())) {
						//如果存在合同申请审核数据，将状态更新成待提交
						contractInfo = contractInfoService.getOne(Wrappers.<TEmployeeContractInfo>query()
								.lambda().eq(TEmployeeContractInfo::getId, pre.getContractId())
								.eq(TEmployeeContractInfo::getDeleteFlag, CommonConstants.ZERO_INT)
								.last(CommonConstants.LAST_ONE_SQL));
						if (Common.isNotNull(contractInfo)) {
							contractInfo.setAuditStatus(CommonConstants.FIVE_INT);
							contractInfo.setInUse(CommonConstants.ONE_STRING);
							contractInfoService.updateById(contractInfo);
						}
					}
				}
			}
		}
		return R.ok();
	}

	/**
	 * @Description: 获取前端客服的所有项目权限
	 * @Author: huych
	 * @Date: 2025/6/11 16:55
	 * @return:
	 **/
	public void initSearchVo(TEmployeeContractPreSearchVo searchVo) {
		YifuUser user = SecurityUtils.getUser();
		long roleId = 1839501715787390978L;
		boolean isSsc = this.haveRole(user, roleId);
		if (isSsc || CommonConstants.ZERO_STRING.equals(user.getSystemFlag())) {
			searchVo.setAuthSql(null);
			return;
		}
		if (Common.isNotNull(searchVo.getType()) && CommonConstants.ONE_STRING.equals(searchVo.getType())) {
			searchVo.setAuthSql(null);
			//获取项目信息
			List<String> deptNos = tSettleDomainService.getAllDeptByCustomerLoginName(user.getUsername());
			if (null != deptNos && !deptNos.isEmpty()) {
				searchVo.setDeptNoList(deptNos);
			} else {
				searchVo.setId(CommonConstants.ONE_STRING_NEGATE);
			}
		}
	}

	@Override
	public void pushWxConfrimMessage() {
		//获取所有预计派单时间为当天而且状态是待确认的合同待签署数据
		List<TEmployeeContractPre> unConfirmList = baseMapper.getAllUnconfimData();
		if (Common.isNotNull(unConfirmList) && !unConfirmList.isEmpty()) {
			for (TEmployeeContractPre pre : unConfirmList) {
				try {
					sendMessageToWx(pre);
				} catch (Exception e) {
					log.error("执行异常", e);
				}
			}
		}
	}

	@Override
	public void pushDisConfrimContracts() {
		//获取所有待派单的数据
		List<String> unConfirmList = baseMapper.getAllUnDisData();
		if (null != unConfirmList && !unConfirmList.isEmpty()) {
			try {
				this.dispatcherContract(unConfirmList,"2");
			} catch (Exception e) {
				log.error("执行异常", e);
			}
		}
	}

	@Override
	public Boolean checkContractPreIsExit(EmpProjectStatusVo vo) {
		TEmployeeContractPre contractPre = baseMapper.selectOne(Wrappers.<TEmployeeContractPre>query().lambda()
				.eq(TEmployeeContractPre::getEmpIdcard, vo.getEmpIdcard())
				.eq(TEmployeeContractPre::getDeptNo, vo.getDeptNo())
				.ne(TEmployeeContractPre::getProcessStatus, CommonConstants.TEN_STRING)
				.ne(TEmployeeContractPre::getProcessStatus, CommonConstants.ELEVEN_STRING)
				.ne(TEmployeeContractPre::getIsRefuse, CommonConstants.ZERO_STRING)
				.ne(TEmployeeContractPre::getIsLeave, CommonConstants.ZERO_STRING)
				.last(CommonConstants.LAST_ONE_SQL));
		if (Common.isNotNull(contractPre)) {
			//如果是已完结判断合同申请数据在不在用
			if (CommonConstants.NINE_STRING.equals(contractPre.getProcessStatus()) && Common.isNotNull(contractPre.getContractId())) {
				TEmployeeContractInfo contractInfo = contractInfoService.getOne(Wrappers.<TEmployeeContractInfo>query()
						.lambda().eq(TEmployeeContractInfo::getId, contractPre.getContractId())
						.eq(TEmployeeContractInfo::getDeleteFlag, CommonConstants.ZERO_INT)
						.eq(TEmployeeContractInfo::getInUse, CommonConstants.ZERO_STRING)
						.last(CommonConstants.LAST_ONE_SQL));
				return Common.isNotNull(contractInfo);
			} else {
				return true;
			}
		} else {
			return false;
		}
	}

	//发送企业微信待办
	private void sendMessageToWx(TEmployeeContractPre pre) {
		//获取前端客服
		SysUser user;
		if (Common.isEmpty(pre.getCustomerUserLoginname())) {
			return;
		}
		R<SysUser> res = upmsDaprUtils.getSimpleUserByLoginName(pre.getCustomerUserLoginname());
		if (Common.isNotNull(res) && Common.isNotNull(res.getData())) {
			user = res.getData();
		} else {
			return;
		}
		StringBuilder sendUser = null;
		if (Common.isNotKong(user.getWxMessage())) {
			sendUser = new StringBuilder(user.getWxMessage());
		}
		if (sendUser != null) {
			RestTemplate restTemplate = new RestTemplate();
			Map<String, Object> requestMap = new HashMap<>();
			Map<String, Object> textcard = new HashMap<>();
			String authUrl = String.format(SecurityConstants.WX_GET_MESSAGE_AUTH_URL, wxConfig.getCorpid(), wxConfig.getDomainName() + "/auth/oauth/wxLogin", "03" + pre.getCustomerUserLoginname());
			StringBuilder description = new StringBuilder();
			String title = "合同待签署确认";
			description.append("您有新的合同待签署确认数据，请及时确认").append("<br>");
			textcard.put("title", title);
			textcard.put("url", authUrl);
			textcard.put("description", description.toString());
			requestMap.put("touser", sendUser);
			requestMap.put("agentid", wxConfig.getAgentid());
			requestMap.put("msgtype", "textcard");
			requestMap.put("textcard", textcard);
			// 必须加上header说明
			if (!wxConfig.sendTextCard(restTemplate, requestMap)) {
				wxConfig.sendTextCard(restTemplate, requestMap);
			}
		}
	}


	//发送企业微信待办
	private void sendFailueMessageToWx(String loginName,String summary,Map<String, String> loginNameMap) {
		//获取前端客服
		SysUser user;
		if (Common.isEmpty(loginName)) {
			return;
		}
		R<SysUser> res = upmsDaprUtils.getSimpleUserByLoginName(loginName);
		if (Common.isNotNull(res) && Common.isNotNull(res.getData())) {
			user = res.getData();
		} else {
			return;
		}
		StringBuilder sendUser = null;
		if (Common.isNotKong(user.getWxMessage())) {
			sendUser = new StringBuilder(user.getWxMessage());
		}
		if (sendUser != null) {
			RestTemplate restTemplate = new RestTemplate();
			Map<String, Object> requestMap = new HashMap<>();
			Map<String, Object> textcard = new HashMap<>();
			String id = loginNameMap.get(loginName);
			String authUrl = String.format(SecurityConstants.WX_GET_MESSAGE_AUTH_URL, wxConfig.getCorpid(), wxConfig.getDomainName() + "/auth/oauth/wxLogin", "69" + id);
			StringBuilder description = new StringBuilder();
			String title = "作业自动化——合同签署发起失败提醒";
			description.append(summary).append("<br>");
			description.append("请及时至HRO系统处理，以免耽误签署进度！").append("<br>");
			textcard.put("title", title);
			textcard.put("url", authUrl);
			textcard.put("description", description.toString());
			requestMap.put("touser", sendUser);
			requestMap.put("agentid", wxConfig.getAgentid());
			requestMap.put("msgtype", "textcard");
			requestMap.put("textcard", textcard);
			// 必须加上header说明
			if (!wxConfig.sendTextCard(restTemplate, requestMap)) {
				wxConfig.sendTextCard(restTemplate, requestMap);
			}
		}
	}

	public boolean haveRole(YifuUser user, long roleId) {
		List<Long> roleList = user.getClientRoleMap().get(ClientNameConstants.CLIENT_MVP);
		for (Long role : roleList) {
			if (role == roleId) {
				return true;
			}
		}
		return false;
	}

	@Override
	public R autoRevokeElectronicSign() {
		try {
			// 查询符合条件的合同：状态为"签署中"(6) 且 为电子签任务(signType=0) 且 入职日期到当日正好一个月
			LocalDate currentDate = LocalDate.now();
			LocalDate oneMonthAgo = currentDate.minusMonths(1).plusDays(1);
			
			List<TEmployeeContractPre> contractsToRevoke = baseMapper.selectList(Wrappers.<TEmployeeContractPre>query()
					.lambda()
					.eq(TEmployeeContractPre::getProcessStatus, CommonConstants.SIX_STRING) // 签署中
					.eq(TEmployeeContractPre::getSignType, CommonConstants.ZERO_STRING) // 电子签
					.eq(TEmployeeContractPre::getJoinLeaveDate, LocalDateTimeUtils.convertLDToDate(oneMonthAgo)) // 入职日期正好一个月前
			);
			
			if (Common.isEmpty(contractsToRevoke)) {
				return R.ok("未找到需要撤销的超时电子签署任务");
			}

			for (TEmployeeContractPre contractPre : contractsToRevoke) {
				try {
					// 调用法大大撤销签署接口
					R<String> revokeResult = fascService.cancelTask(contractPre.getId());
					
					if (revokeResult.getCode() == 200) {
						// 撤销成功：状态更新为"待发起"(1) 且 签署方式变更为"线下签"(1)
						LambdaUpdateWrapper<TEmployeeContractPre> updateWrapper = new LambdaUpdateWrapper<>();
						updateWrapper.eq(TEmployeeContractPre::getId, contractPre.getId())
								.set(TEmployeeContractPre::getProcessStatus, CommonConstants.ELEVEN_STRING) // 11 撤销签署-系统自动撤销
								.set(TEmployeeContractPre::getSignType, CommonConstants.ONE_STRING) // 线下签
								.set(TEmployeeContractPre::getRevokeReason, "超时未签署自行变更为线下签")
								.set(TEmployeeContractPre::getChangeTypeReason, "超时未签署自行变更为线下签")
								.set(TEmployeeContractPre::getChangeTypeUser, "超管")
								.set(TEmployeeContractPre::getChangeTypeTime, DateUtil.getCurrentDateTime());
						this.update(updateWrapper);
						TEmployeeContractAudit audit = new TEmployeeContractAudit();
						audit.setRootName("撤销签署");
						audit.setCreateName("系统自动撤销");
						audit.setLinkId(contractPre.getContractId());
						audit.setLinkType(CommonConstants.ONE_INT);
						audit.setRemark("电子合同签署超过1个月未完成签署系统，自动撤销");
						tEmployeeContractAuditService.save(audit);

					} else if ("已完成签署".equals(revokeResult.getMsg())) {
						// 撤销失败原因为已完成签署：更新为签署完成的"待归档"状态(8)
						LambdaUpdateWrapper<TEmployeeContractPre> updateWrapper = new LambdaUpdateWrapper<>();
						updateWrapper.eq(TEmployeeContractPre::getId, contractPre.getId())
								.set(TEmployeeContractPre::getProcessStatus, CommonConstants.EIGHT_STRING); // 电子待归档
						this.update(updateWrapper);
						
					} else {
						// 其他撤销失败原因
						log.error("合同ID：{}，撤销失败，原因：{}", contractPre.getId(), revokeResult.getMsg());
					}
					
				} catch (Exception e) {
					log.error("处理合同ID：{}时发生异常", contractPre.getId(), e);
				}
			}
			return R.ok();
			
		} catch (Exception e) {
			log.error("执行自动撤销超时电子签署任务时发生异常", e);
			return R.failed("执行自动撤销超时电子签署任务时发生异常：" + e.getMessage());
		}
	}

	@Override
	public R notifyRevokedElectronicSign() {
		try {
			// 通过审计表查询前一日的撤销记录
			LocalDate yesterday = LocalDate.now().minusDays(1);
			Date yesterdayStart = LocalDateTimeUtils.convertLDToDate(yesterday);
			Date yesterdayEnd = LocalDateTimeUtils.convertLDToDate(yesterday.plusDays(1));
			
			// 查询前一日的撤销审计记录
			List<TEmployeeContractAudit> yesterdayAudits = tEmployeeContractAuditService.list(Wrappers.<TEmployeeContractAudit>query()
					.lambda()
					.eq(TEmployeeContractAudit::getRootName, "撤销签署")
					.eq(TEmployeeContractAudit::getCreateName, "系统自动撤销")
					.eq(TEmployeeContractAudit::getLinkType, CommonConstants.ONE_INT)
					.ge(TEmployeeContractAudit::getCreateTime, yesterdayStart)
					.lt(TEmployeeContractAudit::getCreateTime, yesterdayEnd)
			);
			
			if (Common.isEmpty(yesterdayAudits)) {
				return R.ok("前一日未发现撤销的电子签署任务");
			}
			
			// 根据审计记录获取对应的合同ID列表
			List<String> contractIds = yesterdayAudits.stream()
					.map(TEmployeeContractAudit::getLinkId)
					.filter(Objects::nonNull)
					.collect(Collectors.toList());
			
			if (Common.isEmpty(contractIds)) {
				return R.ok("前一日撤销记录中未找到有效的合同ID");
			}
			
			// 根据合同ID查询对应的合同预签订记录
			List<TEmployeeContractPre> revokedContracts = baseMapper.selectList(Wrappers.<TEmployeeContractPre>query()
					.lambda()
					.in(TEmployeeContractPre::getContractId, contractIds)
					.eq(TEmployeeContractPre::getProcessStatus, CommonConstants.ELEVEN_STRING) // 撤销签署-系统自动撤销
					.eq(TEmployeeContractPre::getSignType, CommonConstants.ONE_STRING) // 线下签
					.eq(TEmployeeContractPre::getChangeTypeReason, "超时未签署自行变更为线下签")
			);
			
			if (Common.isEmpty(revokedContracts)) {
				return R.ok("前一日未发现撤销的电子签署任务");
			}
			
			// 按前端客服分组统计
			Map<String, CustomerRevokeStatistics> customerStatsMap = new HashMap<>();

			Map<String, String> loginNameMap = new HashMap<>();
			for (TEmployeeContractPre contract : revokedContracts) {
				String customerLoginName = contract.getCustomerUserLoginname();
				if (Common.isNotNull(customerLoginName)) {
					if (null == loginNameMap.get(customerLoginName)) {
						UUID uuid = UUID.randomUUID();
						loginNameMap.put(customerLoginName, uuid.toString());
					}
					CustomerRevokeStatistics stats = customerStatsMap.computeIfAbsent(customerLoginName, k -> {
						CustomerRevokeStatistics newStats = new CustomerRevokeStatistics();
						newStats.setCustomerUserLoginname(customerLoginName);
						return newStats;
					});
					stats.setRevokedCount(stats.getRevokedCount() + 1);
					//生成快照数据
					TContractAutoLog contractAutoLog = new TContractAutoLog();
					contractAutoLog.setContractId(loginNameMap.get(customerLoginName));
					contractAutoLog.setEmpName(contract.getEmployeeName());
					contractAutoLog.setEmpIdcard(contract.getEmpIdcard());
					contractAutoLog.setPhone(contract.getEmpPhone());
					contractAutoLog.setJoinLeaveDate(contract.getJoinLeaveDate());
					contractAutoLog.setMainId(contract.getId());
					contractAutoLogService.save(contractAutoLog);
				}
			}
			
			// 为每个前端客服发送通知
			for (Map.Entry<String, CustomerRevokeStatistics> entry : customerStatsMap.entrySet()) {
				CustomerRevokeStatistics stats = entry.getValue();
				if (stats.getRevokedCount() > 0 && Common.isNotNull(stats.getCustomerUserLoginname())) {
					// 生成通知内容
					String notificationContent = String.format("距离入职日期已超过1个月，仍未完成合同签署（%d人），系统已自动撤回签署任务，点击可查看具体撤回清单", 
							stats.getRevokedCount());
					
					// 发送企微通知
					sendRevokeNotificationToWx(stats.getCustomerUserLoginname(), notificationContent, loginNameMap);
				}
			}
			return R.ok();
			
		} catch (Exception e) {
			log.error("执行通知前端客服撤销电子签署情况任务时发生异常", e);
			return R.failed("执行通知前端客服撤销电子签署情况任务时发生异常：" + e.getMessage());
		}
	}
	
	/**
	 * 发送撤销通知到企微
	 * @param loginName 客服登录名
	 * @param content 通知内容
	 */
	private void sendRevokeNotificationToWx(String loginName, String content,Map<String, String> loginNameMap) {
		//获取前端客服
		SysUser user;
		if (Common.isEmpty(loginName)) {
			return;
		}
		R<SysUser> res = upmsDaprUtils.getSimpleUserByLoginName(loginName);
		if (Common.isNotNull(res) && Common.isNotNull(res.getData())) {
			user = res.getData();
		} else {
			return;
		}
		StringBuilder sendUser = null;
		if (Common.isNotKong(user.getWxMessage())) {
			sendUser = new StringBuilder(user.getWxMessage());
		}
		if (sendUser != null) {
			RestTemplate restTemplate = new RestTemplate();
			Map<String, Object> requestMap = new HashMap<>();
			Map<String, Object> textcard = new HashMap<>();
			String authUrl = String.format(SecurityConstants.WX_GET_MESSAGE_AUTH_URL, wxConfig.getCorpid()
					, wxConfig.getDomainName() + "/auth/oauth/wxLogin", "71" + loginNameMap.get(loginName));
			StringBuilder description = new StringBuilder();
			String title = "作业自动化——电子合同签署超期自动撤回提醒";
			description.append(content).append("<br>");
			description.append("请及时进行线下签署，以免产生用工风险！").append("<br>");
			textcard.put("title", title);
			textcard.put("url", authUrl);
			textcard.put("description", description.toString());
			requestMap.put("touser", sendUser);
			requestMap.put("agentid", wxConfig.getAgentid());
			requestMap.put("msgtype", "textcard");
			requestMap.put("textcard", textcard);
			// 必须加上header说明
			if (!wxConfig.sendTextCard(restTemplate, requestMap)) {
				wxConfig.sendTextCard(restTemplate, requestMap);
			}
		}
	}

	@Override
	public R electronicSignExpiringReminder() {
		try {
			LocalDate today = LocalDate.now();
			
			// 查询所有状态为"签署中"(6)且为电子签(signType=0)的合同
			List<TEmployeeContractPre> signingContracts = baseMapper.selectList(Wrappers.<TEmployeeContractPre>query()
					.lambda()
					.eq(TEmployeeContractPre::getProcessStatus, CommonConstants.SIX_STRING) // 签署中
					.eq(TEmployeeContractPre::getSignType, CommonConstants.ZERO_STRING) // 电子签
			);
			
			if (Common.isEmpty(signingContracts)) {
				return R.ok("未找到签署中的电子签合同");
			}
			
			// 按前端客服分组统计需要提醒的合同
			Map<String, CustomerExpiringStatistics> customerStatsMap = new HashMap<>();

			Map<String, String> loginNameMap = new HashMap<>();
			for (TEmployeeContractPre contract : signingContracts) {
				if (contract.getJoinLeaveDate() != null) {
					// 计算入职一个月的最后一天
					LocalDate localDate = contract.getJoinLeaveDate().toInstant()
							.atZone(ZoneId.systemDefault())
							.toLocalDate();
					localDate = localDate.plusMonths(1)
							.minusDays(1);
					
					// 计算往前3个工作日
					List<LocalDate> reminderDates = calculateReminderWorkDays(localDate);
					
					// 判断今天是否是提醒日期之一
					if (reminderDates.contains(today)) {
						String customerLoginName = contract.getCustomerUserLoginname();
						if (Common.isNotNull(customerLoginName)) {
							if (null == loginNameMap.get(customerLoginName)) {
								UUID uuid = UUID.randomUUID();
								loginNameMap.put(customerLoginName, uuid.toString());
							}
							CustomerExpiringStatistics stats = customerStatsMap.computeIfAbsent(customerLoginName, k -> {
								CustomerExpiringStatistics newStats = new CustomerExpiringStatistics();
								newStats.setCustomerUserLoginname(customerLoginName);
								return newStats;
							});
							stats.setExpiringCount(stats.getExpiringCount() + 1);

							//生成快照数据
							TContractAutoLog contractAutoLog = new TContractAutoLog();
							contractAutoLog.setContractId(loginNameMap.get(customerLoginName));
							contractAutoLog.setEmpName(contract.getEmployeeName());
							contractAutoLog.setEmpIdcard(contract.getEmpIdcard());
							contractAutoLog.setPhone(contract.getEmpPhone());
							contractAutoLog.setJoinLeaveDate(contract.getJoinLeaveDate());
							contractAutoLog.setMainId(contract.getId());
							contractAutoLogService.save(contractAutoLog);
						}
						//更新催办和超期标识标识
						contract.setOverFlag(CommonConstants.ZERO_STRING);
					}
				}
			}
			
			// 为每个前端客服发送提醒
			for (Map.Entry<String, CustomerExpiringStatistics> entry : customerStatsMap.entrySet()) {
				CustomerExpiringStatistics stats = entry.getValue();
				if (stats.getExpiringCount() > 0 && Common.isNotNull(stats.getCustomerUserLoginname())) {
					// 生成提醒内容
					String reminderContent = String.format("距离入职1个月还剩3天，仍未签署合同的员工数：%d人",
							stats.getExpiringCount());
					
					// 发送企微提醒
					sendExpiringReminderToWx(stats.getCustomerUserLoginname(), reminderContent,loginNameMap);
				}
			}
			
			return R.ok();
			
		} catch (Exception e) {
			log.error("执行电子签合同即将超期提醒任务时发生异常", e);
			return R.failed("执行电子签合同即将超期提醒任务时发生异常：" + e.getMessage());
		}
	}

	@Override
	public R contractUrg(String id)  {
		// 查询所有待催办的合同
		List<TContractAutoLog> signingContracts = contractAutoLogService.list(Wrappers.<TContractAutoLog>query()
				.lambda()
				.eq(TContractAutoLog::getContractId, id)
		);
		if (Common.isNotNull(signingContracts) && signingContracts.size() > 0) {
			try {
				for (TContractAutoLog log : signingContracts) {
					//查询合同待购买数据
					TEmployeeContractPre pre = baseMapper.selectById(log.getMainId());
					fascService.urgeTask(pre.getId());
					log.setIsUrg(CommonConstants.ZERO_STRING);
					contractAutoLogService.updateById(log);
				}
			} catch (Exception e) {
				log.error("发送法大大催办时发生异常", e);
			}
		}
		return R.ok();
	}

	/**
	 * 计算入职一个月最后一天往前3个工作日的日期列表
	 * @param lastDay 入职一个月的最后一天
	 * @return 3个工作日的日期列表
	 */
	private List<LocalDate> calculateReminderWorkDays(LocalDate lastDay) {
		List<LocalDate> reminderDates = new ArrayList<>();
		LocalDate currentDate = lastDay;
		int workDayCount = 0;
		
		// 往前找3个工作日
		while (workDayCount < 3) {
			// 检查当前日期是否为工作日
			if (isWorkDay(currentDate)) {
				reminderDates.add(currentDate);
				workDayCount++;
			}
			// 往前一天
			currentDate = currentDate.minusDays(1);
		}
		
		// 按日期正序排列（最早的日期在前）
		Collections.reverse(reminderDates);
		return reminderDates;
	}
	
	/**
	 * 判断指定日期是否为工作日
	 * @param date 要检查的日期
	 * @return true-工作日，false-非工作日
	 */
	private boolean isWorkDay(LocalDate date) {
		TEmployeeInsuranceWorkDayVo workDayVo = new TEmployeeInsuranceWorkDayVo();
		workDayVo.setRegistDate(LocalDateTimeUtils.convertLDToDate(date));
		
		// 使用THolidayInfoService的checkIsWorkDay方法判断是否为假期
		// 如果是假期则不是工作日，否则是工作日
		R<Boolean> res = socialDaprUtils.checkIsWorkDay(workDayVo);
		return !res.getData();
	}
	
	/**
	 * 发送即将超期提醒到企微
	 * @param loginName 客服登录名
	 * @param content 提醒内容
	 */
	private void sendExpiringReminderToWx(String loginName, String content,Map<String, String> loginNameMap) {
		//获取前端客服
		SysUser user;
		if (Common.isEmpty(loginName)) {
			return;
		}
		R<SysUser> res = upmsDaprUtils.getSimpleUserByLoginName(loginName);
		if (Common.isNotNull(res) && Common.isNotNull(res.getData())) {
			user = res.getData();
		} else {
			return;
		}
		StringBuilder sendUser = null;
		if (Common.isNotKong(user.getWxMessage())) {
			sendUser = new StringBuilder(user.getWxMessage());
		}
		if (sendUser != null) {
			RestTemplate restTemplate = new RestTemplate();
			Map<String, Object> requestMap = new HashMap<>();
			Map<String, Object> textcard = new HashMap<>();
			String authUrl = String.format(SecurityConstants.WX_GET_MESSAGE_AUTH_URL, wxConfig.getCorpid()
					, wxConfig.getDomainName() + "/auth/oauth/wxLogin", "70" + loginNameMap.get(loginName));
			StringBuilder description = new StringBuilder();
			String title = "作业自动化——合同签署超期提醒";
			description.append(content).append("<br>");
			description.append("请及时提醒员工，尽快完成法大大签署任务！").append("<br>");
			textcard.put("title", title);
			textcard.put("url", authUrl);
			textcard.put("description", description.toString());
			requestMap.put("touser", sendUser);
			requestMap.put("agentid", wxConfig.getAgentid());
			requestMap.put("msgtype", "textcard");
			requestMap.put("textcard", textcard);
			// 必须加上header说明
			if (!wxConfig.sendTextCard(restTemplate, requestMap)) {
				wxConfig.sendTextCard(restTemplate, requestMap);
			}
		}
	}
	@Override
	public R<TEmployeeContractPre> getInfoByRegistId(String registId) {
		if (Common.isEmpty(registId)) {
			return R.failed(CommonConstants.PARAM_INFO_ERROR);
		}
		return R.ok(baseMapper.selectOne(Wrappers.<TEmployeeContractPre>query().lambda()
				.notIn(TEmployeeContractPre::getProcessStatus, Arrays.asList("0","1","3","5","7","10","11"))
				.eq(TEmployeeContractPre::getRegisterId, registId)
				.last(CommonConstants.LAST_ONE_SQL)));
	}

	// 获取处理中的自动化合同（2线下签待审核、6签署中
	@Override
	public boolean judgeHaveProcessingContracnt(BaseSearchVO paramVo) {
		if (Common.isNotNull(paramVo.getEmpIdCard()) && Common.isNotNull(paramVo.getDeptNo())) {
			TEmployeeContractPre pre = baseMapper.selectOne(Wrappers.<TEmployeeContractPre>query().lambda()
					.eq(TEmployeeContractPre::getIsRefuse, CommonConstants.ONE_STRING)
					.eq(TEmployeeContractPre::getIsLeave, CommonConstants.ONE_STRING)
					.in(TEmployeeContractPre::getProcessStatus, Arrays.asList("2","6"))
					.eq(TEmployeeContractPre::getEmpIdcard, paramVo.getEmpIdCard())
					.eq(TEmployeeContractPre::getDeptNo, paramVo.getDeptNo())
					.last(CommonConstants.LAST_ONE_SQL));
			// 找到了才阻断，不允许离职确认
			return pre != null;
		} else {
			return false;
		}
	}
}
