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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasc.open.api.bean.base.BaseRes;
import com.fasc.open.api.bean.common.Actor;
import com.fasc.open.api.bean.common.OpenId;
import com.fasc.open.api.bean.common.TemplateField;
import com.fasc.open.api.exception.ApiException;
import com.fasc.open.api.v5_1.client.OpenApiClient;
import com.fasc.open.api.v5_1.client.ServiceClient;
import com.fasc.open.api.v5_1.client.SignTaskClient;
import com.fasc.open.api.v5_1.client.TemplateClient;
import com.fasc.open.api.v5_1.req.signtask.*;
import com.fasc.open.api.v5_1.req.template.GetSignTemplateListReq;
import com.fasc.open.api.v5_1.req.template.GetTemplatePreviewUrlReq;
import com.fasc.open.api.v5_1.req.template.SignTemplateDetailReq;
import com.fasc.open.api.v5_1.req.template.SignTemplateListFilterInfo;
import com.fasc.open.api.v5_1.res.service.AccessTokenRes;
import com.fasc.open.api.v5_1.res.signtask.CreateSignTaskRes;
import com.fasc.open.api.v5_1.res.signtask.SignTaskGetFileRes;
import com.fasc.open.api.v5_1.res.template.*;
import com.yifu.cloud.plus.v1.yifu.archives.entity.*;
import com.yifu.cloud.plus.v1.yifu.archives.mapper.TAttaInfoMapper;
import com.yifu.cloud.plus.v1.yifu.archives.mapper.TEmployeeContractPreMapper;
import com.yifu.cloud.plus.v1.yifu.archives.service.TFascPushLogService;
import com.yifu.cloud.plus.v1.yifu.archives.util.IdCardUtil;
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.constant.ExcelAttribute;
import com.yifu.cloud.plus.v1.yifu.common.core.exception.CheckedException;
import com.yifu.cloud.plus.v1.yifu.common.core.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.alibaba.fastjson.serializer.SerializerFeature.*;

/**
 * @Author: hgw
 * @Date: 2025-9-25 14:24:53
 * @return: 企业法大大专业版配置
 **/
@Component
public class FascUtil {

	@Autowired
	private RedisTemplate redisTemplate;
	@Autowired
	//private FascConfig fascConfig;

	private static final String DATA_COVER = "dataCover";
	private static final String DATE_FORMAT = "dateFormat";

	private static final SerializerFeature[] features = new SerializerFeature[]{
			WriteMapNullValue, WriteNullNumberAsZero, WriteNullListAsEmpty,
			WriteNullStringAsEmpty, WriteDateUseDateFormat
	};

	/**
	 * @Description: 获取token
	 * @Author: huyc
	 * @Date: 2023/7/28 14:46
	 * @return: java.lang.String
	 **/
	public String getFascToken(OpenApiClient openApiClient, TFascCompany company) throws ApiException {
		String tokenKey = CacheConstants.FASC_ACCOSS_TOKEN;
		Object wxToken = redisTemplate.opsForValue().get(tokenKey);
		if (null != wxToken) {
			return String.valueOf(wxToken);
		}
		if (openApiClient == null) {
			openApiClient = new OpenApiClient(company.getAppId(), company.getAppSecret(), company.getAppUrl());
		}
		ServiceClient serviceClient = new ServiceClient(openApiClient);
		BaseRes<AccessTokenRes> res = serviceClient.getAccessToken();
		String token = null;
		if (res != null && res.isSuccess() && res.getData() != null && res.getData().getAccessToken() != null) {
			token = res.getData().getAccessToken();
		}
		if (Common.isEmpty(token)) {
			throw new CheckedException("获取法大大专业版token失败");
		}
		redisTemplate.opsForValue().set(tokenKey, token);
		redisTemplate.expire(tokenKey, 3600, TimeUnit.SECONDS);
		return token;
	}

	/**
	 * @Description: 获取模板
	 * @Author: hgw
	 * @Date: 2025/10/10 17:59
	 * @return: java.util.List<com.fasc.open.api.v5_1.res.template.SignTemplateListInfo>
	 **/
	public List<SignTemplateListInfo> getTemplateList(String templateName, TFascPushLogService tFascPushLogService, TFascCompany company)
			throws ApiException {
		OpenApiClient openApiClient = new OpenApiClient(company.getAppId(), company.getAppSecret(), company.getAppUrl());
		TemplateClient templateClient = new TemplateClient(openApiClient);
		String accessToken = this.getFascToken(openApiClient, company);

		GetSignTemplateListReq getSignTemplateListReq = new GetSignTemplateListReq();
		getSignTemplateListReq.setListPageNo(1);
		getSignTemplateListReq.setListPageSize(100);
		OpenId ownerId = new OpenId();
		ownerId.setIdType(CacheConstants.FASC_ID_TYPE);
		ownerId.setOpenId(company.getOpenId());
		getSignTemplateListReq.setOwnerId(ownerId);
		SignTemplateListFilterInfo signTemplateListFilterInfo = new SignTemplateListFilterInfo();
		if (Common.isNotNull(templateName)) {
			// 签署任务模板名称，如果传了该参数，会根据名称模糊匹配查询，长度最大100个字符。
			signTemplateListFilterInfo.setSignTemplateName(templateName);
		} else {
			signTemplateListFilterInfo.setSignTemplateName("");
		}
		getSignTemplateListReq.setListFilter(signTemplateListFilterInfo);
		getSignTemplateListReq.setAccessToken(accessToken);

		// 新增推送日志
		TFascPushLog pushLog = new TFascPushLog();
		pushLog.setTransReferenceId(company.getOpenId());
		pushLog.setPushData(JSON.toJSONString(getSignTemplateListReq, features));
		pushLog.setTaskStatus(CommonConstants.ZERO_STRING);
		pushLog.setTypeKey("获取所有模板");
		pushLog.setTypeName("获取模板");
		tFascPushLogService.save(pushLog);

		BaseRes<SignTemplateListRes> res = templateClient.getSignTemplateList(getSignTemplateListReq);
		List<SignTemplateListInfo> list = null;
		if (res != null) {
			// 更新日志
			pushLog.setReturnData(JSON.toJSONString(res, features));
			pushLog.setTaskStatus(res.isSuccess() ? CommonConstants.ONE_STRING : CommonConstants.TWO_STRING);
			tFascPushLogService.updateById(pushLog);

			if (res.isSuccess() && res.getData() != null && res.getData().getSignTemplates() != null
					&& !res.getData().getSignTemplates().isEmpty()) {
				list = res.getData().getSignTemplates();
				if (res.getData().getListPageCount() != null) {
					int listPageCount = res.getData().getListPageCount();
					// 超过1页的循环查询
					if (listPageCount > 1) {
						for (int i = 2; i <= listPageCount; i++) {
							getSignTemplateListReq.setListPageNo(i);

							pushLog = new TFascPushLog();
							pushLog.setTransReferenceId(company.getOpenId());
							pushLog.setPushData(JSON.toJSONString(getSignTemplateListReq, features));
							pushLog.setTaskStatus(CommonConstants.ZERO_STRING);
							pushLog.setTypeKey(pushLog.getId() + "获取所有模板" + i);
							pushLog.setTypeName("分页循环获取模板");
							tFascPushLogService.save(pushLog);

							res = templateClient.getSignTemplateList(getSignTemplateListReq);
							if (res != null) {
								// 更新日志
								pushLog.setReturnData(JSON.toJSONString(res, features));
								pushLog.setTaskStatus(res.isSuccess() ? CommonConstants.ONE_STRING : CommonConstants.TWO_STRING);
								tFascPushLogService.updateById(pushLog);

								if (res.getData().getSignTemplates() != null && !res.getData().getSignTemplates().isEmpty()) {
									list.addAll(res.getData().getSignTemplates());
								}
							}
						}
					}
				}
			}
		}
		return list;
	}

	/**
	 * @Description: 获取明细映射
	 * @Author: hgw
	 * @Date: 2025/10/10 17:59
	 * @return: void
	 **/
	public void getTemplateDetailList(List<SignTemplateListInfo> templateList, List<TFascTemplate> tList
			, List<TFascTemplateDetail> detailList, TFascPushLogService tFascPushLogService
			, TFascCompany company) throws ApiException {
		OpenApiClient openApiClient = new OpenApiClient(company.getAppId(), company.getAppSecret(), company.getAppUrl());
		TemplateClient templateClient = new TemplateClient(openApiClient);
		String accessToken = this.getFascToken(openApiClient, company);

		OpenId openId = new OpenId();
		openId.setIdType(CacheConstants.FASC_ID_TYPE);
		openId.setOpenId(company.getOpenId());
		List<DocumentInfo> list = null;
		if (templateList != null && !templateList.isEmpty()) {
			// 调用查询模板详情接口
			SignTemplateDetailReq signTemplateDetailReq;
			BaseRes<SignTemplateDetailRes> res;
			TFascTemplate template;
			TFascTemplateDetail detail;
			String signTemplateId;
			String fieldType;
			String isMust;
			StringBuilder zhangName;
			String docId;
			for (SignTemplateListInfo mainInfo : templateList) {
				if (mainInfo != null && mainInfo.getSignTemplateId() != null) {
					zhangName = new StringBuilder();
					template = new TFascTemplate();
					signTemplateId = mainInfo.getSignTemplateId();
					template.setSignTemplateId(signTemplateId);
					template.setSignTemplateName(mainInfo.getSignTemplateName());
					template.setSignTemplateStatus(mainInfo.getSignTemplateStatus());
					if (Common.isNotNull(mainInfo.getCreateTime())) {
						template.setFascCreateTime(LocalDateTimeUtils.coverStringToLDT(mainInfo.getCreateTime()));
					}
					if (Common.isNotNull(mainInfo.getUpdateTime())) {
						template.setFascUpdateTime(LocalDateTimeUtils.coverStringToLDT(mainInfo.getUpdateTime()));
					}

					template.setCompanyId(company.getId());
					template.setCompanyName(company.getCompanyName());
					template.setSignName(company.getCompanyName());
					template.setSignOpenId(company.getOpenId());
					template.setCreatorMemberName(mainInfo.getCreatorMemberName());
					template.setDeleteFlag(CommonConstants.NOT_DELETE_FLAG);
					tList.add(template);

					signTemplateDetailReq = new SignTemplateDetailReq();
					signTemplateDetailReq.setOwnerId(openId);
					signTemplateDetailReq.setSignTemplateId(mainInfo.getSignTemplateId());
					signTemplateDetailReq.setAccessToken(accessToken);

					// 新增推送日志
					TFascPushLog pushLog = new TFascPushLog();
					pushLog.setTransReferenceId(company.getOpenId());
					pushLog.setPushData(JSON.toJSONString(signTemplateDetailReq, features));
					pushLog.setTaskStatus(CommonConstants.ZERO_STRING);
					pushLog.setTypeKey("获取所有明细映射");
					pushLog.setTypeName("获取明细映射");
					tFascPushLogService.save(pushLog);

					res = templateClient.getSignTemplateDetail(signTemplateDetailReq);

					if (res != null) {
						// 更新日志
						pushLog.setReturnData(JSON.toJSONString(res, features));
						pushLog.setTaskStatus(res.isSuccess() ? CommonConstants.ONE_STRING : CommonConstants.TWO_STRING);
						tFascPushLogService.updateById(pushLog);

						if (res.isSuccess() && res.getData() != null && res.getData().getActors() != null
								&& !res.getData().getActors().isEmpty()) {
							String companyActorId = null;
							String personActorId = null;
							for (SignTaskActorInfo actor : res.getData().getActors()) {
								if (Common.isEmpty(companyActorId) && actor.getActorInfo() != null
										&& Common.isNotNull(actor.getActorInfo().getActorType())
										&& "corp".equals(actor.getActorInfo().getActorType())
										&& Common.isNotNull(actor.getActorInfo().getActorId())) {
									companyActorId = actor.getActorInfo().getActorId();
								}
								if (Common.isEmpty(personActorId) && actor.getActorInfo() != null
										&& Common.isNotNull(actor.getActorInfo().getActorType())
										&& "person".equals(actor.getActorInfo().getActorType())
										&& Common.isNotNull(actor.getActorInfo().getActorId())) {
									personActorId = actor.getActorInfo().getActorId();
								}
							}
							template.setCompanyActorId(companyActorId);
							template.setPersonActorId(personActorId);
						}
						if (res.isSuccess() && res.getData() != null && res.getData().getDocs() != null
								&& !res.getData().getDocs().isEmpty()) {
							if (list == null) {
								list = new ArrayList<>();
							}
							// 循环文档（1,2,3）
							for (DocumentInfo doc : res.getData().getDocs()) {
								if (doc.getDocFields() != null && Common.isNotNull(doc.getDocId())) {
									docId = String.valueOf(doc.getDocId());
									// 循环文档里的字段
									for (TemplateField fields : doc.getDocFields()) {
										fieldType = fields.getFieldType();
										if (Common.isNotNull(fieldType)) {
											if (FascConstants.FIELD_TEXT_TYPE.contains(fieldType)) {
												// 文本数字等控件
												detail = new TFascTemplateDetail();
												detail.setSignTemplateId(signTemplateId);
												detail.setFascDocId(docId);
												detail.setFascField(fields.getFieldName());
												detail.setFascFieldId(fields.getFieldId());
												isMust = CommonConstants.ONE_STRING;
												if (this.isFieldNotRequired(fields, fieldType)) {
													isMust = CommonConstants.ZERO_STRING;
												}
												detail.setIsMust(isMust);
												detail.setDeleteFlag(CommonConstants.NOT_DELETE_FLAG);
												detailList.add(detail);
											} else if (FascConstants.FIELD_ZHANG_TYPE.contains(fieldType)) {
												// 章控件
												if (zhangName.length() > 0) {
													zhangName.append("；");
												}
												zhangName.append(fields.getFieldName());
											}
										}
									}
								}
							}
						}
					}
					template.setZhangName(zhangName.toString());
				}
			}
		}
	}

	/**
	 * @param fields    字段属性
	 * @param fieldType 字段类型
	 * @Description: 统一判断字段是否非必填
	 * @Author: hgw
	 * @Date: 2025/10/10 16:10
	 * @return: boolean
	 **/
	private boolean isFieldNotRequired(TemplateField fields, String fieldType) {
		switch (fieldType) {
			case "text_single_line":
				return fields.getFieldTextSingleLine() != null && Boolean.FALSE.equals(fields.getFieldTextSingleLine().getRequired());
			case "text_multi_line":
				return fields.getFieldTextMultiLine() != null && Boolean.FALSE.equals(fields.getFieldTextMultiLine().getRequired());
			case "number":
				return fields.getFieldNumber() != null && Boolean.FALSE.equals(fields.getFieldNumber().getRequired());
			case "id_card":
				return fields.getFieldIdCard() != null && Boolean.FALSE.equals(fields.getFieldIdCard().getRequired());
			case "fill_date":
				return fields.getFieldFillDate() != null && Boolean.FALSE.equals(fields.getFieldFillDate().getRequired());
			default:
				return false;
		}
	}

	public R<String> submitContract(TEmployeeContractPre contract, TFascPushLogService tFascPushLogService
			, TEmployeeContractPreMapper tEmployeeContractPreMapper
			, TFascTemplate tFascTemplate, List<TFascTemplateDetail> detailList, TFascCompany company) throws ApiException {
		OpenApiClient openApiClient = new OpenApiClient(company.getAppId(), company.getAppSecret(), company.getAppUrl());
		String accessToken = this.getFascToken(openApiClient, company);
		OpenId openId = new OpenId();
		openId.setIdType(CacheConstants.FASC_ID_TYPE);
		openId.setOpenId(company.getOpenId());

		SignTaskClient signTaskClient = new SignTaskClient(openApiClient);
		CreateWithTemplateReq createWithTemplateReq = new CreateWithTemplateReq();
		createWithTemplateReq.setAccessToken(accessToken);
		createWithTemplateReq.setInitiator(openId);
		createWithTemplateReq.setSignTaskSubject("签署合同-" + contract.getEmpIdcard() + CommonConstants.DOWN_LINE_STRING + DateUtil.getThisTime());
		createWithTemplateReq.setAutoStart(false);// 不要自动提交
		createWithTemplateReq.setAutoFillFinalize(true);// 自动定稿
		createWithTemplateReq.setAutoFinish(true);// 签署完成后自动结束
		createWithTemplateReq.setCertCAOrg("CFCA");// 签署参与方使用的签章证书颁发机构，默认无要求。CFCA：要求使用CFCA（中国金融认证中心）；EZCA：要求使用东方中讯CA
		createWithTemplateReq.setSignTemplateId(contract.getFadadaTemplateId());

		// 核心代码：设置参与方列表
		createWithTemplateReq.setActors(this.buildActors(contract, company, tFascTemplate));
		// 新增推送日志
		TFascPushLog pushLog = new TFascPushLog();
		pushLog.setTransReferenceId(company.getOpenId());
		pushLog.setPushData(JSON.toJSONString(createWithTemplateReq, features));
		pushLog.setTaskStatus(CommonConstants.ZERO_STRING);
		String empIdCard = contract.getEmpIdcard();
		pushLog.setTypeKey("发起合同签署任务，身份证：" + empIdCard);
		pushLog.setTypeName("发起合同签署任务");
		pushLog.setContractId(contract.getId());
		tFascPushLogService.save(pushLog);

		BaseRes<CreateSignTaskRes> res = signTaskClient.createWithTemplate(createWithTemplateReq);
		String requestId = null;
		String msg = "法大大第一步创建签署任务失败！";
		if (res != null) {
			// 更新日志
			pushLog.setReturnData(JSON.toJSONString(res, features));
			pushLog.setTaskStatus(res.isSuccess() ? CommonConstants.ONE_STRING : CommonConstants.TWO_STRING);
			if (res.isSuccess() && res.getData() != null && res.getData().getSignTaskId() != null) {
				requestId = res.getData().getSignTaskId();
				pushLog.setSignTaskId(requestId);
			}
			tFascPushLogService.updateById(pushLog);
			if (Common.isNotNull(requestId)) {
				// 第二步：填写控件
				R<String> sendValue = buildDocFieldValue(contract, requestId, openApiClient, accessToken, detailList);
				if (R.isSuccess(sendValue)) {
					// 第三步：提交任务
					sendValue = submitTask(requestId, openApiClient, accessToken);
					if (R.isSuccess(sendValue)) {
						// 电子签签署中
						this.doSuccessContract(contract, tEmployeeContractPreMapper, requestId);
						return R.ok();
					} else {
						msg = "第三步失败：提交任务失败：" + sendValue.getMsg();
					}
				} else {
					msg = "第二步失败：填写控件失败：" + sendValue.getMsg();
				}
			} else {
				msg = "第一步失败：" + res.getMsg();
			}
		}
		this.doFailContract(contract, tEmployeeContractPreMapper, msg);
		return R.failed(msg);
	}

	// 发起失败，更新合同状态
	private void doFailContract(TEmployeeContractPre contract, TEmployeeContractPreMapper tEmployeeContractPreMapper, String msg) {
		contract.setProcessStatus(CommonConstants.dingleDigitStrArray[7]);
		contract.setRequestMsg(msg);
		tEmployeeContractPreMapper.updateById(contract);
	}

	// 发起成功，更新合同状态
	private void doSuccessContract(TEmployeeContractPre contract, TEmployeeContractPreMapper tEmployeeContractPreMapper, String requestId) {
		// 电子签签署中
		contract.setProcessStatus(CommonConstants.dingleDigitStrArray[6]);
		contract.setRequestId(requestId);
		contract.setRequestMsg("");
		tEmployeeContractPreMapper.updateById(contract);
	}

	public static final String YEAR_MONTH_DATE_FORMAT = "yyyy年MM月";

	// 第二步：填写控件
	private R<String> buildDocFieldValue(TEmployeeContractPre contract, String requestId
			, OpenApiClient openApiClient, String accessToken
			, List<TFascTemplateDetail> detailList) throws ApiException {
		SignTaskClient signTaskClient = new SignTaskClient(openApiClient);
		FillFieldValuesReq fillFieldValuesReq = new FillFieldValuesReq();
		fillFieldValuesReq.setSignTaskId(requestId);
		List<DocFieldValueInfo> docFieldValues = new ArrayList<>();

		if (detailList != null && !detailList.isEmpty()) {
			DocFieldValueInfo dfv;
			String fieldValue;
			String fieldName;
			// 字段中文名
			String fieldNameChinese;
			for (TFascTemplateDetail detail : detailList) {
				if (Common.isNotNull(detail.getHrFieldId()) && Common.isNotNull(detail.getHrField())) {
					fieldValue = null;
					dfv = new DocFieldValueInfo();
					dfv.setDocId(detail.getFascDocId());
					dfv.setFieldId(detail.getFascFieldId());

					// 转化字段
					fieldName = detail.getHrFieldId();
					fieldNameChinese = detail.getHrField();
					if (FascConstants.CONTRACT_DURATION.equals(fieldName)) {
						fieldValue = contract.getContractDurationYear() + CommonConstants.CENTER_SPLIT_LINE_STRING + contract.getContractDurationMonth();
					} else if (FascConstants.DISPATCH_PERIOD.equals(fieldName)) {
						fieldValue = contract.getDispatchPeriodYear() + CommonConstants.CENTER_SPLIT_LINE_STRING + contract.getDispatchPeriodMonth();
					}  else if (FascConstants.EMP_SEX.equals(fieldName)) {
						fieldValue = "";
						if(Common.isNotNull(contract.getEmpIdcard()) && contract.getEmpIdcard().length() > 14){
							String idCard = contract.getEmpIdcard();
							fieldValue = IdCardUtil.getSexName(idCard);
						}
					} else if (FascConstants.EMP_BIRTHDAY_MONTH.equals(fieldName)) {
						fieldValue = contract.getEmpIdcard();
						if(Common.isNotNull(contract.getEmpIdcard()) && contract.getEmpIdcard().length() > 14){
							String idCard = contract.getEmpIdcard();
							if (Common.isNotNull(detail.getFieldValue())) {
								fieldValue = IdCardUtil.getBirthdateByPatten(idCard, detail.getFieldValue());
							} else {
								fieldValue = IdCardUtil.getBirthdateByPatten(idCard, YEAR_MONTH_DATE_FORMAT);
							}
						}
					} else {
						if (Common.isNotNull(fieldNameChinese)) {
							// 0=已完成一定工作任务为期限,1=固定期限,2=无固定期限
							// 针对一个模板，三种类型，有的要开始时间，有的不要，这里做区分：
							if (fieldNameChinese.contains("无固定-")) {
								if (CommonConstants.TWO_STRING.equals(contract.getContractTerm())) {
									fieldValue = this.getContractFieldValueByReflection(contract, fieldName, detail.getFieldType(), detail.getFieldValue());
								}
							} else if (fieldNameChinese.contains("固定-")) {
								if (CommonConstants.ONE_STRING.equals(contract.getContractTerm())) {
									fieldValue = this.getContractFieldValueByReflection(contract, fieldName, detail.getFieldType(), detail.getFieldValue());
								}
							} else if (fieldNameChinese.contains("完成任务-")) {
								if (CommonConstants.ZERO_STRING.equals(contract.getContractTerm())) {
									fieldValue = this.getContractFieldValueByReflection(contract, fieldName, detail.getFieldType(), detail.getFieldValue());
								}
							} else {
								fieldValue = this.getContractFieldValueByReflection(contract, fieldName, detail.getFieldType(), detail.getFieldValue());
							}
						}
					}
					if (Common.isNotNull(fieldValue)) {
						dfv.setFieldValue(fieldValue);
						docFieldValues.add(dfv);
					}
				}
			}
		}

		fillFieldValuesReq.setDocFieldValues(docFieldValues);
		fillFieldValuesReq.setAccessToken(accessToken);
		BaseRes<Void> res = signTaskClient.fillFieldValues(fillFieldValuesReq);
		if (res != null) {
			if (res.isSuccess()) {
				return R.ok();
			}
			return R.failed(res.getMsg());
		}
		return R.failed("res无返回");
	}

	/**
	 * 使用反射根据字段名获取合同对象中对应字段的值
	 *
	 * @param contract  合同对象
	 * @param fieldName 字段名
	 * @return 字段值
	 */
	private String getContractFieldValueByReflection(TEmployeeContractPre contract, String fieldName, String fieldType, String fieldValue) {
		if (contract == null || fieldName == null) {
			return null;
		}

		try {
			// 获取对应的getter方法名
			String getterMethodName = "get" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);

			// 获取方法并调用
			java.lang.reflect.Method method = contract.getClass().getMethod(getterMethodName);
			Object value = method.invoke(contract);
			String valueStr = String.valueOf(value);
			valueStr = this.getCoverValue(valueStr, fieldType, fieldValue);
			return valueStr;
		} catch (Exception e) {
			// 如果找不到对应的方法，尝试直接匹配字段名
			try {
				java.lang.reflect.Field field = contract.getClass().getDeclaredField(fieldName);
				field.setAccessible(true);
				Object value = field.get(contract);
				return value != null ? value.toString() : null;
			} catch (Exception ex) {
				return null;
			}
		}
	}

	// 翻译字典
	private String getCoverValue(String valueStr, String fieldType, String fieldValue) {
		if (Common.isNotNull(valueStr) && (Common.isNotNull(fieldType))) {
			if (DATA_COVER.equals(fieldType)) {
				valueStr = convertByExp(fieldValue, valueStr);
			} else if (DATE_FORMAT.equals(fieldType)) {
				valueStr = formatStringDate(fieldValue, valueStr);
			}
		}
		return valueStr;
	}

	public static String formatStringDate(String pattern, String dateValue) {
		if (dateValue == null || dateValue.trim().isEmpty() || pattern == null) {
			return dateValue;
		}
		SimpleDateFormat sdfInput = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
		SimpleDateFormat sdfOutput = new SimpleDateFormat(pattern);

		try {
			Date date = sdfInput.parse(dateValue);
			String result = sdfOutput.format(date);
			if (Common.isNotNull(result)) {
				return result;
			} else {
				String trimmedValue = dateValue.trim();
				try {
					// 尝试解析为java.util.Date
					date = parseDate(trimmedValue);
					if (date != null) {
						java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat(pattern);
						return sdf.format(date);
					}
				} catch (Exception e) {
					// 解析失败，返回原字符串
				}
			}
		} catch (ParseException e) {
		}
		return dateValue;
	}

	/**
	 * 解析字符串为java.util.Date
	 */
	private static java.util.Date parseDate(String dateStr) {

		// 常见日期格式模式
		String[] patterns = {
				"EEE MMM dd HH:mm:ss z yyyy",
				"yyyy-MM-dd",
				"yyyy/MM/dd",
				"yyyy年MM月dd日",
				"yyyy-MM-dd HH:mm:ss",
				"yyyy/MM/dd HH:mm:ss",
				"yyyy-MM-dd HH:mm",
				"yyyy/MM/dd HH:mm"
		};

		for (String pattern : patterns) {
			try {
				java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat(pattern);
				sdf.setLenient(false); // 严格模式
				return sdf.parse(dateStr);
			} catch (Exception e) {
				// 继续尝试下一种格式
			}
		}

		return null;
	}

	/**
	 * 根据转换表达式翻译值
	 */
	private static String convertByExp(String converterExp, String value) {
		if (Common.isEmpty(converterExp) || Common.isEmpty(value)) {
			return value;
		}
		String[] items = converterExp.split(",");
		String[] keyValue;
		for (String item : items) {
			keyValue = item.split("=");
			if (keyValue.length == 2 && keyValue[0].trim().equals(value.trim())) {
				return keyValue[1].trim();
			}
		}
		return value; // 如果没有找到匹配的，返回原值
	}

	// 第三步：提交任务
	private R<String> submitTask(String requestId, OpenApiClient openApiClient, String accessToken) throws ApiException {
		SignTaskClient signTaskClient = new SignTaskClient(openApiClient);
		SignTaskBaseReq signTaskBaseReq = new SignTaskBaseReq();
		signTaskBaseReq.setSignTaskId(requestId);
		signTaskBaseReq.setAccessToken(accessToken);
		BaseRes<Void> res = signTaskClient.start(signTaskBaseReq);
		if (res != null) {
			if (res.isSuccess()) {
				return R.ok();
			}
			return R.failed(res.getMsg());
		}
		return R.failed("res无返回");
	}

	/**
	 * 构建参与方列表
	 */
	private List<AddActorsTempInfo> buildActors(TEmployeeContractPre contract, TFascCompany company, TFascTemplate tFascTemplate) {
		List<AddActorsTempInfo> actors = new ArrayList<>();

		if (Common.isNotNull(tFascTemplate.getCompanyActorId())) {
			// 添加企业方（甲方）
			actors.add(buildCompanyActor(company, tFascTemplate.getCompanyActorId()));
		}
		if (Common.isNotNull(tFascTemplate.getPersonActorId())) {
			// 添加企业方（甲方）
			// 核心代码：添加员工方（乙方）
			actors.add(buildEmployeeActor(contract, tFascTemplate.getPersonActorId()));
		}

		return actors;
	}

	/**
	 * 构建企业方参与方
	 */
	private AddActorsTempInfo buildCompanyActor(TFascCompany company, String actorId) {

		AddActorsTempInfo companyActor = new AddActorsTempInfo();

		Actor actor = new Actor();
		actor.setActorId(actorId); // 与模板中的参与方标识一致
		actor.setActorType(CacheConstants.FASC_ID_TYPE);
		actor.setActorName(company.getCompanyName());

		// 权限设置
		actor.setPermissions(Collections.singletonList("sign"));

		// 企业OpenId
		actor.setActorOpenId(company.getOpenId());

		// 通知设置
		actor.setSendNotification(true);
		// 通知地址:注：如参与方已传actorOpenId、acterFDDId或accountName，该字段会被忽略
		/*if Common.isNotNull(contract.getEmpPhone()))
			actor.setNotifyAddress(contract.getEmpPhone()
		}*/
		actor.setNotifyType(Collections.singletonList("start"));

		companyActor.setActor(actor);

		if (Common.isNotNull(company.getBusinessId())) {
			// 添加免验签
			companyActor.setSignConfigInfo(buildZhang());
		}

		return companyActor;
	}

	private TemplateSignConfigInfoReq buildZhang() {
		TemplateSignConfigInfoReq templateSignConfigInfoReq1 = new TemplateSignConfigInfoReq();
		templateSignConfigInfoReq1.setOrderNo(1);
		templateSignConfigInfoReq1.setRequestVerifyFree(true);
		return templateSignConfigInfoReq1;
	}

	/**
	 * 构建员工方参与方
	 */
	private AddActorsTempInfo buildEmployeeActor(TEmployeeContractPre contract, String actorId) {
		AddActorsTempInfo employeeActor = new AddActorsTempInfo();

		Actor actor = new Actor();
		actor.setActorId(actorId); // 与模板中的参与方标识一致
		actor.setActorType(CacheConstants.FASC_ID_TYPE_PERSON);
		actor.setActorName(contract.getEmployeeName());

		// 权限设置
		actor.setPermissions(Collections.singletonList("sign"));

		// 通知设置
		actor.setSendNotification(true);
		if (Common.isNotNull(contract.getEmpPhone())) {
			actor.setNotifyAddress(contract.getEmpPhone());
		}
		actor.setNotifyType(Collections.singletonList("start"));


		employeeActor.setActor(actor);


		return employeeActor;
	}


	// 撤销签署
	public R<String> cancelTask(TEmployeeContractPre contract, TFascPushLogService tFascPushLogService
			, TEmployeeContractPreMapper tEmployeeContractPreMapper, TFascCompany company) throws ApiException {
		OpenApiClient openApiClient = new OpenApiClient(company.getAppId(), company.getAppSecret(), company.getAppUrl());
		String accessToken = this.getFascToken(openApiClient, company);

		SignTaskClient signTaskClient = new SignTaskClient(openApiClient);
		SignTaskCancelReq signTaskCancelReq = new SignTaskCancelReq();
		signTaskCancelReq.setSignTaskId(contract.getRequestId());
		signTaskCancelReq.setAccessToken(accessToken);
		// 新增推送日志
		TFascPushLog pushLog = new TFascPushLog();
		pushLog.setTransReferenceId(company.getOpenId());
		pushLog.setPushData(JSON.toJSONString(signTaskCancelReq, features));
		pushLog.setTaskStatus(CommonConstants.ZERO_STRING);
		String empIdCard = contract.getEmpIdcard();
		pushLog.setTypeKey("发起撤销签署任务，身份证：" + empIdCard);
		pushLog.setTypeName("发起撤销签署任务");
		pushLog.setContractId(contract.getId());
		tFascPushLogService.save(pushLog);
		BaseRes<Void> res = signTaskClient.cancel(signTaskCancelReq);
		if (res != null) {
			pushLog.setReturnData(JSON.toJSONString(res, features));
			pushLog.setTaskStatus(res.isSuccess() ? CommonConstants.ONE_STRING : CommonConstants.TWO_STRING);
			tFascPushLogService.updateById(pushLog);
			if (res.isSuccess()) {
				contract.setProcessStatus(CommonConstants.dingleDigitStrArray[1]);
				contract.setSignType(CommonConstants.dingleDigitStrArray[1]);
				contract.setRequestMsg("");
				tEmployeeContractPreMapper.updateById(contract);
				return R.ok();
			} else {
				// 撤销签署失败原因为 已完成签署（处理的同时员工完成签署公司免验证签完成），则更新为签署完成的“待归档”状态。
				if (Common.isNotNull(res.getMsg()) && FascConstants.FIELD_REASON.equals(res.getMsg())) {
					contract.setProcessStatus(CommonConstants.dingleDigitStrArray[8]);
					contract.setRevokeReason(FascConstants.TIME_OUT_REASON);
				}
				contract.setRequestMsg(res.getMsg());
				tEmployeeContractPreMapper.updateById(contract);
				return R.failed(res.getMsg());
			}
		}
		return R.failed("res无返回");
	}


	// 催办
	public R<String> urgeTask(TEmployeeContractPre contract, TFascPushLogService tFascPushLogService
			, TEmployeeContractPreMapper tEmployeeContractPreMapper, TFascCompany company) throws ApiException {
		OpenApiClient openApiClient = new OpenApiClient(company.getAppId(), company.getAppSecret(), company.getAppUrl());
		String accessToken = this.getFascToken(openApiClient, company);

		SignTaskClient signTaskClient = new SignTaskClient(openApiClient);
		SignTaskBaseReq signTaskBaseReq = new SignTaskBaseReq();
		signTaskBaseReq.setSignTaskId(contract.getRequestId());
		signTaskBaseReq.setAccessToken(accessToken);

		// 新增推送日志
		TFascPushLog pushLog = new TFascPushLog();
		pushLog.setTransReferenceId(company.getOpenId());
		pushLog.setPushData(JSON.toJSONString(signTaskClient, features));
		pushLog.setTaskStatus(CommonConstants.ZERO_STRING);
		String empIdCard = contract.getEmpIdcard();
		pushLog.setTypeKey("发起催办任务，身份证：" + empIdCard);
		pushLog.setTypeName("发起催办任务");
		pushLog.setContractId(contract.getId());
		tFascPushLogService.save(pushLog);

		BaseRes<Void> res = signTaskClient.signTaskUrge(signTaskBaseReq);
		if (res != null) {
			pushLog.setReturnData(JSON.toJSONString(res, features));
			pushLog.setTaskStatus(res.isSuccess() ? CommonConstants.ONE_STRING : CommonConstants.TWO_STRING);
			tFascPushLogService.updateById(pushLog);
			if (res.isSuccess()) {
				return R.ok();
			} else {
				contract.setRequestMsg(res.getMsg());
				tEmployeeContractPreMapper.updateById(contract);
				return R.failed(res.getMsg());
			}
		}
		return R.failed("res无返回");
	}


	// 获取模板详情预览链接
	public R<String> getTemplateDetailUrl(String signTemplateId, TFascPushLogService tFascPushLogService, TFascCompany company) throws ApiException {
		OpenApiClient openApiClient = new OpenApiClient(company.getAppId(), company.getAppSecret(), company.getAppUrl());
		String accessToken = this.getFascToken(openApiClient, company);

		TemplateClient templateClient = new TemplateClient(openApiClient);
		GetTemplatePreviewUrlReq getTemplatePreviewUrlReq = new GetTemplatePreviewUrlReq();
		getTemplatePreviewUrlReq.setOpenCorpId(company.getOpenId());
		getTemplatePreviewUrlReq.setTemplateId(signTemplateId);
		getTemplatePreviewUrlReq.setAccessToken(accessToken);


		// 新增推送日志
		TFascPushLog pushLog = new TFascPushLog();
		pushLog.setTransReferenceId(company.getOpenId());
		pushLog.setPushData(JSON.toJSONString(templateClient, features));
		pushLog.setTaskStatus(CommonConstants.ZERO_STRING);
		pushLog.setTypeKey("获取模板详情预览链接，signTemplateId：" + signTemplateId);
		pushLog.setTypeName("获取模板详情预览链接");
		pushLog.setContractId(signTemplateId);
		tFascPushLogService.save(pushLog);

		BaseRes<GetTemplatePreviewUrlRes> res = templateClient.getTemplatePreviewUrl(getTemplatePreviewUrlReq);
		if (res != null) {
			pushLog.setReturnData(JSON.toJSONString(res, features));
			pushLog.setTaskStatus(res.isSuccess() ? CommonConstants.ONE_STRING : CommonConstants.TWO_STRING);
			tFascPushLogService.updateById(pushLog);
			if (res.isSuccess() && Common.isNotNull(res.getData())) {
				return R.ok(res.getData().getTemplatePreviewUrl());
			} else {
				return R.failed(res.getMsg());
			}
		}
		return R.failed("res无返回");
	}

	// 获取附件
	public boolean getFileByRequestId(TEmployeeContractPre contract, TFascPushLogService tFascPushLogService
			, TAttaInfoMapper tAttaInfoMapper, OSSUtil ossUtil, TFascCompany company) throws ApiException {
		OpenApiClient openApiClient = new OpenApiClient(company.getAppId(), company.getAppSecret(), company.getAppUrl());
		String accessToken = this.getFascToken(openApiClient, company);

		SignTaskClient signTaskClient = new SignTaskClient(openApiClient);
		SignTaskGetFileReq signTaskGetFileReq = new SignTaskGetFileReq();
		signTaskGetFileReq.setSignTaskId(contract.getRequestId());
		signTaskGetFileReq.setAccessToken(accessToken);

		// 新增推送日志
		TFascPushLog pushLog = new TFascPushLog();
		pushLog.setTransReferenceId(company.getOpenId());
		pushLog.setPushData(JSON.toJSONString(signTaskClient, features));
		pushLog.setTaskStatus(CommonConstants.ZERO_STRING);
		String empIdCard = contract.getEmpIdcard();
		pushLog.setTypeKey("获取附件，身份证：" + empIdCard);
		pushLog.setTypeName("获取附件");
		pushLog.setContractId(contract.getId());
		pushLog.setSignTaskId(contract.getRequestId());
		tFascPushLogService.save(pushLog);

		BaseRes<SignTaskGetFileRes> res = signTaskClient.signTaskGetFile(signTaskGetFileReq);
		if (res != null) {
			pushLog.setReturnData(JSON.toJSONString(res, features));
			pushLog.setTaskStatus(res.isSuccess() ? CommonConstants.ONE_STRING : CommonConstants.TWO_STRING);
			tFascPushLogService.updateById(pushLog);
			if (res.isSuccess()) {
				if (Common.isNotNull(res.getData()) && Common.isNotNull(res.getData().getDocs())) {
					for (SignTaskGetFileRes.DocFileInfo doc : res.getData().getDocs()) {
						if (Common.isNotNull(doc.getFddFileUrl())) {
							// 存储文档
							// 将法大大回传的url字符串转化为流，存储到阿里云
							this.streamUpload(doc.getFddFileUrl(), ossUtil, tAttaInfoMapper, contract.getContractId(), doc.getDocName());
						}
					}
				}
				return true;
			} else {
				return false;
			}
		}
		return false;
	}

	public void streamUpload(String fileUrl, OSSUtil ossUtil, TAttaInfoMapper tAttaInfoMapper, String domainId, String fileName) {
		InputStream inputStream = null;
		HttpURLConnection connection = null;

		try {
			// 创建URL连接
			URL url = new URL(fileUrl);
			connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("GET");
			connection.setConnectTimeout(30000);
			connection.setReadTimeout(60000);
			// 获取输入流
			inputStream = connection.getInputStream();

			String fileType = ".pdf";
			fileName += fileType;
			// Bucket 命名规范：1)只能包括小写字母，数字和短横线（-）；2)必须以小写字母或者数字开头；3)长度必须在 3-63 字节之间。
			String ossKey = "fasc/" + domainId + "/" + System.currentTimeMillis() + fileName;

			// 直接流式上传到OSS
			ossUtil.uploadFileByStream(inputStream, ossKey, null);
			TAttaInfo unitAtta = new TAttaInfo();
			unitAtta.setDomainId(domainId);
			unitAtta.setRelationType(CommonConstants.FOUR_STRING);
			unitAtta.setAttaName(fileName);
			unitAtta.setAttaSrc(ossKey);
			unitAtta.setAttaType(fileType);
			unitAtta.setCreateTime(LocalDateTime.now());
			unitAtta.setCreateName("法大大电子签");
			tAttaInfoMapper.insert(unitAtta);

		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("法大大附件流式上传失败: " + e.getMessage());
		} finally {
			// 关闭资源
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			if (connection != null) {
				connection.disconnect();
			}
		}
	}

}
