package com.yifu.cloud.plus.v1.yifu.archives.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fadada.api.utils.crypt.FddCryptUtil;
import com.fasc.open.api.constants.RequestConstants;
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.FascConfig;
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.service.*;
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.Common;
import com.yifu.cloud.plus.v1.yifu.common.core.util.R;
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.annotation.Inner;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * @auther huyc
 * @date 2022/6/29
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/fasc")
@Tag(name = "法大大专业版接口")
public class FascController {

	@Autowired
	private FascService fascService;
	@Autowired
	private FascConfig fascConfig;

	@Autowired
	private WxConfig wxConfig;

	@Autowired
	private UpmsDaprUtils upmsDaprUtils;

	private final TFascPushLogService tFascPushLogService;
	private final TEmployeeContractPreService tEmployeeContractPreService;
	private final TEmployeeContractInfoService tEmployeeContractInfoService;
	private final TEmployeeContractAuditService tEmployeeContractAuditService;
	private final TContractAutoLogService contractAutoLogService;

	private static String FASC_EVENT = "X-FASC-Event";
	private static String FASC_BIZ_CONTENT = "bizContent";
	private static String FASC_SUCCESS = "success";
	private static String FASC_BIZ_CONTENT_STR = "；fddBizContent：";

	/**
	 * @Description: 获取模板
	 * @Author: hgw
	 * @Date: 2025/9/26 16:21
	 * @return: com.yifu.cloud.plus.v1.yifu.common.core.util.R<java.lang.String>
	 **/
	@Operation(description = "每日定时获取法大大模板和详情")
	@PostMapping("/inner/everyDayGetFascTemplate")
	@Inner
	public R<String> everyDayGetFascTemplate() throws ApiException {
		return fascService.getTemplate(null);
	}

	/**
	 * @param templateName 签署任务模板名称，如果传了该参数，会根据名称模糊匹配查询，长度最大100个字符。
	 * @Description: 获取模板
	 * @Author: hgw
	 * @Date: 2025/9/26 16:21
	 * @return: com.yifu.cloud.plus.v1.yifu.common.core.util.R<java.lang.String>
	 **/
	@Operation(description = "获取模板")
	@GetMapping("/getTemplate")
	public R<String> getTemplate(@RequestParam(required = false) String templateName) throws ApiException {
		return fascService.getTemplate(templateName);
	}

	/**
	 * @param signTemplateId 签署任务模板ID
	 * @Description: 获取模板详情预览链接
	 * @Author: hgw
	 * @Date: 2025/9/26 16:21
	 * @return: com.yifu.cloud.plus.v1.yifu.common.core.util.R<java.lang.String>
	 **/
	@Operation(description = "获取模板详情预览链接")
	@GetMapping("/getTemplateDetailUrl")
	public R<String> getTemplateDetailUrl(@RequestParam String signTemplateId) throws ApiException {
		return fascService.getTemplateDetailUrl(signTemplateId);
	}

	/**
	 * @param id 合同待签订任务记录表TEmployeeContractPre：id
	 * @Description: 发起电子签署
	 * @Author: hgw
	 * @Date: 2025/10/13 17:24
	 * @return: com.yifu.cloud.plus.v1.yifu.common.core.util.R<java.lang.String>
	 **/
	@Operation(description = "发起电子签署")
	@GetMapping("/submitContract")
	public R<String> submitContract(@RequestParam String id) throws ApiException {
		return fascService.submitContract(id);
	}

	/**
	 * @param id 合同待签订任务记录表TEmployeeContractPre：id
	 * @Description: 撤销签署
	 * @Author: hgw
	 * @Date: 2025/10/13 17:24
	 * @return: com.yifu.cloud.plus.v1.yifu.common.core.util.R<java.lang.String>
	 **/
	@Operation(description = "撤销签署")
	@GetMapping("/cancelTask")
	public R<String> cancelTask(@RequestParam String id) throws ApiException {
		return fascService.cancelTask(id);
	}

	/**
	 * @param id 合同待签订任务记录表TEmployeeContractPre：id
	 * @Description: 催办
	 * @Author: hgw
	 * @Date: 2025/10/13 17:24
	 * @return: com.yifu.cloud.plus.v1.yifu.common.core.util.R<java.lang.String>
	 **/
	@Operation(description = "催办")
	@GetMapping("/urgeTask")
	public R<String> urgeTask(@RequestParam String id) throws ApiException {
		return fascService.urgeTask(id);
	}

	/**
	 * @param id 合同待签订任务记录表TEmployeeContractPre：id
	 * @Description: 获取附件
	 * @Author: hgw
	 * @Date: 2025/10/13 17:24
	 * @return: com.yifu.cloud.plus.v1.yifu.common.core.util.R<java.lang.String>
	 **/
	@Operation(description = "获取附件")
	@GetMapping("/getFileByRequestId")
	public R<String> getFileByRequestId(@RequestParam String id) throws ApiException {
		boolean flag = fascService.getFileByRequestId(id);
		return R.ok();
	}

	private YifuUser getNewYifuUser() {
		Set<String> dbAuthsSet = new HashSet<>();
		Collection<? extends GrantedAuthority> authorities = AuthorityUtils
				.createAuthorityList(dbAuthsSet.toArray(new String[0]));
		return new YifuUser("2", 1L, "", "法大大电子签",
				"法大大电子签", "0", SecurityConstants.BCRYPT + "123456",
				"12345678911", true, true, true,
				true,
				"1", authorities, "1",
				null, null,
				null,null);
	}

	@Operation(summary = "异步通知", description = "异步通知")
	@RequestMapping(value = "/api/fascCallback")
	public R<String> notifyUrl(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 新增推送日志
		TFascPushLog pushLog = new TFascPushLog();
		pushLog.setTransReferenceId(fascConfig.getOpenId());
		pushLog.setTaskStatus(CommonConstants.ONE_STRING);
		pushLog.setTypeKey("签署任务事件，异步通知");
		pushLog.setTypeName("签署任务事件，异步通知");
		tFascPushLogService.save(pushLog);

		if (checkSign(request, pushLog)) {
			pushLog.setTaskStatus(CommonConstants.TWO_STRING);
			tFascPushLogService.updateById(pushLog);
			return R.failed("验签失败");
		}
		tFascPushLogService.updateById(pushLog);
		String fddEvent = request.getHeader(FASC_EVENT);
		String fddBizContent = request.getParameter(FASC_BIZ_CONTENT);
		if (Common.isNotNull(fddEvent)) {
			JSONObject jsonObject = JSON.parseObject(fddBizContent);
			// 任务ID
			String signTaskId = jsonObject.getString("signTaskId");
			// 原因
			String terminationNote = jsonObject.getString("terminationNote");
			// 操作人
			String userName = jsonObject.getString("userName");
			pushLog.setTypeKey("fddEvent："+ fddEvent);
			pushLog.setReturnData("初始无事件：fddEvent：" + fddEvent + "fddBizContent：" + fddBizContent);

			if (Common.isNotNull(signTaskId)) {
				// 根据requestId获取信息：
				TEmployeeContractPre pre = tEmployeeContractPreService.getOne(Wrappers.<TEmployeeContractPre>query().lambda()
						.eq(TEmployeeContractPre::getRequestId, signTaskId).last(CommonConstants.LAST_ONE_SQL));
				YifuUser user = getNewYifuUser();
				if (pre != null) {
					TEmployeeContractInfo contractInfo = null;
					if (Common.isNotNull(pre.getContractId())) {
						//如果存在合同申请审核数据，将状态更新成待提交
						contractInfo = tEmployeeContractInfoService.getById(pre.getContractId());
					}
					if (contractInfo != null) {
						if (fddEvent.equals("sign-task-finished")) {
							// 1：签署任务完成事件
							// 8电子待归档
							pre.setProcessStatus(CommonConstants.dingleDigitStrArray[8]);

							// 加日志
							this.saveAuditLogSuccess(pre, "签署成功");

							// 尝试获取归档文件
							boolean flag = fascService.getFileByRequestId(pre.getId());

							contractInfo.setAuditStatus(CommonConstants.TWO_INT);
							tEmployeeContractInfoService.auditContract(contractInfo, user);
							if (flag) {
								// 加日志
								this.saveAuditLogSuccess(pre, "归档成功");
								pre.setProcessStatus(CommonConstants.dingleDigitStrArray[9]);

								contractInfo.setIsFile(CommonConstants.ZERO_STRING);
								tEmployeeContractInfoService.updateById(contractInfo);
							}
							tEmployeeContractPreService.updateById(pre);


							pushLog.setReturnData("签署任务完成事件：fddEvent：" + fddEvent + FASC_BIZ_CONTENT_STR + fddBizContent);
						} else if (fddEvent.equals("sign-task-canceled") || fddEvent.equals("sign-task-abolish")) {
							// 2：签署任务撤销事件 || 4：签署任务作废事件
							if (fddEvent.equals("sign-task-canceled")) {
								// 4：签署任务作废事件
								pushLog.setReturnData("签署任务撤销事件：fddEvent：" + fddEvent + FASC_BIZ_CONTENT_STR + fddBizContent);
							} else {
								// 4：签署任务作废事件
								pushLog.setReturnData("签署任务作废事件：fddEvent：" + fddEvent + FASC_BIZ_CONTENT_STR + fddBizContent);
							}
							//电子待归档、线下签待归档、已完结的不能撤销签署
							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())) {
									// 加日志
									this.saveAuditLogFail(pre, "撤销签署", terminationNote);
								}
								pre.setProcessStatus(CommonConstants.TEN_STRING);
								pre.setSignFlag(CommonConstants.ZERO_STRING);
								pre.setRevokeReason(terminationNote);
								tEmployeeContractPreService.updateById(pre);
							}
							//如果存在合同申请审核数据，将状态更新成待提交
							contractInfo.setAuditStatus(CommonConstants.ZERO_INT);
							contractInfo.setInUse(CommonConstants.ONE_STRING);
							tEmployeeContractInfoService.updateById(contractInfo);
						} else if (fddEvent.equals("sign-task-sign-failed")) {
							// 3：签署任务参与方签署失败事件
							pre.setProcessStatus(CommonConstants.dingleDigitStrArray[7]);
							pre.setRequestId("");
							tEmployeeContractPreService.updateById(pre);

							//如果存在合同申请审核数据，将状态更新成待提交
							contractInfo.setAuditStatus(CommonConstants.ZERO_INT);
							contractInfo.setInUse(CommonConstants.ONE_STRING);
							tEmployeeContractInfoService.updateById(contractInfo);

							UUID uuid = UUID.randomUUID();
							//生成快照数据
							TContractAutoLog contractAutoLog = new TContractAutoLog();
							contractAutoLog.setContractId(uuid.toString());
							contractAutoLog.setEmpName(pre.getEmployeeName());
							contractAutoLog.setEmpIdcard(pre.getEmpIdcard());
							contractAutoLog.setMainId(pre.getId());
							contractAutoLog.setErrorInfo(terminationNote);
							contractAutoLogService.save(contractAutoLog);
							//签署失败发送企微消息
							sendFddFalureInfoToWx(pre,contractAutoLog.getId());

							// 加日志
							this.saveAuditLogFail(pre, "签署失败", terminationNote);
							pushLog.setReturnData("签署任务参与方签署失败事件：fddEvent：" + fddEvent + FASC_BIZ_CONTENT_STR + fddBizContent);
						}
					}
				}
			}
			tFascPushLogService.updateById(pushLog);
			return R.ok(null, FASC_SUCCESS);
		}

		return R.ok(null, FASC_SUCCESS);
	}

	// 加合同里的流程进展明细的日志——成功
	public void saveAuditLogSuccess(TEmployeeContractPre tEmployeeContractPre, String rootName) {
		// 加流程进展明细
		if (tEmployeeContractPre != null && Common.isNotNull(tEmployeeContractPre.getContractId())) {
			this.saveAuditLogInfo(tEmployeeContractPre.getContractId(), rootName, "审核通过", null);
		}
	}
	// 加合同里的流程进展明细的日志——失败
	public void saveAuditLogFail(TEmployeeContractPre tEmployeeContractPre, String rootName, String remark) {
		// 加流程进展明细
		if (tEmployeeContractPre != null && Common.isNotNull(tEmployeeContractPre.getContractId())) {
			this.saveAuditLogInfo(tEmployeeContractPre.getContractId(), rootName, "审核不通过", remark);
		}
	}
	// 加合同里的流程进展明细的日志
	public void saveAuditLogInfo(String contractId, String rootName, String auditStatus, String remark) {
		// 加流程进展明细
		if (Common.isNotNull(contractId)) {
			TEmployeeContractAudit audit = new TEmployeeContractAudit();
			audit.setRootName(rootName);
			audit.setLinkId(contractId);
			audit.setLinkType(CommonConstants.ONE_INT);
			audit.setAuditStatus(auditStatus);
			if (Common.isNotNull(remark)) {
				audit.setRemark(remark);
			}
			audit.setCreateBy("1");
			audit.setCreateName("法大大电子签");
			tEmployeeContractAuditService.save(audit);
		}
	}

	//验证签名，返回true表示失败
	public boolean checkSign(HttpServletRequest request, TFascPushLog pushLog) throws Exception {

		Map<String, String> paraMap = new HashMap<>();
		paraMap.put(RequestConstants.APP_ID, request.getHeader(RequestConstants.APP_ID));
		paraMap.put(RequestConstants.SIGN_TYPE, request.getHeader(RequestConstants.SIGN_TYPE));

		String timeStamp = request.getHeader(RequestConstants.TIMESTAMP);
		paraMap.put(RequestConstants.TIMESTAMP, timeStamp);
		paraMap.put(RequestConstants.NONCE, request.getHeader(RequestConstants.NONCE));
		paraMap.put(FASC_EVENT, request.getHeader(FASC_EVENT));
		paraMap.put(FASC_BIZ_CONTENT, request.getParameter(FASC_BIZ_CONTENT));
		//参数排序，ascii码排序
		String sortParam = FddCryptUtil.sortParameters(paraMap);
		pushLog.setPushData(sortParam);
		//计算之后得到签名 该签名需要放到请求头
		if (Common.isEmpty(sortParam) || Common.isEmpty(timeStamp)) {
			return true;
		}
		String signature = FddCryptUtil.sign(sortParam, timeStamp, fascConfig.getAppSecret());
		if (StringUtils.equals(signature, request.getHeader(RequestConstants.SIGN))) {
			return false;
		}
		// 表示验签失败：
		return true;
	}

	/**
	 * 发送法大大失败提醒通知到企微
	 * @param pre 合同待购买
	 */
	private void sendFddFalureInfoToWx(TEmployeeContractPre pre,String id) {
		//获取前端客服
		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", "72" + id);
			StringBuilder description = new StringBuilder();
			String title = "作业自动化——电子合同签署超期自动撤回提醒";
			description.append(pre.getEmployeeName() + "-" +  pre.getEmpIdcard()+ "-" + pre.getEmpPhone() +
					"，电子合同签署失败").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);
			}
		}
	}
}
