package com.xinelu.manage.service.aiob.impl;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.xinelu.common.config.AliYunSmsTwoConfig;
import com.xinelu.common.config.SystemBusinessConfig;
import com.xinelu.common.constant.*;
import com.xinelu.common.core.redis.RedisCache;
import com.xinelu.common.enums.*;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.common.utils.StringUtils;
import com.xinelu.manage.domain.batchsendtaskinfo.BatchSendTaskInfo;
import com.xinelu.manage.domain.patientinfo.PatientInfo;
import com.xinelu.manage.domain.patientquestionoptionresult.PatientQuestionOptionResult;
import com.xinelu.manage.domain.patientquestionsubjectresult.PatientQuestionSubjectResult;
import com.xinelu.manage.domain.patientquestionsubmitresult.PatientQuestionSubmitResult;
import com.xinelu.manage.domain.patienttaskexecuterecord.PatientTaskExecuteRecord;
import com.xinelu.manage.domain.patientvisitrecord.PatientVisitRecord;
import com.xinelu.manage.domain.phonedialrecord.PhoneDialRecord;
import com.xinelu.manage.domain.questioninfo.QuestionInfo;
import com.xinelu.manage.domain.questionsubjectoption.QuestionSubjectOption;
import com.xinelu.manage.domain.scriptInfo.ScriptInfo;
import com.xinelu.manage.domain.scriptinfotaskinfo.ScriptInfoTaskInfo;
import com.xinelu.manage.domain.signpatientmanageroute.SignPatientManageRoute;
import com.xinelu.manage.domain.signpatientmanageroutenode.SignPatientManageRouteNode;
import com.xinelu.manage.domain.signpatientrecord.SignPatientRecord;
import com.xinelu.manage.domain.textmessage.TextMessage;
import com.xinelu.manage.dto.aiob.*;
import com.xinelu.manage.dto.patientquestionsubmitresult.PatientQuestionSubmitResultDTO;
import com.xinelu.manage.dto.smssend.SmsInfoDTO;
import com.xinelu.manage.mapper.batchsendtaskinfo.BatchSendTaskInfoMapper;
import com.xinelu.manage.mapper.labelfieldcontent.LabelFieldContentMapper;
import com.xinelu.manage.mapper.patientinfo.PatientInfoMapper;
import com.xinelu.manage.mapper.patientquestionoptionresult.PatientQuestionOptionResultMapper;
import com.xinelu.manage.mapper.patientquestionsubjectresult.PatientQuestionSubjectResultMapper;
import com.xinelu.manage.mapper.patientquestionsubmitresult.PatientQuestionSubmitResultMapper;
import com.xinelu.manage.mapper.patienttaskexecuterecord.PatientTaskExecuteRecordMapper;
import com.xinelu.manage.mapper.patientvisitrecord.PatientVisitRecordMapper;
import com.xinelu.manage.mapper.phonedialrecord.PhoneDialRecordMapper;
import com.xinelu.manage.mapper.questioninfo.QuestionInfoMapper;
import com.xinelu.manage.mapper.questionsubject.QuestionSubjectMapper;
import com.xinelu.manage.mapper.questionsubjectoption.QuestionSubjectOptionMapper;
import com.xinelu.manage.mapper.scriptInfo.ScriptInfoMapper;
import com.xinelu.manage.mapper.scriptinfotaskinfo.ScriptInfoTaskInfoMapper;
import com.xinelu.manage.mapper.signpatientmanageroute.SignPatientManageRouteMapper;
import com.xinelu.manage.mapper.signpatientmanageroutenode.SignPatientManageRouteNodeMapper;
import com.xinelu.manage.mapper.signpatientrecord.SignPatientRecordMapper;
import com.xinelu.manage.mapper.textmessage.TextMessageMapper;
import com.xinelu.manage.service.aiob.IAIOBService;
import com.xinelu.manage.service.patienttaskstatistics.IPatientTaskStatisticsService;
import com.xinelu.manage.service.signpatientmanageroute.ISignPatientManageRouteService;
import com.xinelu.manage.service.signpatientmanageroutenode.ISignPatientManageRouteNodeService;
import com.xinelu.manage.vo.aiob.ImportTaskVo;
import com.xinelu.manage.vo.labelfieldcontent.LabelFieldInfoContentVo;
import com.xinelu.manage.vo.questionsubject.QuestionSubjectVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @description: 百度客悦·智能外呼平台Service实现
 * @author: haown
 * @create: 2024-08-22 09:54
 **/
@Slf4j
@Service
public class AIOBServiceImpl implements IAIOBService {
	@Value("${aiob.url}")
	private String url;

	@Value("${aiob.accessKey}")
	private String accessKey;

	@Value("${aiob.secretKey}")
	private String secretKey;

	@Resource
	private RedisCache redisCache;

	@Resource
	private SystemBusinessConfig systemBusinessConfig;

	@Resource
	private SignPatientRecordMapper signPatientRecordMapper;
	@Resource
	private SignPatientManageRouteMapper signPatientManageRouteMapper;
	@Resource
	private SignPatientManageRouteNodeMapper signPatientManageRouteNodeMapper;
	@Resource
	private PhoneDialRecordMapper phoneDialRecordMapper;
	@Resource
	private AliYunSmsTwoConfig aliYunSmsTwoConfig;
	@Resource
	private ISignPatientManageRouteService signPatientManageRouteService;
	@Resource
	private ISignPatientManageRouteNodeService signPatientManageRouteNodeService;
	@Resource
	private TextMessageMapper textMessageMapper;
	@Resource
	private PatientTaskExecuteRecordMapper patientTaskExecuteRecordMapper;
	@Resource
	private IPatientTaskStatisticsService patientTaskStatisticsService;
	@Resource
	private PatientInfoMapper patientInfoMapper;
	@Resource
	private LabelFieldContentMapper labelFieldContentMapper;
	@Resource
	private ScriptInfoMapper scriptInfoMapper;
	@Resource
	private QuestionInfoMapper questionInfoMapper;
	@Resource
	private PatientQuestionSubmitResultMapper questionSubmitResultMapper;
	@Resource
	private QuestionSubjectMapper questionSubjectMapper;
	@Resource
	private PatientQuestionSubjectResultMapper patientQuestionSubjectResultMapper;
	@Resource
	private QuestionSubjectOptionMapper questionSubjectOptionMapper;
	@Resource
	private PatientQuestionOptionResultMapper patientQuestionOptionResultMapper;
	@Resource
	private ScriptInfoTaskInfoMapper scriptInfoTaskInfoMapper;
	@Resource
	private PatientVisitRecordMapper patientVisitRecordMapper;
	@Resource
	private BatchSendTaskInfoMapper batchSendTaskInfoMapper;

	/**
	 * @description 获取外呼平台accessToken
	 * @return 智能外呼平台 accessToken
	 * @Author haown
	 * @Date 2024-8-22 15:30
	*/
	@Override
	public String getAccessToken() {
		String accessToken = redisCache.getCacheObject("AIOBAssessToken");
		if (StringUtils.isBlank(accessToken)) {
			JSONObject requestBodyJson = new JSONObject();
			requestBodyJson.put("secretKey", secretKey);
			requestBodyJson.put("accessKey", accessKey);

			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_JSON);
			HttpEntity<JSONObject> requestEntity = new HttpEntity<>(requestBodyJson, headers);

			RestTemplate restTemplate = new RestTemplate();
			ResponseEntity<String> responseEntity = restTemplate.exchange(url + "/v2/getToken", HttpMethod.POST, requestEntity, String.class);
			JSONObject object = JSON.parseObject(responseEntity.getBody());
			if (object == null || object.getInteger("code") == null || object.getInteger("code") != 200) {
				throw new ServiceException("获取accessToken失败！");
			}
			JSONObject data = object.getJSONObject("data");
			// accessToken放入redis缓存
			accessToken = data.getString("accessToken");
			// 有效期30天
			int expires_in = data.getInteger("expiresTime");
			redisCache.setCacheObject("AIOBAssessToken", accessToken, expires_in, TimeUnit.MINUTES);
		}
		return accessToken;
		//{
		//  "time" : 1724293180993,
		//  "code" : 200,
		//  "msg" : "OK",
		//  "data" : {
		//    "tenantId" : 3849515568332800,
		//    "accessToken" : "cc-api-auth-v2/10.B88F964FF8AEF605D75872F1B0EDFE57B28609A057F5E24104B4A7FB74CD63EC8199731D637E6EDFD195A82D5DFF454E",
		//    "expiresTime" : 43200,
		//    "accessKey" : "b6d2d73cdf2d4d7ca2ccc84968accdb3",
		//    "secretKey" : "9262d2fe32544eaabce18331bd5ca2c5"
		//  }
		//}
	}

	/**
	 * @description 创建任务
	 * @param createTaskDto 创建任务传输对象
	 * @return taskId 客悦·智能外呼平台任务唯一标识
	 * @Author haown
	 * @Date 2024-8-22 15:34
	*/
	@Override
	public String createTask(CreateTaskDto createTaskDto) {
		String accessToken = getAccessToken();
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		headers.set("Authorization", accessToken);

		HttpEntity<JSONObject> requestEntity = new HttpEntity<>((JSONObject)JSON.toJSON(createTaskDto), headers);
		RestTemplate restTemplate = new RestTemplate();
		ResponseEntity<String> responseEntity = restTemplate.exchange(url + "/v3/console/apitask/create", HttpMethod.POST, requestEntity, String.class);
		JSONObject object = JSON.parseObject(responseEntity.getBody());
		if (object == null || object.getInteger("code") == null || object.getInteger("code") != 200) {
			throw new ServiceException("创建任务失败，" + object.getString("msg"));
		}
		JSONObject data = object.getJSONObject("data");
		return data.getString("taskId");
		// {
		//       "code": 200,
		//       "msg": "success",
		//       "data": {
		//           "taskId": "731346584781056" //任务ID，必填
		//       }
		//   }
	}

	/**
	 * @description 创建实时任务
	 * @param actualTimeTaskDto 百度外呼创建实时任务传输对象
	 * @return memberId 被叫号码系统唯一标识，可根据该标识查询通话记录
	 * @Author haown
	 * @Date 2024-9-20 16:15
	 */
	@Override public Long createActualTimeTask(ActualTimeTaskDto actualTimeTaskDto) {
		String accessToken = getAccessToken();
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		headers.set("Authorization", accessToken);

		HttpEntity<JSONObject> requestEntity = new HttpEntity<>((JSONObject)JSON.toJSON(actualTimeTaskDto), headers);
		RestTemplate restTemplate = new RestTemplate();
		ResponseEntity<String> responseEntity = restTemplate.exchange(url + "/v3/console/realtime/status/create", HttpMethod.POST, requestEntity, String.class);
		JSONObject object = JSON.parseObject(responseEntity.getBody());
		if (object == null || object.getInteger("code") == null || object.getInteger("code") != 200) {
			throw new ServiceException("创建任务失败，" + object.getString("msg"));
		}
		JSONObject data = object.getJSONObject("data");
		return data.getLong("memberId");
	}

	/**
	 * @description 任务状态变更
	 * @param taskId 任务id
	 * @param taskStatus 修改状态 2：执行中，3：已暂停，4：已完成（如点击「终止」
	 * @return 状态码
	 * @Author haown
	 * @Date 2024-8-23 11:49
	 */
	@Override
	public Integer updateTaskStatus(String taskId, Integer taskStatus) {
		String accessToken = getAccessToken();
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		headers.set("Authorization", accessToken);

		JSONObject jsonObject = new JSONObject();
		jsonObject.fluentPut("taskId", taskId)
			.fluentPut("taskStatus", taskStatus);
		HttpEntity<JSONObject> requestEntity = new HttpEntity<>(jsonObject, headers);
		RestTemplate restTemplate = new RestTemplate();
		ResponseEntity<String> responseEntity = restTemplate.exchange(url + "/v3/console/apitask/task/status/update", HttpMethod.POST, requestEntity, String.class);
		JSONObject object = JSON.parseObject(responseEntity.getBody());
		if (object == null || object.getInteger("code") == null || object.getInteger("code") != 200) {
			throw new ServiceException("修改任务状态失败，" + object.getString("msg"));
		}
		return 1;
		// {
		//	"requestId": "c323dc9e5f67427c9c9d735a76e14164",
		//	"time": 1724375025670,
		//	"code": 200,
		//	"msg": "OK",
		//	"data": null
		//}
	}

	/**
	 * @description 任务导入客户名单
	 * @param importTaskDto 导入名单传输对象
	 * @return 名单导入结果
	 * @Author haown
	 * @Date 2024-8-23 17:34
	 */
	@Override
	public List<ImportTaskVo> importTask(ImportTaskDto importTaskDto) {
		String accessToken = getAccessToken();
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		headers.set("Authorization", accessToken);

		HttpEntity<JSONObject> requestEntity = new HttpEntity<>((JSONObject)JSON.toJSON(importTaskDto), headers);
		RestTemplate restTemplate = new RestTemplate();
		ResponseEntity<String> responseEntity = restTemplate.exchange(url + "/v3/console/apitask/import", HttpMethod.POST, requestEntity, String.class);
		JSONObject object = JSON.parseObject(responseEntity.getBody());
		if (object == null || object.getInteger("code") == null || object.getInteger("code") != 200) {
			throw new ServiceException("导入名单失败，" + object.getString("msg"));
		}
		JSONObject data = object.getJSONObject("data");

		JSONArray resList = data.getJSONArray("resList");
		List<ImportTaskVo> importTaskList = Arrays.asList(resList.toArray(ImportTaskVo.class));
		return importTaskList;
	}

	/**
	 * @description 任务执行回调方法
	 * @param callbackType 回调数据类型， 0-任务呼叫单通电话回调 1-号码组终态回调 2-任务状态变更回调 3-实时呼叫单通电话回调
	 * @param data 任务单通电话回调传输data
	 * @return JSONObject
	 * @Author haown
	 * @Date 2024-9-2 14:20
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public JSONObject taskCallBack(Integer callbackType, TaskCallbackDataDto data) throws ClientException {
		JSONObject retObj = new JSONObject();
		retObj.fluentPut("code", 200).fluentPut("msg", "success");
		if (callbackType == 0 || callbackType == 3) {
			// 是否发送短信标识
			boolean needSendSms = false;
			// 是否重拨
			boolean needRedial = false;
			// 根据id查询任务
			SignPatientManageRouteNode signPatientManageRouteNode = signPatientManageRouteNodeMapper.selectSignPatientManageRouteNodeById(Long.valueOf(data.getExtJson()));
			if (ObjectUtils.isNotEmpty(signPatientManageRouteNode)) {
				// 标记任务执行状态
				signPatientManageRouteNode.setNodeExecuteStatus(NodeExecuteStatusEnum.EXECUTED.getInfo());

				//接通状态，1-已接通 0-未接通
				//如果未接通
				if (data.getEndType() != null && data.getEndType() == 0) {
					// 设置电话拨通情况
					signPatientManageRouteNode.setPhoneNodeExecuteResultStatus(NodeExecuteResultStatusEnum.FAILURE.getInfo());
					// 电话短信提醒
					if (StringUtils.equals(PhoneMessageRemindConstants.NOT_CONNECTED_SEND_MESSAGE, signPatientManageRouteNode.getPhoneMessageRemind())) {
						// 发送短信
						needSendSms = true;
					}

					// 实时任务设置电话重拨
					//zyk 20241219  增加==0
					if (callbackType == 3 || callbackType == 0) {
						// 查询拨打次数
						PhoneDialRecord phoneDialRecordQuery = new PhoneDialRecord();
						phoneDialRecordQuery.setManageRouteNodeId(signPatientManageRouteNode.getId());
						List<PhoneDialRecord> phoneDialRecordList = phoneDialRecordMapper.selectPhoneDialRecordList(phoneDialRecordQuery);
						String redialTimes = StringUtils.isEmpty(signPatientManageRouteNode.getPhoneRedialTimes())?"NOT_REPLAY":signPatientManageRouteNode.getPhoneRedialTimes();
						if ((CollectionUtils.isEmpty(phoneDialRecordList) && PhoneRedialTimesEnum.getValueByInfo(redialTimes).getValue() > 0)
								|| phoneDialRecordList.size() + 1 < PhoneRedialTimesEnum.getValueByInfo(redialTimes).getValue()) {
							// 重拨
							needRedial = true;
						}
						//如果不需要重拨，则设置完成时间,问卷提交失败
						else
						{
							// 问卷设置任务完成时间
							if (StringUtils.equals(TaskNodeTypeEnum.QUESTIONNAIRE_SCALE.getInfo(), signPatientManageRouteNode.getTaskNodeType())) {
								signPatientManageRouteNode.setNodeFinishDate(LocalDateTime.now());
								signPatientManageRouteNode.setNodeFinishStatus(NodeExecuteResultStatusEnum.FAILURE.getInfo());
							}
						}
					}
				} else {
					signPatientManageRouteNode.setPhoneNodeExecuteResultStatus(NodeExecuteResultStatusEnum.SUCCESS.getInfo());
					// 问卷设置任务完成时间,问卷提交成功
					if (StringUtils.equals(TaskNodeTypeEnum.QUESTIONNAIRE_SCALE.getInfo(), signPatientManageRouteNode.getTaskNodeType())) {
						signPatientManageRouteNode.setNodeFinishDate(LocalDateTime.now());
						signPatientManageRouteNode.setNodeFinishStatus(NodeExecuteResultStatusEnum.SUCCESS.getInfo());
					}
					if (StringUtils.equals(PhoneMessageRemindConstants.CONNECTED_SEND_MESSAGE, signPatientManageRouteNode.getPhoneMessageRemind())) {
						// 发送短信
						needSendSms = true;
					}
					// 记录通话详情 放到外面执行
					// signPatientManageRouteNode.setPhoneResultJson(com.alibaba.fastjson.JSON.toJSONString(data, SerializerFeature.WriteMapNullValue));
				}

				signPatientManageRouteNode.setPhoneResultJson(com.alibaba.fastjson.JSON.toJSONString(data, SerializerFeature.WriteMapNullValue));

				signPatientManageRouteNodeMapper.updateSignPatientManageRouteNode(signPatientManageRouteNode);

				// 重拨表任务执行状态修改
				scriptInfoTaskInfoMapper.updateExecuteStatusByNodeId(signPatientManageRouteNode.getId());

				// 任务执行记录
				PatientTaskExecuteRecord patientTaskExecuteRecord = new PatientTaskExecuteRecord();
				BeanUtils.copyProperties(signPatientManageRouteNode, patientTaskExecuteRecord);
				SignPatientManageRoute signPatientManageRoute = signPatientManageRouteMapper.selectSignPatientManageRouteById(signPatientManageRouteNode.getManageRouteId());
				if (ObjectUtils.isNotEmpty(signPatientManageRoute)) {
					patientTaskExecuteRecord.setPatientId(signPatientManageRoute.getPatientId());
					patientTaskExecuteRecord.setPatientName(signPatientManageRoute.getPatientName());
					// 签约记录
					SignPatientRecord signPatientRecord = new SignPatientRecord();
					//针对batch_send_task_info表未签约未存patient_info表处理
					if (Objects.nonNull(signPatientManageRoute.getSignPatientRecordId())){
						signPatientRecord = signPatientRecordMapper.selectByPrimaryKey(signPatientManageRoute.getSignPatientRecordId());
					}
					if (ObjectUtils.isNotEmpty(signPatientRecord)) {
						patientTaskExecuteRecord.setVisitRecordId(signPatientRecord.getPatientVisitRecordId());
					}

					// 发送短信
					if (needSendSms) {
						sendSms(signPatientManageRoute.getPatientId(), signPatientManageRouteNode, signPatientManageRoute.getBatchSendTaskId());
					}
					// 重拨
					if (needRedial) {
						if (ObjectUtils.isNotEmpty(signPatientRecord)) {
							PatientVisitRecord patientVisitRecord = patientVisitRecordMapper.selectPatientVisitRecordById(signPatientRecord.getPatientVisitRecordId());
							redialInfoSave(signPatientManageRouteNode, patientVisitRecord);
						} else {
							redialInfoSave(signPatientManageRouteNode, null);
						}
					}
				}
				// 增加任务执行记录
				patientTaskExecuteRecord.setManageRouteNodeId(signPatientManageRouteNode.getId());
				patientTaskExecuteRecord.setManageRouteNodeName(signPatientManageRouteNode.getRouteNodeName());
				patientTaskExecuteRecord.setExecuteResult(data.getEndTypeReason());
				patientTaskExecuteRecord.setExecuteType(TaskCreateTypeConstant.MANUAL_MATCHE);
				patientTaskExecuteRecord.setExecuteTime(LocalDateTime.now());
				patientTaskExecuteRecord.setCreateTime(LocalDateTime.now());

				// 增加电话拨打记录
				PhoneDialRecord phoneDialRecord = new PhoneDialRecord();
				phoneDialRecord.setPatientId(signPatientManageRoute.getPatientId());
				phoneDialRecord.setManageRouteNodeId(signPatientManageRouteNode.getId());
				phoneDialRecord.setPatientPhone(data.getMobile());
				phoneDialRecord.setDialTime(LocalDateTime.now());
				phoneDialRecord.setPhoneTemplateId(signPatientManageRouteNode.getScriptInfoId() + "");
				phoneDialRecord.setPhoneDialMethod(signPatientManageRouteNode.getPhoneDialMethod());
				phoneDialRecord.setErrorCode(data.getEndType() == 0 ? 1L : 0);
				phoneDialRecord.setErrorStatus(data.getEndType() == 0 ? ErrorStatusEnum.fail.getValue() : ErrorStatusEnum.success.getValue());
				phoneDialRecord.setCreateTime(LocalDateTime.now());

				phoneDialRecord.setCtUuid(data.getContactUUID());
				//phoneDialRecord.setPhoneDialRecordVideo(getPhoneDialRecord(data.getContactUUID()));

				phoneDialRecordMapper.insertPhoneDialRecord(phoneDialRecord);

				// 修改任务统计表数据 添加getPatientId判断针对batch_send_task_info表未签约未存patient_info表处理
				if (Objects.nonNull(patientTaskExecuteRecord.getPatientId()) && patientTaskExecuteRecordMapper.insertPatientTaskExecuteRecord(patientTaskExecuteRecord) > 0) {
					// 任务统计表修改
					if (Objects.nonNull(signPatientManageRoute.getPatientId())){
						patientTaskStatisticsService.updateNum(signPatientManageRoute.getPatientId(), TaskStatisticsTypeConstants.TASK_EXECUTE_NUM, 1);
					}
				}

				//接通状态，1-已接通
				if (data.getEndType() != null && data.getEndType() == 1) {
					// 问卷记录保存
					if (StringUtils.equals(signPatientManageRouteNode.getTaskNodeType(), TaskNodeTypeEnum.QUESTIONNAIRE_SCALE.getInfo())) {
						parseQuestionInfo(data.getRecord(), signPatientManageRouteNode, signPatientManageRoute.getPatientId(), patientTaskExecuteRecord.getId());
					}
				}

			}
		}
		return retObj;
	}

	/**
	 * @description
	 * @Param ccUUID 通话录音唯一标识
	 * @return 录音下载地址
	 * @Author haown
	 * @Date 2024-11-8 13:47
	*/
	@Override public String record(String ccUUID) {
		String accessToken = getAccessToken();
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		headers.set("Authorization", accessToken);

		HttpEntity<JSONObject> requestEntity = new HttpEntity<>(null, headers);
		RestTemplate restTemplate = new RestTemplate();
		Map<String, Object> params = new HashMap<>();
		params.put("contactUuid", ccUUID);
		params.put("expiration", 1800);
		params.put("operation", 3);
		ResponseEntity<String> responseEntity = restTemplate.exchange(url + "/v1/record"+"?contactUuid={contactUuid}&expiration={expiration}&operation={operation}", HttpMethod.GET, requestEntity, String.class, params);
		//{
		//  "requestId" : "9c5870a37e2441ad9ccc9100d870054e",
		//  "time" : 1730701318185,
		//  "code" : 200,
		//  "msg" : "OK",
		//  "data" : [ {
		//    "recordUrl" : "https://gz.bcebos.com/v1/cc-call-recording/2024/09/19/3849515568332800/14/1726726696417508_628800_1726726696448834_936326_14_18_42.wav?authorization=bce-auth-v1%2FALTAKOVf6H3DUWVqVqc2k43RAa%2F2024-11-04T06%3A21%3A58Z%2F1800%2F%2Fe33651c189f512aaa3c94f68f8136dc69538c680c94c8605696de5a041c36f49",
		//    "downloadUrl" : "https://gz.bcebos.com/v1/cc-call-recording/2024/09/19/3849515568332800/14/1726726696417508_628800_1726726696448834_936326_14_18_42.wav?responseContentDisposition=attachment%3B%20filename%3D1726726696417508_628800_1726726696448834_936326_14_18_42.wav&authorization=bce-auth-v1%2FALTAKOVf6H3DUWVqVqc2k43RAa%2F2024-11-04T06%3A21%3A58Z%2F1800%2F%2Fa802d88ba4b987f1a0f30ce73b515c8515255b34e5bac4f1d0c27987ac70d68a"
		//  } ]
		//}
		JSONObject object = JSON.parseObject(responseEntity.getBody());
		if (object == null || object.getInteger("code") == null || object.getInteger("code") != 200) {
			return null;
		}
		JSONArray data = object.getJSONArray("data");
		JSONObject obj = data.getJSONObject(0);
		return obj.getOrDefault("downloadUrl", null).toString();
	}

	private void sendSms(Long patientId, SignPatientManageRouteNode signPatientManageRouteNode, Long batchSendTaskId) throws ClientException {
		TextMessage textMessage = textMessageMapper.selectTextMessageById(signPatientManageRouteNode.getPhoneMessageTemplateId());
		if (ObjectUtils.isNotEmpty(textMessage)) {
			// 发送短信
			SmsInfoDTO smsInfoDTO = new SmsInfoDTO();
			String patientPhone = null;
			//添加PatientId判断针对batch_send_task_info表未签约未存patient_info表处理
			if (Objects.nonNull(patientId)){
				patientPhone = signPatientManageRouteMapper.selectPatientPhone(patientId);
			}
			if (Objects.nonNull(patientId)){
				//批量推送任务表没有同步到患者表，所以分开查询
				BatchSendTaskInfo batchSendTaskInfo = batchSendTaskInfoMapper.selectBatchSendTaskInfoById(batchSendTaskId);
				patientPhone = batchSendTaskInfo.getPatientPhone();
			}
			smsInfoDTO.setPhoneNumbers(patientPhone);
			smsInfoDTO.setSignName(aliYunSmsTwoConfig.getSignName());
			smsInfoDTO.setTemplateCode(textMessage.getTextMessageId());
			Boolean b = signPatientManageRouteService.sendSms(smsInfoDTO);
			//发送记录
			PatientQuestionSubmitResultDTO dto = new PatientQuestionSubmitResultDTO();
			dto.setPatientId(patientId);
			dto.setPatientPhone(patientPhone);
			dto.setManageRouteNodeId(signPatientManageRouteNode.getId());
			dto.setPhoneMessageTemplateCode(textMessage.getTextMessageId());
			dto.setPhoneMessageTemplateContent(signPatientManageRouteNode.getPhoneMessageTemplateContent());
			signPatientManageRouteService.shortMessageSendRecordExtracted(dto, LocalDateTime.now(), b, PhoneDialMethodEnum.AI.getInfo());
			//修改电话短信发送情况
			SignPatientManageRouteNode updatePhoneMessage = new SignPatientManageRouteNode();
			updatePhoneMessage.setId(signPatientManageRouteNode.getId());
			if (!b) {
				updatePhoneMessage.setPhoneMessageNodeExecuteResultStatus("FAILURE");
				log.info("短信发送失败");
			} else {
				updatePhoneMessage.setPhoneMessageNodeExecuteResultStatus("SUCCESS");
				log.info("短信发送成功");
			}
			signPatientManageRouteNodeMapper.updateSignPatientManageRouteNode(updatePhoneMessage);
		} else {
			log.info("短信发送成功");
		}
	}

	private void uploadCustomerInfoList(SignPatientManageRouteNode node, String taskId) {
		CustomerInfoDto customerInfoDto = new CustomerInfoDto();
		List<CustomerInfoDto> customerInfoList = new ArrayList<>();
		customerInfoDto.setExtJson(node.getId() + "");
		SignPatientManageRoute signPatientManageRoute = signPatientManageRouteMapper.selectSignPatientManageRouteById(node.getManageRouteId());
		PatientInfo patientInfo = patientInfoMapper.selectPatientInfoById(signPatientManageRoute.getPatientId());
		customerInfoDto.setMobile(patientInfo.getPatientPhone());
		// 查询患者画像信息
		List<LabelFieldInfoContentVo> labelFieldContentList = labelFieldContentMapper.selectByPatientId(patientInfo.getId());
		ScriptInfo scriptInfo = scriptInfoMapper.selectScriptInfoById(node.getScriptInfoId());
		// 处理变量
		JSONObject jsonObject = new JSONObject();
		if (StringUtils.isNotBlank(scriptInfo.getVariables())) {
			List<String> variables = Arrays.asList(scriptInfo.getVariables().split("|"));
			variables.forEach(variable -> {
				LabelFieldInfoContentVo labelFieldContent = labelFieldContentList.stream().filter(s -> Objects.equals(s.getFieldCode(), variable.replaceAll("_", "").toUpperCase())).findFirst().orElse(null);
				jsonObject.fluentPut(variable, ObjectUtils.isEmpty(labelFieldContent) ? "" : labelFieldContent.getFieldValue());
			});
		}

		customerInfoDto.setVar(jsonObject);
		customerInfoList.add(customerInfoDto);
		// 上传名单
		ImportTaskDto importTaskDto = new ImportTaskDto();
		importTaskDto.setTaskId(taskId);
		importTaskDto.setSecretType(2);
		importTaskDto.setCustomerInfoList(customerInfoList);
		importTask(importTaskDto);
	}

	/**
	 * @description 通过通话记录解析问卷内容
	 * @param records 通话记录
	 * @Author haown
	 * @Date 2024-9-6 14:30
	*/
	private void parseQuestionInfo(JSONArray records, SignPatientManageRouteNode node, Long patientInfoId, Long taskExecuteRecordId) {
		List<AiobRecord> aiobRecords = records.toList(AiobRecord.class);
		List<AiobRecord> speechList = aiobRecords.stream().filter(record -> StringUtils.equals("speech", record.getRole()) && !StringUtils.equals("抱歉,我不太理解您的意思", record.getContextText()))
			.collect(Collectors.toMap(AiobRecord::getContextText, p -> p, (p1, p2) -> p2))
			.values()
			.stream()
			.sorted(Comparator.comparing(AiobRecord::getTimestamp))
			.collect(Collectors.toList());
		speechList.forEach(s->{
			if(StringUtils.isNull(s.getIntent())) s.setIntent("");
		});

		// 查询患者画像信息
		List<LabelFieldInfoContentVo> labelFieldContentList = labelFieldContentMapper.selectByPatientId(patientInfoId);

		Map<String, String> contextMap = speechList.stream().collect(Collectors.toMap(AiobRecord::getContextText, AiobRecord::getIntent));

		PatientInfo patientInfo = patientInfoMapper.selectPatientInfoById(patientInfoId);
		QuestionInfo questionInfo = questionInfoMapper.selectQuestionInfoById(node.getQuestionInfoId());
		// 1、保存patient_question_submit_result
		PatientQuestionSubmitResult patientQuestionSubmitResult = new PatientQuestionSubmitResult();
		patientQuestionSubmitResult.setTaskExecuteRecordId(taskExecuteRecordId);
		patientQuestionSubmitResult.setPatientName(patientInfo.getPatientName());
		patientQuestionSubmitResult.setPatientId(patientInfoId);
		patientQuestionSubmitResult.setManageRouteId(node.getManageRouteId());
		patientQuestionSubmitResult.setManageRouteName(node.getManageRouteName());
		patientQuestionSubmitResult.setManageRouteNodeId(node.getId());
		patientQuestionSubmitResult.setManageRouteNodeName(node.getRouteNodeName());
		patientQuestionSubmitResult.setQuestionInfoId(questionInfo.getId());
		patientQuestionSubmitResult.setDepartmentId(questionInfo.getDepartmentId());
		patientQuestionSubmitResult.setDepartmentName(questionInfo.getDepartmentName());
		patientQuestionSubmitResult.setDiseaseTypeId(questionInfo.getDiseaseTypeId());
		patientQuestionSubmitResult.setDiseaseTypeName(questionInfo.getDiseaseTypeName());
		patientQuestionSubmitResult.setQuestionnaireName(questionInfo.getQuestionnaireName());
		patientQuestionSubmitResult.setQuestionnaireDescription(questionInfo.getQuestionnaireDescription());
		patientQuestionSubmitResult.setAnsweringMethod(questionInfo.getAnsweringMethod());
		patientQuestionSubmitResult.setQuestionnaireId(questionInfo.getQuestionnaireId());
		patientQuestionSubmitResult.setQuestionCount(questionInfo.getQuestionCount());
		patientQuestionSubmitResult.setQuestionnaireTotalScore(questionInfo.getQuestionnaireTotalScore());
		patientQuestionSubmitResult.setResidentId(patientInfo.getResidentId());
		patientQuestionSubmitResult.setCreateTime(LocalDateTime.now());
		questionSubmitResultMapper.insertPatientQuestionSubmitResult(patientQuestionSubmitResult);
		// 2、保存patient_question_subject_result
		final BigDecimal[] totalScore = { BigDecimal.ZERO };
		List<QuestionSubjectVO> questionSubjectList = questionSubjectMapper.selectQuestionSubjectBy(node.getQuestionInfoId());
		questionSubjectList.forEach(questionSubjectVO -> {
			// 判断问题中有无变量，有变量替换变量
			String questionNameAlias = replaceQuestionName(questionSubjectVO.getQuestionNameAlias(), labelFieldContentList);
			// 根据通话记录筛查是否询问该问题
			boolean hasQuestion = false;
			String aiobQuestionName = "";
			for (String questionContent : contextMap.keySet()) {
				if (questionContent.replaceAll("\\p{P}", "").contains(questionNameAlias.replaceAll("\\p{P}", ""))) {
					hasQuestion = true;
					aiobQuestionName = questionContent;
					break;
				}
			}
			if (hasQuestion) {

				String finalAiobQuestionName = aiobQuestionName;
				AiobRecord nextRecord = getNextQuestion(speechList, finalAiobQuestionName);

				PatientQuestionSubjectResult patientQuestionSubjectResult = new PatientQuestionSubjectResult();
				BeanUtils.copyProperties(questionSubjectVO, patientQuestionSubjectResult);
				patientQuestionSubjectResult.setId(null);
				patientQuestionSubjectResult.setQuestionSubmitResultId(patientQuestionSubmitResult.getId());
				patientQuestionSubjectResult.setCreateTime(LocalDateTime.now());
				//不管是否是 填空题，都 写入回答 文本
				patientQuestionSubjectResult.setFillBlanksAnswer(nextRecord.getContent());

				patientQuestionSubjectResult.setQuestionSubjectId(questionSubjectVO.getId());
				patientQuestionSubjectResultMapper.insertPatientQuestionSubjectResult(patientQuestionSubjectResult);

				// 3、保存patient_question_option_result
				QuestionSubjectOption questionSubjectOptionQuery = new QuestionSubjectOption();
				questionSubjectOptionQuery.setQuestionnaireSubjectId(questionSubjectVO.getId());
				List<QuestionSubjectOption> questionSubjectOptions = questionSubjectOptionMapper.selectQuestionSubjectOptionList(questionSubjectOptionQuery);
				List<PatientQuestionOptionResult> patientQuestionOptionResults = new ArrayList<>();

				questionSubjectOptions.forEach(questionSubjectOption -> {
					PatientQuestionOptionResult patientQuestionOptionResult = new PatientQuestionOptionResult();
					BeanUtils.copyProperties(questionSubjectOption, patientQuestionOptionResult);
					// 设置是否选中, 通过通话记录中下一个问题的intent字段查询QuestionSubjectOption，
					List<String> intents = Arrays.asList(questionSubjectOption.getIntent().split("\\|"));
					if (ObjectUtils.isNotEmpty(nextRecord) && intents.contains(nextRecord.getIntent())) {
						patientQuestionOptionResult.setOptionChooseSign(0);
					} else {
						patientQuestionOptionResult.setOptionChooseSign(1);
					}
					patientQuestionOptionResult.setId(null);
					patientQuestionOptionResult.setCreateTime(LocalDateTime.now());
					patientQuestionOptionResult.setQuestionSubjectResultId(patientQuestionSubjectResult.getId());

					patientQuestionOptionResult.setQuestionSubjectOptionId(questionSubjectOption.getId());
					patientQuestionOptionResults.add(patientQuestionOptionResult);
				});
                //判断问卷 满意项与异常项
				patientQuestionSubmitResult.setRemarkableFlag(ContentedAndRemarkableFlagEnum.ROUTINE.getInfo());
				patientQuestionSubmitResult.setContentedFlag(ContentedAndRemarkableFlagEnum.CONTENTED.getInfo());
                if (CollectionUtils.isNotEmpty(patientQuestionOptionResults)) {
                    List<PatientQuestionOptionResult> remarkableFlag = patientQuestionOptionResults.stream().filter(Objects::nonNull)
							.filter(item -> org.apache.commons.lang3.StringUtils.isNotBlank(item.getRemarkableFlag())
									&& Objects.nonNull(item.getOptionChooseSign()) && item.getOptionChooseSign().equals(0)
									&& ContentedAndRemarkableFlagEnum.REMARKABLE.getInfo().equals(item.getRemarkableFlag()))
							.collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(remarkableFlag)) {
                        patientQuestionSubmitResult.setRemarkableFlag(ContentedAndRemarkableFlagEnum.REMARKABLE.getInfo());
                    }
                    List<PatientQuestionOptionResult> contentedFlag = patientQuestionOptionResults.stream().filter(Objects::nonNull).filter(item -> org.apache.commons.lang3.StringUtils.isNotBlank(item.getContentedFlag()) && Objects.nonNull(item.getOptionChooseSign()) && item.getOptionChooseSign().equals(0) && ContentedAndRemarkableFlagEnum.DISCONTENTED.getInfo().equals(item.getRemarkableFlag())).collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(contentedFlag)) {
                        patientQuestionSubmitResult.setContentedFlag(ContentedAndRemarkableFlagEnum.DISCONTENTED.getInfo());
                    }
                }

                questionSubmitResultMapper.updatePatientQuestionSubmitResult(patientQuestionSubmitResult);
				if(patientQuestionOptionResults.size()>0) {
					patientQuestionOptionResultMapper.saveQuestionOptionList(patientQuestionOptionResults);
				}
				totalScore[0] = totalScore[0].add(questionSubjectVO.getQuestionScore() == null ? BigDecimal.ZERO : questionSubjectVO.getQuestionScore());
			} else {
				// 没问到问卷中的问题，则保存空问题+空选项
				PatientQuestionSubjectResult patientQuestionSubjectResult = new PatientQuestionSubjectResult();
				BeanUtils.copyProperties(questionSubjectVO, patientQuestionSubjectResult);
				patientQuestionSubjectResult.setId(null);
				patientQuestionSubjectResult.setQuestionSubmitResultId(patientQuestionSubmitResult.getId());
				patientQuestionSubjectResult.setCreateTime(LocalDateTime.now());
				patientQuestionSubjectResultMapper.insertPatientQuestionSubjectResult(patientQuestionSubjectResult);

				// 3、保存空选项
				QuestionSubjectOption questionSubjectOptionQuery = new QuestionSubjectOption();
				questionSubjectOptionQuery.setQuestionnaireSubjectId(questionSubjectVO.getId());
				List<QuestionSubjectOption> questionSubjectOptions = questionSubjectOptionMapper.selectQuestionSubjectOptionList(questionSubjectOptionQuery);
				List<PatientQuestionOptionResult> patientQuestionOptionResults = new ArrayList<>();

				questionSubjectOptions.forEach(questionSubjectOption -> {
					PatientQuestionOptionResult patientQuestionOptionResult = new PatientQuestionOptionResult();
					BeanUtils.copyProperties(questionSubjectOption, patientQuestionOptionResult);
					patientQuestionOptionResult.setOptionChooseSign(1);
					patientQuestionOptionResult.setId(null);
					patientQuestionOptionResult.setCreateTime(LocalDateTime.now());
					patientQuestionOptionResult.setQuestionSubjectResultId(patientQuestionSubjectResult.getId());
					patientQuestionOptionResults.add(patientQuestionOptionResult);
				});
				if(patientQuestionOptionResults.size()>0) {
					patientQuestionOptionResultMapper.saveQuestionOptionList(patientQuestionOptionResults);
				}
				totalScore[0] = totalScore[0].add(BigDecimal.ZERO);
			}
		});

		// 4、更新总得分
		patientQuestionSubmitResult.setTotalScore(totalScore[0]);
		questionSubmitResultMapper.updatePatientQuestionSubmitResult(patientQuestionSubmitResult);
	}

	private AiobRecord getNextQuestion(List<AiobRecord> speechList, String currentQuestion) {
		if (StringUtils.isNotBlank(currentQuestion)) {
			for (int i = 0; i < speechList.size(); i++) {
				if (StringUtils.equals(speechList.get(i).getContextText(), currentQuestion)) {
					if (speechList.size() >= i + 1)
						return speechList.get(i + 1);
					else
						return null;
				}
			}
		}
		return null;
	}

	private String replaceQuestionName(String questionNameAlias, List<LabelFieldInfoContentVo> labelFieldContentList) {
		Pattern pattern = Pattern.compile("\\{%\\s*&[\\s\\S]*?\\s*%}");
		Matcher matcher = pattern.matcher(questionNameAlias);
		while (matcher.find()) {
			LabelFieldInfoContentVo labelFieldContent = labelFieldContentList.stream().filter(s -> Objects.equals(s.getFieldCode(), matcher.group(1).replaceAll("_", "").toUpperCase())).findFirst().orElse(null);
			if (ObjectUtils.isNotEmpty(labelFieldContent)) {
				questionNameAlias = questionNameAlias.replaceAll("\\{%\\s*&[\\s\\S]*?\\s*%}", ObjectUtils.isEmpty(labelFieldContent) ? "" : labelFieldContent.getFieldValue());
			}
		}
		return questionNameAlias;
	}

	/**
	 * @description 重拨信息保存
	 * @param signPatientManageRouteNode 任务信息
	 * @param patientVisitRecord 就诊记录信息
	 * @Author haown
	 * @Date 2024-9-24 15:08
	*/
	private void redialInfoSave(SignPatientManageRouteNode signPatientManageRouteNode, PatientVisitRecord patientVisitRecord) {
		ScriptInfoTaskInfo scriptInfoTaskInfo = new ScriptInfoTaskInfo();
		scriptInfoTaskInfo.setScriptInfoId(signPatientManageRouteNode.getScriptInfoId());
		scriptInfoTaskInfo.setRobotId(signPatientManageRouteNode.getRobotPublishId());
		scriptInfoTaskInfo.setCreateTime(LocalDateTime.now());
		scriptInfoTaskInfo.setSignPatientManageRouteNodeId(signPatientManageRouteNode.getId());
		scriptInfoTaskInfo.setAiobTaskType(AiobTaskTypeContant.ACTUALTIMETASK);
		scriptInfoTaskInfo.setExecuteStatus(NodeExecuteStatusEnum.UNEXECUTED.getInfo());
		LocalDateTime executeTime = signPatientManageRouteNode.getNodePlanTime();
		if(ObjectUtils.isNotEmpty(patientVisitRecord)) {
			executeTime = signPatientManageRouteNodeService.getExecuteTime(signPatientManageRouteNode.getExecuteTime(),
					signPatientManageRouteNode.getRouteNodeName(), signPatientManageRouteNode.getRouteNodeDay(), patientVisitRecord);
		}
		scriptInfoTaskInfo.setExecuteTime(executeTime.plusMinutes(signPatientManageRouteNode.getPhoneTimeInterval()));
		scriptInfoTaskInfoMapper.insertScriptInfoTaskInfo(scriptInfoTaskInfo);
	}

	/**
	 * @description 通话录音保存到本地并返回本地虚拟路径
	 * @Param ccUuid 通话录音唯一标识
	 * @return 录音本地虚拟路径
	 * @Author haown
	 * @Date 2024-11-8 13:49
	*/
	@Override
	public String getPhoneDialRecord(String ccUuid) {
		String url = "";
		String downLoadUrl = record(ccUuid);
		if (StringUtils.isBlank(downLoadUrl)) {
			throw new ServiceException("暂未获取到录音，请稍后再试!");
		}
		url = systemBusinessConfig.getProfile() + systemBusinessConfig.getPhoneDialRecordVideo() + "/" + ccUuid + ".wav";
		File outputPath = new File(url);
		File dir = outputPath.getParentFile();
		if (!dir.exists()){
			dir.mkdirs();
		}
		try {
			outputPath.createNewFile(); // 创建文件
			URL fileUrl = new URL(downLoadUrl);
			HttpURLConnection connection = (HttpURLConnection)fileUrl.openConnection();
			connection.setRequestMethod("GET");
			connection.connect();
			if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
				InputStream inputStream = new BufferedInputStream(connection.getInputStream());
				FileOutputStream outputStream = new FileOutputStream(outputPath);
				byte[] buffer = new byte[1024];
				int bytesRead;
				while ((bytesRead = inputStream.read(buffer)) != -1) {
					outputStream.write(buffer, 0, bytesRead);
				}
				outputStream.close();
				inputStream.close();
				return Constants.RESOURCE_PREFIX + systemBusinessConfig.getPhoneDialRecordVideo() + "/" + ccUuid + ".wav";
			} else {
				throw new ServiceException("下载录音失败，请稍后再试");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
}
