/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the yifu4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
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.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.yifu.cloud.plus.v1.yifu.archives.entity.TEmployeeContractInfo;
import com.yifu.cloud.plus.v1.yifu.archives.entity.TGzEmpInfo;
import com.yifu.cloud.plus.v1.yifu.archives.entity.TGzOfferInfo;
import com.yifu.cloud.plus.v1.yifu.archives.entity.TRegisteWarningEmployee;
import com.yifu.cloud.plus.v1.yifu.archives.mapper.EmployeeRegistrationPreMapper;
import com.yifu.cloud.plus.v1.yifu.archives.mapper.TEmployeeContractInfoMapper;
import com.yifu.cloud.plus.v1.yifu.archives.mapper.TGzOfferInfoMapper;
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.CacheConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.*;
import com.yifu.cloud.plus.v1.yifu.common.core.util.alisms.AliSmsResult;
import com.yifu.cloud.plus.v1.yifu.common.core.util.alisms.RegistParamVo;
import com.yifu.cloud.plus.v1.yifu.common.core.util.alisms.YiFuSmsUtil;
import com.yifu.cloud.plus.v1.yifu.common.core.vo.YifuUser;
import com.yifu.cloud.plus.v1.yifu.common.dapr.util.UpmsDaprUtils;
import com.yifu.cloud.plus.v1.yifu.common.security.util.SecurityUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
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;

/**
 * 瓜子offer信息接收表
 *
 * @author chenyx
 * @date 2025-06-11 15:58:37
 */
@Log4j2
@Service
@RequiredArgsConstructor
public class TGzOfferInfoServiceImpl extends ServiceImpl<TGzOfferInfoMapper, TGzOfferInfo> implements TGzOfferInfoService {

	private final TRegisteWarningEmployeeService employeeService;

	private final EmployeeRegistrationPreMapper registrationPreMapper;

	private final LGuaziOfferRecordService lGuaziOfferRecordService;

	private final TEmployeeContractInfoMapper employeeContractInfoMapper;
	// 瓜子合同信息提取方法————因为循环调用了
	private final TGzContractService tGzContractService;

	@Autowired
	private UpmsDaprUtils upmsDaprUtils;

	// 禁止手动变更的状态:3：待发送Offer,9：候选人填写信息,12：候选人信息审核，13：待签署，8：合同审核通过，99：已归档，97：候选人审核通过
	private final String[] forbidStatusArr = {"3", "9", "12", "13", "8","99","97"};

	// 当前Offer更新状态,无法再发起更新：5：拒绝Offer、10：取消offer、8：合同审核通过、99：已归档
	private final String[] failStatusArr = {"5", "10", "8", "99"};

	private final TGzEmpInfoService tGzEmpInfoService;

    /**
     * 瓜子offer信息接收表简单分页查询
     * @param tGzOfferInfo 瓜子offer信息接收表
     * @return IPage<TGzOfferInfoVo>
     */
    @Override
    public IPage<TGzOfferInfoVo> getTGzOfferInfoPage(Page<TGzOfferInfoVo> page, TGzOfferInfoVo tGzOfferInfo){
		return baseMapper.getTGzOfferInfoPage(page,tGzOfferInfo);
    }

	/**
	 * 仅返回指定条数的列表数据
	 *
	 * @param tGzOfferInfo 瓜子offer信息接收表
	 * @return R<List < TGzOfferInfoVo>>
	 */
	@Override
	public List<TGzOfferInfoVo> getTGzOfferInfoList(TGzOfferInfoVo tGzOfferInfo) {
		return baseMapper.getTGzOfferInfoListHaveLimit(tGzOfferInfo,2000);
	}

	/**
	 * 符合查询条件的数量
	 *
	 * @param tGzOfferInfo 瓜子offer信息接收表
	 * @return R<Integer>
	 */
	@Override
	public Integer getTGzOfferInfoCount(TGzOfferInfoVo tGzOfferInfo) {
		return baseMapper.getTGzOfferInfoCount(tGzOfferInfo);
	}

	@Override
	public TGzOfferInfo getDataById(Integer id) {
		return this.getInfoCommon(id);
	}

	/**
	 * 修改瓜子offer信息
	 *
	 * @param tGzOfferInfo 字典
	 * @return R<String>
	 */
	@Override
	public R<String> updateDataById(TGzOfferInfo tGzOfferInfo) {
		YifuUser user = SecurityUtils.getUser();
		if (user == null || Common.isEmpty(user.getId())) {
			return R.failed(CommonConstants.PLEASE_LOG_IN);
		}
		TGzOfferInfo findInfo = this.getInfoCommon(tGzOfferInfo.getId());
		if (Common.isEmpty(findInfo)) {
			return R.failed(CommonConstants.ERROR_NO_DOMAIN);
		}

		tGzOfferInfo.setUpdateBy(user.getId());
		tGzOfferInfo.setUpdateTime(LocalDateTime.now());
		this.updateById(tGzOfferInfo);

		// 记录offer操作日志
		LGuaziOfferRecordVo lGuaziOfferRecordVo = new LGuaziOfferRecordVo();
		Map<String,List<String>> changeInfoMap = new HashMap<>();
		if(!tGzOfferInfo.getPhone().equals(findInfo.getPhone())){
			List<String> valueList = new ArrayList<>();
			valueList.add(findInfo.getPhone());
			valueList.add(tGzOfferInfo.getPhone());
			changeInfoMap.put("个人手机号",valueList);
		}
		if(!tGzOfferInfo.getEmail().equals(findInfo.getEmail())){
			List<String> valueList = new ArrayList<>();
			valueList.add(findInfo.getEmail());
			valueList.add(tGzOfferInfo.getEmail());
			changeInfoMap.put("个人邮箱",valueList);
		}
		if(changeInfoMap.size() > 0){
			lGuaziOfferRecordVo.setOfferId(tGzOfferInfo.getId());
			lGuaziOfferRecordVo.setRecordFrom(CommonConstants.TWO_STRING);
			lGuaziOfferRecordVo.setChangeInfoMap(changeInfoMap);
			lGuaziOfferRecordVo.setCreateBy(user.getId());
			lGuaziOfferRecordVo.setCreateName(user.getNickname());
			lGuaziOfferRecordService.saveRecordOne(lGuaziOfferRecordVo);
		}

		return R.ok(CommonConstants.RESULT_DATA_SUCESS);
	}

	/**
	 * 瓜子offer手动状态更新
	 *
	 * @param tGzOfferInfo 字典
	 * @return R<String>
	 */
	@Override
	public R<String> updateStatus(TGzOfferInfo tGzOfferInfo) {
		YifuUser user = SecurityUtils.getUser();
		if (user == null || Common.isEmpty(user.getId())) {
			return R.failed(CommonConstants.PLEASE_LOG_IN);
		}
		if (Common.isEmpty(tGzOfferInfo.getId())) {
			return R.failed(CommonConstants.PARAM_IS_NOT_EMPTY);
		}
		if (Common.isEmpty(tGzOfferInfo.getOfferStatus())) {
			return R.failed("更新状态不能为空");
		}
		// 禁止手动变更的状态
		if (ArrayUtils.contains(forbidStatusArr, tGzOfferInfo.getOfferStatus())) {
			return R.failed("参数错误，禁止手动变更为该状态");
		}

		TGzOfferInfo findInfo = this.getInfoCommon(tGzOfferInfo.getId());
		if (Common.isEmpty(findInfo)) {
			return R.failed(CommonConstants.ERROR_NO_DOMAIN);
		}
		// 更新为同一状态的提示操作失败
		if (findInfo.getOfferStatus().equals(tGzOfferInfo.getOfferStatus())) {
			return R.failed("当前Offer更新状态失败，请刷新页面后重试");
		}
		// 当前Offer更新状态,无法再发起更新
		if (ArrayUtils.contains(failStatusArr, findInfo.getOfferStatus())) {
			return R.failed("当前Offer状态,无法再发起手动更新");
		}
		// 获取当前状态下，允许更新的状态列表
		List<String> allowUpdateStatusList = this.allowUpdateStatus(findInfo.getOfferStatus());
		if (!allowUpdateStatusList.contains(tGzOfferInfo.getOfferStatus())) {
			return R.failed("当前Offer更新状态失败，禁止更新为所选状态，请刷新页面后重试");
		}
		// 更新状态
		LambdaUpdateWrapper<TGzOfferInfo> updateOfferWrapper = new LambdaUpdateWrapper<>();
		updateOfferWrapper.eq(TGzOfferInfo::getId, tGzOfferInfo.getId())
				.set(TGzOfferInfo::getOfferStatus, tGzOfferInfo.getOfferStatus())
				.set(TGzOfferInfo::getUpdateTime, LocalDateTime.now())
				.set(TGzOfferInfo::getUpdateBy, user.getId());
		this.update(null, updateOfferWrapper);

		// 记录状态变更的offer操作日志 记录来源: 手动更新状态
		this.saveOfferStatusRecord(tGzOfferInfo.getId(),CommonConstants.ONE_STRING,
				findInfo.getOfferStatus(),tGzOfferInfo.getOfferStatus(),user.getId(),user.getNickname());

		return R.ok(CommonConstants.RESULT_DATA_SUCESS);
	}

	/**
	 * 瓜子候选人信息审核
	 * @param tGzOfferInfo 字典
	 * @return R<String>
	 */
	@Override
	public R<String> offerAudit(TGzOfferInfo tGzOfferInfo) {
		YifuUser user = SecurityUtils.getUser();
		if (user == null || Common.isEmpty(user.getId())) {
			return R.failed(CommonConstants.PLEASE_LOG_IN);
		}
		if(Common.isEmpty(tGzOfferInfo.getId())){
			return R.failed(CommonConstants.PARAM_IS_NOT_EMPTY);
		}
		if(Common.isEmpty(tGzOfferInfo.getOfferStatus())){
			return R.failed("审核结果不能为空");
		}
		TGzOfferInfo findInfo = this.getInfoCommon(tGzOfferInfo.getId());
		if (Common.isEmpty(findInfo)){
			return R.failed(CommonConstants.ERROR_NO_DOMAIN);
		}
		if (!CommonConstants.TWELVE_STRING.equals(findInfo.getOfferStatus())){
			return R.failed("当前Offer不符合档案审核状态，禁止操作");
		}

		// 允许更新的Offer状态：97：候选人审核通过、9：候选人填写信息
		String[] allowStatusArr = {"97", "9"};
		if (!ArrayUtils.contains(allowStatusArr, tGzOfferInfo.getOfferStatus())) {
			return R.failed("审核结果无效");
		}

		// 审核通过, 执行一下2个事件：
		if("97".equals(tGzOfferInfo.getOfferStatus())){
			// 1、生成人员档案信息、项目档案信息
			// hgw 2025-6-20 14:55:12
			R<String> saveEmpInfoR = tGzEmpInfoService.saveEmpInfoByGz(findInfo);
			if (saveEmpInfoR != null && Common.isNotNull(saveEmpInfoR.getCode()) && saveEmpInfoR.getCode() != CommonConstants.SUCCESS) {
				return saveEmpInfoR;
			}

			// 2、检查 该项目该人员是否有在途或审核通过或已归档的状态为“可用”的合同，
			//        若有则根据当前状态更新Offer状态，合同未审核通过：存【13：待签署】；合同审核通过：存【8：合同审核通过】；合同已归档：存【99：已归档】，
			//        存合同信息；
			String changeStatus = this.checkSaveContract(findInfo.getNationalId(),findInfo.getId(), findInfo.getWorkLocation());
			tGzOfferInfo.setOfferStatus(changeStatus);
		}

		// 更新状态
		LambdaUpdateWrapper<TGzOfferInfo> updateOfferWrapper = new LambdaUpdateWrapper<>();
		updateOfferWrapper.eq(TGzOfferInfo::getId, tGzOfferInfo.getId())
				.set(TGzOfferInfo::getOfferStatus, tGzOfferInfo.getOfferStatus())
				.set(TGzOfferInfo::getUpdateTime, LocalDateTime.now())
				.set(TGzOfferInfo::getUpdateBy, user.getId());
		this.update(null, updateOfferWrapper);

		// 记录状态变更的offer操作日志 记录来源: 档案审核
		this.saveOfferStatusRecord(findInfo.getId(),CommonConstants.SEVEN_STRING,
				findInfo.getOfferStatus(),tGzOfferInfo.getOfferStatus(),user.getId(),user.getNickname());

		return R.ok(CommonConstants.RESULT_DATA_SUCESS);
	}

	/**
	 * 检查 瓜子档案审核通过后，是否需要再生成合同信息
	 * 该项目该人员是否有在途或审核通过或已归档的状态为“可用”的合同，
	 * 若有则根据当前状态更新Offer状态，合同未审核通过：存【13：待签署】；合同审核通过：存【8：合同审核通过】；合同已归档：存【99：已归档】
	 * @param nationalId 人员身份证号
	 * @param offerId offerId
	 * @param workLocation 工作地点
	 * @return String 后续offer要更新的状态
	 */
	private String checkSaveContract(String nationalId,Integer offerId, String workLocation){
		// 默认是档案审核通过
		String changeStatus = "97";
		TEmployeeContractInfo contractInfo = employeeContractInfoMapper.selectOne(Wrappers.<TEmployeeContractInfo>query().lambda()
				.eq(TEmployeeContractInfo::getDeptNo, CommonConstants.GZ_DEPT_NO)
				.eq(TEmployeeContractInfo::getEmpIdcard, nationalId)
				.last(CommonConstants.LAST_ONE_SQL));
		if(Common.isNotNull(contractInfo)){
			// 合同已归档
			if(CommonConstants.ZERO_STRING.equals(contractInfo.getIsFile())
					&& CommonConstants.ZERO_STRING.equals(contractInfo.getInUse())){
				// 生成瓜子档案里的合同信息
				tGzContractService.saveContractInfoToGzEmpInfo(contractInfo, offerId, workLocation);
				return "99";
			}
			// 合同审核通过
			if(CommonConstants.TWO_INTEGER.equals(contractInfo.getAuditStatus())
					&& CommonConstants.ZERO_STRING.equals(contractInfo.getInUse())){
				// 生成瓜子档案里的合同信息
				tGzContractService.saveContractInfoToGzEmpInfo(contractInfo, offerId, workLocation);
				return CommonConstants.EIGHT_STRING;
			}
			// 合同已提交待审核
			if(CommonConstants.ONE_INTEGER.equals(contractInfo.getAuditStatus())){
				return CommonConstants.THIRTEEN_STRING;
			}
		}

		return changeStatus;
	}

	/**
	 * 获取当前状态下，允许更新的状态列表
	 *
	 * @param orgStatus 当前状态
	 * @return List<String> 允许更新的状态列表
	 */
	private List<String> allowUpdateStatus(String orgStatus) {
		List<String> allowUpdateStatusList = new ArrayList<>();
		// 3：待发送Offer
		if (CommonConstants.THREE_STRING.equals(orgStatus)) {
			// 可更新为：4：待接受Offer、10：取消offer
			allowUpdateStatusList.add(CommonConstants.FOUR_STRING);
			allowUpdateStatusList.add(CommonConstants.TEN_STRING);
		}
		// 4：待接受Offer
		if (CommonConstants.FOUR_STRING.equals(orgStatus)) {
			// 可更新为：5：拒绝Offer、7：接受offer、10：取消offer
			allowUpdateStatusList.add(CommonConstants.FIVE_STRING);
			allowUpdateStatusList.add(CommonConstants.SEVEN_STRING);
			allowUpdateStatusList.add(CommonConstants.TEN_STRING);
		}
		// 7：接受Offer
		if (CommonConstants.SEVEN_STRING.equals(orgStatus)) {
			// 可更新为：98：信息待收集、10：取消offer
			allowUpdateStatusList.add("98");
			allowUpdateStatusList.add(CommonConstants.TEN_STRING);
		}
		// 98：信息待收集、9：候选人填写信息、12：候选人信息审核、97：候选人审核通过、13：待签署
		if ("98".equals(orgStatus) || CommonConstants.NINE_STRING.equals(orgStatus)
				|| CommonConstants.TWELVE_STRING.equals(orgStatus) || "97".equals(orgStatus)
				|| CommonConstants.THIRTEEN_STRING.equals(orgStatus)) {
			// 可更新为：10：取消offer
			allowUpdateStatusList.add(CommonConstants.TEN_STRING);
		}

		return allowUpdateStatusList;
	}

	private TGzOfferInfo getInfoCommon(Integer id) {
		return this.getOne(Wrappers.<TGzOfferInfo>query().lambda()
				.eq(TGzOfferInfo::getId, id)
				.eq(TGzOfferInfo::getDelFlag, CommonConstants.ZERO_STRING)
				.last(CommonConstants.LAST_ONE_SQL));
	}


	@Override
	public R<List<ErrorMessage>> importDiy(InputStream inputStream) {
		List<ErrorMessage> errorMessageList = new ArrayList<>();
		ExcelUtil<TGzOfferInfoImportVo> util1 = new ExcelUtil<>(TGzOfferInfoImportVo.class);
		// 写法2：
		// 匿名内部类 不用额外写一个DemoDataListener
		// 这里 需要指定读用哪个class去读，然后读取第一个sheet 文件流会自动关闭
		try {
			EasyExcel.read(inputStream, TGzOfferInfoImportVo.class, new ReadListener<TGzOfferInfoImportVo>() {
				/**
				 * 单次缓存的数据量
				 */
				public static final int BATCH_COUNT = CommonConstants.BATCH_COUNT;
				/**
				 *临时存储
				 */
				private List<TGzOfferInfoImportVo> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

				@Override
				public void invoke(TGzOfferInfoImportVo data, AnalysisContext context) {
					ReadRowHolder readRowHolder = context.readRowHolder();
					Integer rowIndex = readRowHolder.getRowIndex();
					data.setRowIndex(rowIndex + 1);
					ErrorMessage errorMessage = util1.checkEntity(data, data.getRowIndex());
					if (Common.isNotNull(errorMessage)) {
						errorMessageList.add(errorMessage);
					} else {
						cachedDataList.add(data);
					}
					if (cachedDataList.size() >= BATCH_COUNT) {
						saveData();
						// 存储完成清理 list
						cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
					}
				}

				@Override
				public void doAfterAllAnalysed(AnalysisContext context) {
					saveData();
				}

				/**
				 * 加上存储数据库
				 */
				private void saveData() {
					log.info("{}条数据，开始存储数据库！", cachedDataList.size());
					importTDispatchExportLog(cachedDataList);
					log.info("存储数据库成功！");
				}
			}).sheet().doRead();
		} catch (Exception e) {
			log.error(CommonConstants.IMPORT_DATA_ANALYSIS_ERROR, e);
			return R.failed(CommonConstants.IMPORT_DATA_ANALYSIS_ERROR);
		}
		if (errorMessageList.isEmpty()) {
			return R.ok();
		} else {
			return R.ok(errorMessageList);
		}
	}

	@Override
	public R<String> sendOfferAlert(TGzOfferInfoVo tGzOfferInfo) {
		YifuUser user = SecurityUtils.getUser();
		if (user == null || Common.isEmpty(user.getId())) {
			return R.failed(CommonConstants.PLEASE_LOG_IN);
		}
		//获取所有满足条件的未发送offer提醒的数据
		if (Common.isNotNull(tGzOfferInfo)) {
			tGzOfferInfo.setOfferStatus(CommonConstants.FOUR_STRING);
			List<TGzOfferInfoVo> offerList = baseMapper.getTGzOfferInfoSendAlertList(tGzOfferInfo);
			if (Common.isNotNull(offerList) && !offerList.isEmpty()) {
				if (Common.isNotNull(offerList) && offerList.size() >200) {
					return R.failed("短信批量发送单次最多两百条");
				}
				//获取短信待发放和信息待填写的数据
				List<String> errorList = new ArrayList<>();

				// 发送短信成功的offer集合
				List<Integer> successOfferIds = new ArrayList<>();
				// 发送短信失败的offer集合
				List<Integer> errorOfferIds = new ArrayList<>();

				for (TGzOfferInfoVo sendVo : offerList) {
					List<RegistParamVo> params = new ArrayList<>();
					List<String> phones = new ArrayList<>();
					RegistParamVo paramVo = new RegistParamVo();
					AliSmsResult res;
					paramVo.setName(sendVo.getName());
					phones.add(sendVo.getPhone());
					//生成短信发送的记录
					TRegisteWarningEmployee smsEmployee = new TRegisteWarningEmployee();
					smsEmployee.setEmpName(sendVo.getName());
					smsEmployee.setEmpPhone(sendVo.getPhone());
					smsEmployee.setEmpIdcard(sendVo.getNationalId());
					smsEmployee.setSendDate(DateUtil.getCurrentDateTime());
					smsEmployee.setSendMethod(CommonConstants.ONE_INT);
					smsEmployee.setWarningId(sendVo.getId().toString());
					smsEmployee.setType(CommonConstants.THREE_STRING);
					employeeService.save(smsEmployee);
					params.add(paramVo);
					res = sendMessage(phones, params,CommonConstants.TWO_STRING);
					//更新Offer信息接收表发送状态为已发送
					LambdaUpdateWrapper<TGzOfferInfo> updateWrapper = new LambdaUpdateWrapper<>();
					updateWrapper.eq(TGzOfferInfo::getId, sendVo.getId())
							.eq(TGzOfferInfo::getOfferSendStatus, CommonConstants.ONE_STRING)
							.set(TGzOfferInfo::getOfferSendStatus, CommonConstants.ZERO_STRING)
							.set(TGzOfferInfo::getUpdateTime, LocalDateTime.now())
							.set(TGzOfferInfo::getUpdateBy, user.getId());
					// 执行更新操作
					this.update(updateWrapper);
					if (null != res && null != res.getBizId()) {
						//发送成功
						smsEmployee.setBizId(res.getBizId());
						smsEmployee.setMessage(res.getMessage());
						employeeService.updateById(smsEmployee);

						// 记录发送短信成功的offerId 到集合
						successOfferIds.add(sendVo.getId());
					} else {
						smsEmployee.setMessage("瓜子发送提醒短信失败");
						employeeService.updateById(smsEmployee);
						errorList.add("瓜子发送提醒短信失败");

						// 记录发送短信失败的offerId 到集合
						errorOfferIds.add(sendVo.getId());
					}
				}

				// 记录批量发送短信的offer操作日志。结果：0成功，1失败
				if(Common.isNotNull(successOfferIds)){
					this.saveSendSmsRecord(successOfferIds,CommonConstants.THREE_STRING,CommonConstants.ZERO_STRING, user.getId(),user.getNickname());
				}
				if(Common.isNotNull(errorOfferIds)){
					this.saveSendSmsRecord(successOfferIds,CommonConstants.THREE_STRING,CommonConstants.ONE_STRING, user.getId(),user.getNickname());
				}

				if (!errorList.isEmpty() && errorList.stream().allMatch(e->e.equals("瓜子发送提醒短信失败"))) {
					return R.ok("瓜子发送提醒短信失败");
				}
				return R.ok();
			} else {
				return R.failed(CommonConstants.NO_DATA_TO_HANDLE);
			}
		}
		return R.failed(CommonConstants.PARAM_IS_NOT_ERROR);
	}

	@Override
	public R<String> sendCollectOfferMsg(TGzOfferInfoVo tGzOfferInfo) {
		YifuUser user = SecurityUtils.getUser();
		if (user == null || Common.isEmpty(user.getId())) {
			return R.failed(CommonConstants.PLEASE_LOG_IN);
		}

		//获取所有满足条件的信息待收集、候选人填写信息的offer提醒的数据
		if (Common.isNotNull(tGzOfferInfo)) {
			tGzOfferInfo.setStatusList(Stream.of("9","98").collect(Collectors.toList()));
			List<TGzOfferInfoVo> offerList = baseMapper.getTGzOfferInfoSendAlertList(tGzOfferInfo);
			if (Common.isNotNull(offerList) && !offerList.isEmpty()) {
				if (Common.isNotNull(offerList) && offerList.size() >200) {
					return R.failed("短信批量发送单次最多两百条");
				}
				//获取短信信息待收集、候选人填写信息的数据
				List<String> errorList = new ArrayList<>();

				// 发送短信成功的offer集合
				List<Integer> successOfferIds = new ArrayList<>();
				// 发送短信失败的offer集合
				List<Integer> errorOfferIds = new ArrayList<>();

				// 记录从【信息待收集】状态触发短信的offer集合
				List<Integer> changeOfferIds = new ArrayList<>();

				for (TGzOfferInfoVo sendVo : offerList) {
					List<RegistParamVo> params = new ArrayList<>();
					List<String> phones = new ArrayList<>();
					RegistParamVo paramVo = new RegistParamVo();
					AliSmsResult res;
					paramVo.setName(sendVo.getName());
					phones.add(sendVo.getPhone());
					//生成短信发送的记录
					TRegisteWarningEmployee smsEmployee = new TRegisteWarningEmployee();
					smsEmployee.setEmpName(sendVo.getName());
					smsEmployee.setEmpPhone(sendVo.getPhone());
					smsEmployee.setEmpIdcard(sendVo.getNationalId());
					smsEmployee.setSendDate(DateUtil.getCurrentDateTime());
					smsEmployee.setSendMethod(CommonConstants.ONE_INT);
					smsEmployee.setWarningId(sendVo.getId().toString());
					smsEmployee.setType(CommonConstants.FOUR_STRING);
					employeeService.save(smsEmployee);
					paramVo.setLink(smsEmployee.getId().toString());
					params.add(paramVo);
					res = sendMessage(phones, params,CommonConstants.THREE_STRING);
					if (null != res && null != res.getBizId()) {
						//发送成功
						smsEmployee.setBizId(res.getBizId());
						smsEmployee.setMessage(res.getMessage());
						employeeService.updateById(smsEmployee);
						//如果状态是信息待收集更新Offer状态为候选人填写信息
						LambdaUpdateWrapper<TGzOfferInfo> updateWrapper = new LambdaUpdateWrapper<>();
						updateWrapper.eq(TGzOfferInfo::getId, sendVo.getId())
								.eq(TGzOfferInfo::getOfferStatus, "98")
								.set(TGzOfferInfo::getOfferStatus, "9")
								.set(TGzOfferInfo::getUpdateTime, LocalDateTime.now())
								.set(TGzOfferInfo::getUpdateBy, user.getId());
						// 执行更新操作
						this.update(updateWrapper);

						// 更新前状态是 98：信息待收集，短信发送成功后，记录状态变更
						if("98".equals(sendVo.getOfferStatus())){
							changeOfferIds.add(sendVo.getId());
						}
						// 记录发送短信成功的offerId 到集合
						successOfferIds.add(sendVo.getId());

					} else {
						smsEmployee.setMessage("瓜子发送收集短信失败");
						employeeService.updateById(smsEmployee);
						errorList.add("瓜子发送收集短信失败");

						// 记录发送短信失败的offerId 到集合
						errorOfferIds.add(sendVo.getId());
					}
				}

				// 记录状态变更的offer操作日志 记录来源: 5：收集短信发送成功
				if(Common.isNotNull(changeOfferIds)){
					this.saveBatchOfferStatusRecord(changeOfferIds,CommonConstants.FIVE_STRING,
							"98","9",user.getId(),user.getNickname());
				}
				// 记录批量发送短信的offer操作日志。结果：0成功，1失败
				if(Common.isNotNull(successOfferIds)){
					this.saveSendSmsRecord(successOfferIds,CommonConstants.FOUR_STRING,CommonConstants.ZERO_STRING, user.getId(),user.getNickname());
				}
				if(Common.isNotNull(errorOfferIds)){
					this.saveSendSmsRecord(successOfferIds,CommonConstants.FOUR_STRING,CommonConstants.ONE_STRING, user.getId(),user.getNickname());
				}

				if (!errorList.isEmpty() && errorList.stream().allMatch(e->e.equals("瓜子发送收集短信失败"))) {
					return R.ok("瓜子发送收集短信失败");
				}
				return R.ok();
			} else {
				return R.failed(CommonConstants.NO_DATA_TO_HANDLE);
			}
		}
		return R.failed(CommonConstants.PARAM_IS_NOT_ERROR);
	}

	@Override
	public R<String> sendContractDownloadOfferMsg(TGzOfferInfoVo tGzOfferInfo) {
		YifuUser user = SecurityUtils.getUser();
		if (user == null || Common.isEmpty(user.getId())) {
			return R.failed(CommonConstants.PLEASE_LOG_IN);
		}
		//获取所有满足条件的已归档的offer提醒的数据
		if (Common.isNotNull(tGzOfferInfo)) {
			tGzOfferInfo.setOfferStatus(CommonConstants.NINETY_NINE);
			List<TGzOfferInfoVo> offerList = baseMapper.getTGzOfferInfoSendAlertList(tGzOfferInfo);
			if (Common.isNotNull(offerList) && !offerList.isEmpty()) {
				if (Common.isNotNull(offerList) && offerList.size() >200) {
					return R.failed("短信批量发送单次最多两百条");
				}
				//获取已归档的数据
				List<String> errorList = new ArrayList<>();
				// 发送短信成功的offer集合
				List<Integer> successOfferIds = new ArrayList<>();
				// 发送短信失败的offer集合
				List<Integer> errorOfferIds = new ArrayList<>();

				for (TGzOfferInfoVo sendVo : offerList) {
					List<RegistParamVo> params = new ArrayList<>();
					List<String> phones = new ArrayList<>();
					RegistParamVo paramVo = new RegistParamVo();
					AliSmsResult res;
					paramVo.setName(sendVo.getName());
					phones.add(sendVo.getPhone());
					//生成短信发送的记录
					TRegisteWarningEmployee smsEmployee = new TRegisteWarningEmployee();
					smsEmployee.setEmpName(sendVo.getName());
					smsEmployee.setEmpPhone(sendVo.getPhone());
					smsEmployee.setEmpIdcard(sendVo.getNationalId());
					smsEmployee.setSendDate(DateUtil.getCurrentDateTime());
					smsEmployee.setSendMethod(CommonConstants.ONE_INT);
					smsEmployee.setWarningId(sendVo.getId().toString());
					smsEmployee.setType(CommonConstants.FIVE_STRING);
					employeeService.save(smsEmployee);
					params.add(paramVo);
					res = sendMessage(phones, params,CommonConstants.FOUR_STRING);
					if (null != res && null != res.getBizId()) {
						//发送成功
						smsEmployee.setBizId(res.getBizId());
						smsEmployee.setMessage(res.getMessage());
						employeeService.updateById(smsEmployee);

						// 记录发送短信成功的offerId 到集合
						successOfferIds.add(sendVo.getId());
					} else {
						smsEmployee.setMessage("瓜子发送合同下载短信失败");
						employeeService.updateById(smsEmployee);
						errorList.add("瓜子发送合同下载短信失败");

						// 记录发送短信失败的offerId 到集合
						errorOfferIds.add(sendVo.getId());
					}
				}

				// 记录批量发送短信的offer操作日志。结果：0成功，1失败
				if(Common.isNotNull(successOfferIds)){
					this.saveSendSmsRecord(successOfferIds,"12",CommonConstants.ZERO_STRING, user.getId(),user.getNickname());
				}
				if(Common.isNotNull(errorOfferIds)){
					this.saveSendSmsRecord(successOfferIds,"12",CommonConstants.ONE_STRING, user.getId(),user.getNickname());
				}

				if (!errorList.isEmpty() && errorList.stream().allMatch(e->e.equals("瓜子发送合同下载短信失败"))) {
					return R.ok("瓜子发送合同下载短信失败");
				}
				return R.ok();
			} else {
				return R.failed(CommonConstants.NO_DATA_TO_HANDLE);
			}
		}
		return R.failed(CommonConstants.PARAM_IS_NOT_ERROR);
	}

	/**
	 * @Description: 批量发送短信
	 * @Author: huych
	 * @Date: 2025/3/18 17:02
	 * @return:
	 **/
	public AliSmsResult sendMessage (List<String> phones,List<RegistParamVo> params,String type ) {
		List<String> signNames = new ArrayList<>();
		MessageTempleteVo templeteVo = registrationPreMapper.selectTempleteVo(type);
		for (int i=0;i<phones.size();i++){
			signNames.add(templeteVo.getSignName());
		}
		return YiFuSmsUtil.sendRegistBatchSms(phones, params, signNames, templeteVo.getTempleteCode());
	}

	private void importTDispatchExportLog(List<TGzOfferInfoImportVo> excelVOList) {
		// 个性化校验逻辑
		// 执行数据插入操作 组装
		TGzOfferInfoImportVo excel;
		for (int i = 0; i < excelVOList.size(); i++) {
			excel = excelVOList.get(i);
			// 插入
			insertExcel(excel);
		}
	}

	/**
	 * 插入excel bad record
	 */
	private void insertExcel(TGzOfferInfoImportVo excel) {
		TGzOfferInfo insert = new TGzOfferInfo();
		BeanUtil.copyProperties(excel, insert);
		insert.setBizId("0");
		this.save(insert);
	}

	/**
	 * 导出瓜子OFFER
	 *
	 * @return
	 */
	@Override
	public void exportMain(HttpServletResponse response, TGzOfferInfoVo searchVo) {
		String prfName = "瓜子OFFER信息";
		String fileName = prfName + DateUtil.getThisTime() + ".xlsx";
		//获取要导出的列表
		List<TGzOfferInfoExportMainVo> list = new ArrayList<>();
		long count = baseMapper.getTGzOfferCount(searchVo);

		ServletOutputStream out = null;
		try {
			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));
			Map<String,String> redisLabelMap = (Map<String, String>) RedisUtil.redis.opsForValue().get(CacheConstants.REDIS_DICT_LABLE);
			Map<String,String> nameAndDicTypeMap = new HashMap<>();
			ExcelUtil.getDictMapAndExp(TGzOfferInfoExportMainVo.class, nameAndDicTypeMap, redisLabelMap);
			ExcelWriter excelWriter = EasyExcelFactory.write(out, TGzOfferInfoExportMainVo.class).registerConverter(new DictConverter(nameAndDicTypeMap, redisLabelMap)).build();
			int index = 0;
			if (count > CommonConstants.ZERO_INT) {
				WriteSheet writeSheet;
				for (int i = 0; i <= count; i += CommonConstants.EXCEL_EXPORT_LIMIT){
					// 获取实际记录
					searchVo.setLimitStart(i);
					searchVo.setLimitEnd(CommonConstants.EXCEL_EXPORT_LIMIT);
					list = baseMapper.getTGzOfferMainList(searchVo);
					if (Common.isNotNull(list)) {
						writeSheet = EasyExcelFactory.writerSheet(prfName + index).build();
						excelWriter.write(list, writeSheet);
						index++;
					}

					if (Common.isNotNull(list)) {
						list.clear();
					}
				}
			} else {
				WriteSheet writeSheet = EasyExcelFactory.writerSheet(prfName + index).build();
				excelWriter.write(list, writeSheet);
			}
			if (Common.isNotNull(list)) {
				list.clear();
			}
			out.flush();
			excelWriter.finish();
		} catch (Exception e) {
			log.error("执行异常", e);
		} finally {
			try {
				if (null != out) {
					out.close();
				}
			} catch (IOException e) {
				log.error("执行异常", e);
			}
		}
	}

	/**
	 * 导出瓜子OFFER详情
	 *
	 * @return
	 */
	@Override
	public void exportDetail(HttpServletResponse response, TGzOfferInfoVo searchVo) {
		String prfName = "瓜子OFFER详情信息";
		String fileName = prfName + DateUtil.getThisTime() + ".xlsx";
		//获取要导出的列表
		List<TGzOfferInfoExportDetailVo> list = new ArrayList<>();
		long count = baseMapper.getTGzOfferCount(searchVo);

		ServletOutputStream out = null;
		try {
			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));
			// 这是获取所有字典的值
			Map<String,String> redisLabelMap = (Map<String, String>) RedisUtil.redis.opsForValue().get(CacheConstants.REDIS_DICT_LABLE);
			Map<String,String> nameAndDicTypeMap = new HashMap<>();
			ExcelUtil.getDictMapAndExp(TGzOfferInfoExportDetailVo.class, nameAndDicTypeMap, redisLabelMap);
			ExcelWriter excelWriter = EasyExcelFactory.write(out, TGzOfferInfoExportDetailVo.class).registerConverter(new DictConverter(nameAndDicTypeMap, redisLabelMap)).build();
			int index = 0;
			if (count > CommonConstants.ZERO_INT) {
				WriteSheet writeSheet;
				for (int i = 0; i <= count; i += CommonConstants.EXCEL_EXPORT_LIMIT){
					// 获取实际记录
					searchVo.setLimitStart(i);
					searchVo.setLimitEnd(CommonConstants.EXCEL_EXPORT_LIMIT);
					list = baseMapper.getTGzOfferDetailList(searchVo);
					if (Common.isNotNull(list)) {
						writeSheet = EasyExcelFactory.writerSheet(prfName + index).build();
						excelWriter.write(list, writeSheet);
						index++;
					}

					if (Common.isNotNull(list)) {
						list.clear();
					}
				}
			} else {
				WriteSheet writeSheet = EasyExcelFactory.writerSheet(prfName + index).build();
				excelWriter.write(list, writeSheet);
			}
			if (Common.isNotNull(list)) {
				list.clear();
			}
			out.flush();
			excelWriter.finish();
		} catch (Exception e) {
			log.error("执行异常", e);
		} finally {
			try {
				if (null != out) {
					out.close();
				}
			} catch (IOException e) {
				log.error("执行异常", e);
			}
		}
	}

	/**
	 * 瓜子批量更新offer状态
	 *
	 * @param tGzOfferInfo 瓜子offer信息接收表
	 * @return R
	 */
	@Override
	public R batchUpdateStatus(TGzOfferInfoVo tGzOfferInfo) {
		YifuUser user = SecurityUtils.getUser();
		if (user == null || Common.isEmpty(user.getId())) {
			return R.failed(CommonConstants.PLEASE_LOG_IN);
		}
		if(Common.isEmpty(tGzOfferInfo.getOfferIdList())){
			return R.failed("需要更新的档案集合不能为空");
		}
		if(Common.isEmpty(tGzOfferInfo.getOfferStatus())){
			return R.failed("需要更新的状态选项不能为空");
		}

		// 禁止手动变更的状态
		if (ArrayUtils.contains(forbidStatusArr, tGzOfferInfo.getOfferStatus())) {
			return R.failed("参数错误，禁止手动变更为该状态");
		}

		LambdaQueryWrapper<TGzOfferInfo> queryOffer = Wrappers.<TGzOfferInfo>lambdaQuery()
				.in(TGzOfferInfo::getId, tGzOfferInfo.getOfferIdList())
				.eq(TGzOfferInfo::getDelFlag, CommonConstants.ZERO_STRING);
		List<TGzOfferInfo> findOfferList = this.list(queryOffer);
		if(Common.isEmpty(findOfferList)){
			return R.failed("没有任何符合更新条件的数据");
		}

		// 存更新失败的offer信息
		List<TGzOfferInfo> updateFailOfferList = new ArrayList<>();

		for(TGzOfferInfo findInfo : findOfferList){
			// 当前Offer更新状态,无法再发起更新
			if (ArrayUtils.contains(failStatusArr, findInfo.getOfferStatus())) {
				updateFailOfferList.add(findInfo);
				continue;
			}
			// 更新为同一状态的提示操作失败
			if (findInfo.getOfferStatus().equals(tGzOfferInfo.getOfferStatus())) {
				updateFailOfferList.add(findInfo);
				continue;
			}
			// 获取当前状态下，允许更新的状态列表
			List<String> allowUpdateStatusList = this.allowUpdateStatus(findInfo.getOfferStatus());
			if (!allowUpdateStatusList.contains(tGzOfferInfo.getOfferStatus())) {
				updateFailOfferList.add(findInfo);
				continue;
			}

			// 更新状态
			LambdaUpdateWrapper<TGzOfferInfo> updateOfferWrapper = new LambdaUpdateWrapper<>();
			updateOfferWrapper.eq(TGzOfferInfo::getId, findInfo.getId())
					.set(TGzOfferInfo::getOfferStatus, tGzOfferInfo.getOfferStatus())
					.set(TGzOfferInfo::getUpdateTime, LocalDateTime.now())
					.set(TGzOfferInfo::getUpdateBy, user.getId());
			boolean res = this.update(null, updateOfferWrapper);
			if(!res){
				updateFailOfferList.add(findInfo);
				continue;
			}

			// 记录状态变更的offer操作日志 记录来源: 手动更新状态
			this.saveOfferStatusRecord(tGzOfferInfo.getId(),CommonConstants.ONE_STRING,
					findInfo.getOfferStatus(),tGzOfferInfo.getOfferStatus(),user.getId(),user.getNickname());
		}

		if(Common.isEmpty(updateFailOfferList)){
			return R.ok("批量更新成功");
		}

		return R.failed(updateFailOfferList,"存在更新失败的数据，未找到该状态下需要更新的人员信息");
	}

	/**
	 * 记录单个状态变更的offer操作日志
	 * @param offerId offerId
	 * @param recordFrom 记录来源：1：手动更新状态；7：档案审核
	 * @param beforeStatus 变更前状态
	 * @param nowStatus 当前状态
	 * @param userId 触发人ID
	 * @param nickname 触发人名称
	 */
	private void saveOfferStatusRecord(Integer offerId, String recordFrom,
									   String beforeStatus, String nowStatus, String userId, String nickname){
		// 记录offer操作日志
		LGuaziOfferRecordVo lGuaziOfferRecordVo = new LGuaziOfferRecordVo();
		// 存变更前后的状态到 状态数组里
		List<String> changeStatusList = new ArrayList<>();
		changeStatusList.add(beforeStatus);
		changeStatusList.add(nowStatus);

		if(changeStatusList.size() > 0){
			lGuaziOfferRecordVo.setOfferId(offerId);
			// 记录来源
			lGuaziOfferRecordVo.setRecordFrom(recordFrom);
			lGuaziOfferRecordVo.setChangeStatusList(changeStatusList);
			lGuaziOfferRecordVo.setCreateBy(userId);
			lGuaziOfferRecordVo.setCreateName(nickname);
			lGuaziOfferRecordService.saveRecordOne(lGuaziOfferRecordVo);
		}
	}

	/**
	 * 记录批量状态变更的offer操作日志
	 * @param offerIds offerId集合
	 * @param recordFrom 记录来源
	 * @param beforeStatus 变更前状态
	 * @param nowStatus 当前状态
	 * @param userId 触发人ID
	 * @param nickname 触发人名称
	 */
	private void saveBatchOfferStatusRecord(List<Integer> offerIds, String recordFrom,
									   String beforeStatus, String nowStatus, String userId, String nickname){
		// 记录offer操作日志
		LGuaziOfferRecordVo lGuaziOfferRecordVo = new LGuaziOfferRecordVo();
		// 存变更前后的状态到 状态数组里
		List<String> changeStatusList = new ArrayList<>();
		changeStatusList.add(beforeStatus);
		changeStatusList.add(nowStatus);

		if(changeStatusList.size() > 0){
			lGuaziOfferRecordVo.setOfferIds(offerIds);
			// 记录来源
			lGuaziOfferRecordVo.setRecordFrom(recordFrom);
			lGuaziOfferRecordVo.setChangeStatusList(changeStatusList);
			lGuaziOfferRecordVo.setCreateBy(userId);
			lGuaziOfferRecordVo.setCreateName(nickname);
			lGuaziOfferRecordService.saveRecordBatch(lGuaziOfferRecordVo);
		}
	}

	/**
	 * 记录批量发送短信的offer操作日志
	 * @param offerIds offerId集合
	 * @param recordFrom 记录来源：3：发送Offer查阅短信；4：发送信息收集短信；12：发送合同下载短信
	 * @param sendSmsRes 发送短信结果：0成功，1失败
	 * @param userId 触发人ID
	 * @param nickname 触发人名称
	 */
	private void saveSendSmsRecord(List<Integer> offerIds, String recordFrom,
									   String sendSmsRes, String userId, String nickname){
		// 记录offer操作日志
		LGuaziOfferRecordVo lGuaziOfferRecordVo = new LGuaziOfferRecordVo();

		lGuaziOfferRecordVo.setOfferIds(offerIds);
		lGuaziOfferRecordVo.setSendSmsRes(sendSmsRes);
		// 记录来源
		lGuaziOfferRecordVo.setRecordFrom(recordFrom);
		lGuaziOfferRecordVo.setCreateBy(userId);
		lGuaziOfferRecordVo.setCreateName(nickname);
		lGuaziOfferRecordService.saveRecordBatch(lGuaziOfferRecordVo);
	}
}
