package com.xinelu.quartz.task;

import com.alibaba.fastjson2.JSONObject;
import com.xinelu.common.constant.AiobTaskTypeContant;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.core.domain.entity.SysDictData;
import com.xinelu.common.enums.*;
import com.xinelu.common.utils.StringUtils;
import com.xinelu.common.utils.regex.RegexUtil;
import com.xinelu.manage.domain.dialtime.DialTime;
import com.xinelu.manage.domain.patientinfo.PatientInfo;
import com.xinelu.manage.domain.patientvisitrecord.PatientVisitRecord;
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.dto.aiob.ActualTimeTaskDto;
import com.xinelu.manage.dto.aiob.CreateTaskDto;
import com.xinelu.manage.dto.aiob.CustomerInfoDto;
import com.xinelu.manage.dto.aiob.ImportTaskDto;
import com.xinelu.manage.dto.signpatientmanageroutenode.SignPatientManageRouteNodeDto;
import com.xinelu.manage.mapper.labelfieldcontent.LabelFieldContentMapper;
import com.xinelu.manage.mapper.patientinfo.PatientInfoMapper;
import com.xinelu.manage.mapper.patientinfoimport.PatientInfoImportMapper;
import com.xinelu.manage.mapper.patientinfoimportmain.PatientInfoImportMainMapper;
import com.xinelu.manage.mapper.patientvisitrecord.PatientVisitRecordMapper;
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.service.aiob.IAIOBService;
import com.xinelu.manage.service.signpatientmanageroutenode.ISignPatientManageRouteNodeService;
import com.xinelu.manage.vo.aiob.ImportTaskVo;
import com.xinelu.manage.vo.labelfieldcontent.LabelFieldInfoContentVo;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Resource;

import com.xinelu.system.service.ISysDictTypeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @description: 百度智能外呼上传任务定时任务
 * @author: haown
 * @create: 2024-08-19 13:58
 **/
@Slf4j
@Component("UploadRobotPublishTask")
public class UploadRobotPublishTask {

    @Value("${aiob.callBackUrl}")
    private String callBackUrl;
    @Resource
    private SignPatientManageRouteNodeMapper signPatientManageRouteNodeMapper;
    @Resource
    private ISignPatientManageRouteNodeService signPatientManageRouteNodeService;
    @Resource
    private SignPatientManageRouteMapper signPatientManageRouteMapper;
    @Resource
    private SignPatientRecordMapper signPatientRecordMapper;
    @Resource
    private PatientVisitRecordMapper patientVisitRecordMapper;
    @Resource
    private ScriptInfoTaskInfoMapper scriptInfoTaskInfoMapper;
    @Resource
    private IAIOBService aiobService;
    @Resource
    private ScriptInfoMapper scriptInfoMapper;
    @Resource
    private PatientInfoMapper patientInfoMapper;
    @Resource
    private LabelFieldContentMapper labelFieldContentMapper;
    @Resource
    private RegexUtil regexUtil;
    @Resource
    private ISysDictTypeService iSysDictTypeService;
    @Resource
    private PatientInfoImportMainMapper patientInfoImportMainMapper;

    /**
     * @description 创建百度智能外呼任务并导入客户名单
     * @Author haown
     * @Date 2024-9-5 13:55
     * @Date 2024-12-11 重构批量执行
     */
    public void uploadRobotPublishTask() {
        log.info("开始执行百度智能外呼创建任务定时任务......");
        // 查找需要当天执行的AI打电话任务（问卷或电话外呼类型）
        SignPatientManageRouteNodeDto signPatientManageRouteNodeDto = new SignPatientManageRouteNodeDto();
        //signPatientManageRouteNodeDto.setTaskNodeType(TaskNodeTypeEnum.PHONE_OUTBOUND.getInfo());
        signPatientManageRouteNodeDto.setNodeExecuteStatus(NodeExecuteStatusEnum.UNEXECUTED.getInfo());
        signPatientManageRouteNodeDto.setPhoneDialMethod(PhoneDialMethodEnum.AI.getInfo());
        //只获取 任务执行类型为 批量执行的
        signPatientManageRouteNodeDto.setTaskExcuteType(TaskExcuteTypeEnum.BATCH_TASK.getInfo());
        //查询未拨打的
        signPatientManageRouteNodeDto.setDialStatus(DialStatusEnum.NODIALED.getInfo());

        List<SignPatientManageRouteNode> nodeList = signPatientManageRouteNodeMapper.selectSignPatientManageRouteNodeList(signPatientManageRouteNodeDto);

        List<SignPatientManageRouteNode> executeNodeList = new ArrayList<>();
        nodeList.forEach(node -> {

            LocalDateTime executeTime;
            if (Objects.nonNull(node.getNodePlanTime()) && org.apache.commons.lang3.StringUtils.isNotBlank(node.getNodePlanTime().toString())) {
                executeTime = node.getNodePlanTime();
            } else {
                SignPatientManageRoute signPatientManageRoute = signPatientManageRouteMapper.selectSignPatientManageRouteById(node.getManageRouteId());
                SignPatientRecord signPatientRecord = signPatientRecordMapper.selectByPrimaryKey(signPatientManageRoute.getSignPatientRecordId());
                PatientVisitRecord patientVisitRecord = patientVisitRecordMapper.selectPatientVisitRecordById(signPatientRecord.getPatientVisitRecordId());
                executeTime = signPatientManageRouteNodeService.getExecuteTime(node.getExecuteTime(), node.getRouteNodeName(), node.getRouteNodeDay(), patientVisitRecord);
            }
            //只处理 流水号不为空的
            if (node.getSn() != null &&
                    //精确到秒
                    node.getScriptInfoId() != null && (executeTime.isBefore(LocalDateTime.now()) || executeTime.isEqual(LocalDateTime.now()))) {
                    //精确到天
                    // node.getScriptInfoId() != null && (executeTime.toLocalDate().isBefore(LocalDate.now()) || executeTime.toLocalDate().isEqual(LocalDate.now()))) {
                executeNodeList.add(node);
            }
        });
        if (executeNodeList.isEmpty()) return;

        //1、最外层，按照导入流水号分组
        Map<String, List<SignPatientManageRouteNode>> routeNodeGroupListBySn =
                executeNodeList.stream().collect(Collectors.groupingBy(SignPatientManageRouteNode::getSn));

        // 开始遍历
        routeNodeGroupListBySn.keySet().forEach(sn -> {
            //2、次外层，按照话术ID分组
            Map<Long, List<SignPatientManageRouteNode>> routeNodeGroupListByScriptInfoId =
                    routeNodeGroupListBySn.get(sn).stream().collect(Collectors.groupingBy(SignPatientManageRouteNode::getScriptInfoId));
            //开始遍历，生成任务
            routeNodeGroupListByScriptInfoId.keySet().forEach(scriptInfoId -> {
                // 同一分组下的任务节点，配置属性 应该是 是相同的，所以取第0项节点 来使用
                SignPatientManageRouteNode nodeFirstTemp = routeNodeGroupListByScriptInfoId.get(scriptInfoId).get(0);
                //话术
                ScriptInfo scriptInfo = scriptInfoMapper.selectScriptInfoById(scriptInfoId);
                //拼接一个taskId，(格式:NodeId_ScriptInfoId_ManageRouteId，不用了）
                // String taskId = scriptInfoTaskInfoMapper.getByNodeId(Long.toString(nodeFirstTemp.getId()).concat("_")
                //                 .concat(Long.toString(nodeFirstTemp.getManageRouteId())).concat("_")
                //                 .concat(String.valueOf(nodeFirstTemp.getScriptInfoId()))
                //         , AiobTaskTypeContant.BATCHTASK);
                ScriptInfoTaskInfo scriptInfoTaskInfoQuery = new ScriptInfoTaskInfo();
                //同一流水号sn下所有任务id相同，所以以第一个节点的属性作为查询条件即可。
                // scriptInfoTaskInfoQuery.setSignPatientManageRouteId(nodeFirstTemp.getManageRouteId());
                // scriptInfoTaskInfoQuery.setScriptInfoId(nodeFirstTemp.getScriptInfoId());
                // scriptInfoTaskInfoQuery.setAiobTaskType(AiobTaskTypeContant.BATCHTASK);
                scriptInfoTaskInfoQuery.setSn(sn);
                String taskId = scriptInfoTaskInfoMapper.getByNodeId(scriptInfoTaskInfoQuery);
                if (StringUtils.isBlank(taskId)) {
                    Long aLong = patientInfoImportMainMapper.selectHospitalAgencyId(sn);
                    DialTime dialTime = patientInfoImportMainMapper.selectDialTimeById(aLong);
                    LocalTime localStartTime = null;
                    LocalTime localEndTime = null;
                    LocalTime dateStartTime;
                    LocalTime dateEndTime;
                    if (Objects.nonNull(dialTime)) {
                        localStartTime = LocalTime.parse(dialTime.getDialStartTime());
                        localEndTime = LocalTime.parse(dialTime.getDialEndTime());
                    } else {
                        localStartTime = LocalTime.parse("08:00");
                        localEndTime = LocalTime.parse("19:00");
                    }
                    List<SysDictData> sysDictDataList = iSysDictTypeService.selectDictDataByType(Constants.DIAL_TIME);
                    if (CollectionUtils.isEmpty(sysDictDataList) || sysDictDataList.size() != 2) {
                        dateStartTime = LocalTime.parse("08:00");
                        dateEndTime = LocalTime.parse("19:00");
                    } else {
                        dateStartTime = LocalTime.parse(sysDictDataList.get(0).getDictValue());
                        dateEndTime = LocalTime.parse(sysDictDataList.get(1).getDictValue());
                    }
                    if (dateStartTime.isAfter(localStartTime)) {
                        localStartTime = dateStartTime;
                    }
                    if (dateEndTime.isBefore(localEndTime)) {
                        localEndTime = dateEndTime;
                    }
                    // 没有任务则创建任务
                    if (ObjectUtils.isNotEmpty(scriptInfo)) {
                        log.info("创建任务......");
                        CreateTaskDto createTaskDto = new CreateTaskDto();

                        //临时重复测试用，
                        String taskName = "T_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + scriptInfo.getScriptName() + "(" + sn + ")";
                        log.info("任务名称：" + taskName);
                        createTaskDto.setTaskName(taskName);
                        // createTaskDto.setTaskName(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + scriptInfo.getScriptName() + "(" + nodeFirstTemp.getManageRouteId() + ")");
                        createTaskDto.setRobotId(scriptInfo.getRobotPublishId());
                        createTaskDto.setDialStartDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
                        createTaskDto.setDialEndDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
                        createTaskDto.setForbidDialDate(Arrays.asList(99));
                        createTaskDto.setRetryTimes(StringUtils.isBlank(nodeFirstTemp.getPhoneRedialTimes()) ? 0 : PhoneRedialTimesEnum.getValueByInfo(nodeFirstTemp.getPhoneRedialTimes()).getValue());
                        createTaskDto.setRetryInterval(nodeFirstTemp.getPhoneTimeInterval());
                        createTaskDto.setNumTypeFilterList(Arrays.asList(1, 2));
                        createTaskDto.setTaskDataCallback(true);
                        createTaskDto.setCallBackUrl(callBackUrl+ "/taskCallBack");
                        createTaskDto.setDialStartTime(localStartTime.format(DateTimeFormatter.ofPattern("HH:mm")));
                        createTaskDto.setDialEndTime(localEndTime.format(DateTimeFormatter.ofPattern("HH:mm")));
                        taskId = aiobService.createTask(createTaskDto);
                        // 开启任务
                        log.info("开启任务......");
                        aiobService.updateTaskStatus(taskId, 2);

                        String finalTaskId1 = taskId;
                        routeNodeGroupListByScriptInfoId.get(scriptInfoId).forEach(nodeForTask -> {
                            ScriptInfoTaskInfo scriptInfoTaskInfo = new ScriptInfoTaskInfo();
                            scriptInfoTaskInfo.setScriptInfoId(scriptInfoId);
                            scriptInfoTaskInfo.setTaskId(finalTaskId1);
                            scriptInfoTaskInfo.setRobotId(scriptInfo.getRobotPublishId());
                            scriptInfoTaskInfo.setCreateTime(LocalDateTime.now());
                            scriptInfoTaskInfo.setSn(sn);
                            scriptInfoTaskInfo.setSignPatientManageRouteNodeId(nodeForTask.getId());
                            scriptInfoTaskInfo.setSignPatientManageRouteId(nodeForTask.getManageRouteId());
                            scriptInfoTaskInfo.setAiobTaskType(AiobTaskTypeContant.BATCHTASK);
                            //进入拔打记录表（用于后续重拨处理等判断)----有时间再优化为批量插入
                            scriptInfoTaskInfoMapper.insertScriptInfoTaskInfo(scriptInfoTaskInfo);
                        });
                        //3、开始组装本任务下的客户变量
                        // 客户名单list
                        List<CustomerInfoDto> customerInfoList = new ArrayList<>();
                        //遍历最内层任务节点
                        routeNodeGroupListByScriptInfoId.get(scriptInfoId).forEach(node -> {
                            CustomerInfoDto customerInfoDto = new CustomerInfoDto();
                            customerInfoDto.setExtJson(node.getId() + "");
                            SignPatientManageRoute signPatientManageRoute = signPatientManageRouteMapper.selectSignPatientManageRouteById(node.getManageRouteId());
                            PatientInfo patientInfo = patientInfoMapper.selectPatientInfoById(signPatientManageRoute.getPatientId());
                            //校验手机号
                            if (org.apache.commons.lang3.StringUtils.isNotBlank(patientInfo.getPatientPhone())) {
                                if (regexUtil.regexPhone(patientInfo.getPatientPhone())) {
                                    customerInfoDto.setMobile(patientInfo.getPatientPhone());
                                    // 查询患者画像信息
                                    List<LabelFieldInfoContentVo> labelFieldContentList = labelFieldContentMapper.selectByPatientId(patientInfo.getId());
                                    // 处理变量
                                    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);
                                }
                            }
                        });
                        // 上传名单
                        log.info("任务导入客户名单......");
                        ImportTaskDto importTaskDto = new ImportTaskDto();
                        importTaskDto.setTaskId(taskId);
                        importTaskDto.setSecretType(2);
                        importTaskDto.setCustomerInfoList(customerInfoList);
                        List<ImportTaskVo> importTaskList = aiobService.importTask(importTaskDto);

                        //设置拨打状态
                        SignPatientManageRouteNode signPatientManageRouteNode_DialStatus = new SignPatientManageRouteNode();
                        // signPatientManageRouteNode_DialStatus.setManageRouteId(routeId);
                        signPatientManageRouteNode_DialStatus.setSn(sn);
                        signPatientManageRouteNode_DialStatus.setScriptInfoId(scriptInfoId);
                        signPatientManageRouteNode_DialStatus.setDialStatus(DialStatusEnum.DIALED.getInfo());
                        signPatientManageRouteNodeMapper.updateDialStatus(signPatientManageRouteNode_DialStatus);

                        String finalTaskId = taskId;
                        importTaskList.forEach(importTaskVo -> {
                            SignPatientManageRouteNode signPatientManageRouteNode = new SignPatientManageRouteNode();
                            // 名单导入成功后，sign_patient_manage_route_node表中设置taskId
                            if (importTaskVo.getStatus()) {
                                signPatientManageRouteNode.setTaskIdExt(finalTaskId);
                                signPatientManageRouteNode.setId(Long.valueOf(importTaskVo.getExtJson()));
                                signPatientManageRouteNodeMapper.updateSignPatientManageRouteNode(signPatientManageRouteNode);
                            }
                        });
                    }
                }
            });
        });
        // 根据机器人id查询智能外呼系统的任务id
        log.info("百度智能外呼创建任务定时任务执行完成......");
    }

    /**
     * @return null
     * @description 创建实时任务
     * @Author haown
     * @Date 2024-9-23 10:41
     */
    public void actualTimeTask() {
        log.info("开始执行百度智能外呼创建实时任务定时任务......");
        // 查找需要当天执行的AI打电话任务（问卷或电话外呼类型）
        SignPatientManageRouteNodeDto signPatientManageRouteNodeDto = new SignPatientManageRouteNodeDto();
        signPatientManageRouteNodeDto.setNodeExecuteStatus(NodeExecuteStatusEnum.UNEXECUTED.getInfo());
        signPatientManageRouteNodeDto.setPhoneDialMethod(PhoneDialMethodEnum.AI.getInfo());
        //只获取 任务执行类型为 单个执行的
        signPatientManageRouteNodeDto.setTaskExcuteType(TaskExcuteTypeEnum.ACTUAL_TIME_TASK.getInfo());
        //查询未拨打的
        signPatientManageRouteNodeDto.setDialStatus(DialStatusEnum.NODIALED.getInfo());

        List<SignPatientManageRouteNode> nodeList = signPatientManageRouteNodeMapper.selectSignPatientManageRouteNodeList(signPatientManageRouteNodeDto);
        List<SignPatientManageRouteNode> executeNodeList = new ArrayList<>();
        nodeList.forEach(node -> {
            LocalDateTime executeTime;
            //如果有计划执行时间，则直接获取
            if (node.getNodePlanTime() != null) {
                executeTime = node.getNodePlanTime();
            }
            // 否则 ，则根据诊后/院后 第几天 计算
            else {
                SignPatientManageRoute signPatientManageRoute = signPatientManageRouteMapper.selectSignPatientManageRouteById(node.getManageRouteId());
                SignPatientRecord signPatientRecord = signPatientRecordMapper.selectByPrimaryKey(signPatientManageRoute.getSignPatientRecordId());
                PatientVisitRecord patientVisitRecord = patientVisitRecordMapper.selectPatientVisitRecordById(signPatientRecord.getPatientVisitRecordId());
                executeTime = signPatientManageRouteNodeService.getExecuteTime(node.getExecuteTime(), node.getRouteNodeName(), node.getRouteNodeDay(), patientVisitRecord);
            }
            //精确到天
            // if (node.getScriptInfoId() != null && (executeTime.toLocalDate().isBefore(LocalDate.now()) || executeTime.toLocalDate().isEqual(LocalDate.now()))) {
            //精确到秒
            if (node.getScriptInfoId() != null && (executeTime.isBefore(LocalDateTime.now()) || executeTime.isEqual(LocalDateTime.now()))) {
                executeNodeList.add(node);
            }
        });

        // 查询需要重拨的任务
        ScriptInfoTaskInfo scriptInfoTaskInfo = new ScriptInfoTaskInfo();
        scriptInfoTaskInfo.setExecuteStatus(NodeExecuteStatusEnum.UNEXECUTED.getInfo());
        scriptInfoTaskInfo.setAiobTaskType(AiobTaskTypeContant.ACTUALTIMETASK);
        List<ScriptInfoTaskInfo> scriptInfoTaskInfoList = scriptInfoTaskInfoMapper.selectList(scriptInfoTaskInfo);
        scriptInfoTaskInfoList.forEach(taskInfo -> {
            SignPatientManageRouteNode node = signPatientManageRouteNodeMapper.selectSignPatientManageRouteNodeById(taskInfo.getSignPatientManageRouteNodeId());
            if (taskInfo.getExecuteTime().isBefore(LocalDateTime.now()) || taskInfo.getExecuteTime().isEqual(LocalDateTime.now())) {
                executeNodeList.add(node);
            }
        });
        if (CollectionUtils.isNotEmpty(executeNodeList)) {
            // 根据机器人id查询智能外呼系统的任务id
            executeNodeList.forEach(node -> {
                createTask(node);
            });
        }
        log.info("百度智能外呼创建实时任务定时任务执行完成......");
    }

    private void createTask(SignPatientManageRouteNode node) {
        ScriptInfo scriptInfo = scriptInfoMapper.selectScriptInfoById(node.getScriptInfoId());
        SignPatientManageRoute signPatientManageRoute = signPatientManageRouteMapper.selectSignPatientManageRouteById(node.getManageRouteId());
        PatientInfo patientInfo = patientInfoMapper.selectPatientInfoById(signPatientManageRoute.getPatientId());
        // 没有任务则创建任务
        if (ObjectUtils.isNotEmpty(scriptInfo) && org.apache.commons.lang3.StringUtils.isNotBlank(patientInfo.getPatientPhone()) && regexUtil.regexPhone(patientInfo.getPatientPhone())) {
            log.info("创建任务......");
            ActualTimeTaskDto actualTimeTaskDto = new ActualTimeTaskDto();
            actualTimeTaskDto.setRobotId(scriptInfo.getRobotPublishId());
            actualTimeTaskDto.setMobile(patientInfo.getPatientPhone());
            actualTimeTaskDto.setSecretType(2);
            actualTimeTaskDto.setStopDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 20:00:00");
            // 查询患者画像信息
            List<LabelFieldInfoContentVo> labelFieldContentList = labelFieldContentMapper.selectByPatientId(patientInfo.getId());
            // 处理变量
            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());
                });
            }
            actualTimeTaskDto.setDialogVar(jsonObject);
            actualTimeTaskDto.setCallBackUrl(callBackUrl);
            actualTimeTaskDto.setExtJson(node.getId() + "");
            aiobService.createActualTimeTask(actualTimeTaskDto);

            log.info("创建任务完成......");

            //设置拨打状态
            SignPatientManageRouteNode signPatientManageRouteNode_DialStatus = new SignPatientManageRouteNode();
            signPatientManageRouteNode_DialStatus.setId(node.getId());
            signPatientManageRouteNode_DialStatus.setDialStatus(DialStatusEnum.DIALED.getInfo());
            signPatientManageRouteNodeMapper.updateDialStatusByNodeId(signPatientManageRouteNode_DialStatus);
        }
    }
}
