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

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.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.TEmployeeContractAudit;
import com.yifu.cloud.plus.v1.yifu.archives.entity.TEmployeeContractInfo;
import com.yifu.cloud.plus.v1.yifu.archives.entity.TEmployeeContractPre;
import com.yifu.cloud.plus.v1.yifu.archives.mapper.TEmployeeContractPreMapper;
import com.yifu.cloud.plus.v1.yifu.archives.service.TEmployeeContractAuditService;
import com.yifu.cloud.plus.v1.yifu.archives.service.TEmployeeContractInfoService;
import com.yifu.cloud.plus.v1.yifu.archives.service.TEmployeeContractPreService;
import com.yifu.cloud.plus.v1.yifu.archives.service.TSettleDomainService;
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.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.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
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.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 TSettleDomainService tSettleDomainService;

	private final TEmployeeContractAuditService tEmployeeContractAuditService;

	@Autowired
	private final TEmployeeContractInfoService contractInfoService;

	@Autowired
	private WxConfig wxConfig;

	@Autowired
	private UpmsDaprUtils upmsDaprUtils;

    /**
     * 合同待签订任务记录表简单分页查询
     * @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").collect(Collectors.toList()));
		}
		return baseMapper.getTEmployeeContractPrePage(page,tEmployeeContractPre);
    }

	/**
	 * 合同待签订任务记录表手机端不分页查询
	 * @param tEmployeeContractPre 合同待签订任务记录表
	 * @return
	 */
	@Override
	public List<TEmployeeContractPre> getTEmployeeContractPreNoPage(TEmployeeContractPreSearchVo tEmployeeContractPre) {
		//权限赋值
		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) {
		//权限赋值
		initSearchVo(tEmployeeContractPre);
		if (Common.isEmpty(tEmployeeContractPre.getProcessStatus())&& Common.isEmpty(tEmployeeContractPre.getStatusList())) {
			tEmployeeContractPre.setStatusList(Stream.of("0","1","2","3","4","5","6","7","8").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").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)) {
					pre.setId(preExit.getId());
					baseMapper.deleteById(preExit);
					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 = baseMapper.selectList(Wrappers.<TEmployeeContractPre>query()
				.lambda().in(TEmployeeContractPre::getId, idList)
				.in(TEmployeeContractPre::getProcessStatus, CommonConstants.socialInfoStatus));
		// 如果没有找到任何未处理的合同待派单数据，返回失败消息
		if (Common.isEmpty(contractPreList)) {
			return R.failed(CommonConstants.NO_DATA_TO_HANDLE);
		}
		//发起派单
		List<ErrorMessage> errorMessageListAll = new ArrayList<>();
		List<EmployeeContractVO> excelVOList = baseMapper.getDisPatcherContractList(idList,CommonConstants.socialInfoStatus,type);
		if (Common.isNotNull(excelVOList) && !excelVOList.isEmpty()) {
			List<EmployeeContractVO> disList;
			int k = 0;
			int i = (int) Math.ceil((double) excelVOList.size() / CommonConstants.INTEGER_HUNDRED);
			for (int j = 0; j < i; j++) {
				if (j == i - 1) {
					disList = excelVOList.subList(k, excelVOList.size());
				} else {
					disList = excelVOList.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);
								LambdaUpdateWrapper<TEmployeeContractPre> updateWrapper = new LambdaUpdateWrapper<>();
								updateWrapper.in(TEmployeeContractPre::getId, contractVO.getPreId())
										.in(TEmployeeContractPre::getProcessStatus, CommonConstants.socialInfoStatus)
										.set(TEmployeeContractPre::getProcessStatus, CommonConstants.FIVE_STRING)
										.set(TEmployeeContractPre::getErrorInfo, errorMessage.getMessage())
										.set(TEmployeeContractPre::getErrorTime, LocalDateTimeUtils.convertLDToDate(LocalDate.now()));
								// 执行更新操作
								this.update(updateWrapper);
							}
						}
					}
				}
			}
		}
		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.EIGHT_STRING));
			if (Common.isEmpty(contractPreList)) {
				return R.failed(CommonConstants.NO_DATA_TO_HANDLE);
			}
			TEmployeeContractPre pre;
			TEmployeeContractInfo contractInfo;
			for (TEmployeeAutoRegistRevokeVo registRevokeVo : registRevokeVoList) {
				pre = baseMapper.selectById(registRevokeVo.getId());
				//电子待归档、线下签待归档、已完结的不能撤销签署
				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);
						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.ZERO_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) {
		return baseMapper.selectCount(Wrappers.<TEmployeeContractPre>query().lambda()
				.eq(TEmployeeContractPre::getEmpIdcard, vo.getEmpIdcard())
				.eq(TEmployeeContractPre::getDeptNo, vo.getDeptNo())
				.ne(TEmployeeContractPre::getProcessStatus, CommonConstants.NINE_STRING)
				.ne(TEmployeeContractPre::getProcessStatus, CommonConstants.TEN_STRING)
				.last(CommonConstants.LAST_ONE_SQL)) > 0;
	}

	//发送企业微信待办
	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);
			}
		}
	}

	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;
	}
}
