package com.docus.server.message.busservice.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.docus.core.util.DateUtil;
import com.docus.core.util.Func;
import com.docus.infrastructure.core.exception.BaseException;
import com.docus.infrastructure.web.api.CommonResult;
import com.docus.infrastructure.web.api.ResultCode;
import com.docus.server.message.busservice.NkBusinessService;
import com.docus.server.message.config.CollectTaskConfig;
import com.docus.server.message.converters.NkWsRecordSubmitMessageConvert;
import com.docus.server.message.converters.ZqWsRecordSubmitMessageConvert;
import com.docus.server.message.dto.*;
import com.docus.server.message.entity.CqcPushConfig;
import com.docus.server.message.entity.TBasic;
import com.docus.server.message.feign.dto.CompensateTasRequest;
import com.docus.server.message.feign.dto.HospitalSubmitNodeLogAddDTO;
import com.docus.server.message.feign.enums.HospitalSubmitNodeEnum;
import com.docus.server.message.feign.service.CollectTaskService;
import com.docus.server.message.feign.service.HospitalSubmitNodeServiceApi;
import com.docus.server.message.feign.vo.ArchiveAndRecallPushVo;
import com.docus.server.message.mapper.CqcPushConfigMapper;
import com.docus.server.message.mapper.TBasicMapper;
import com.docus.server.message.validate.NkRecordSubmitValidate;
import lombok.extern.slf4j.Slf4j;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.ibatis.mapping.ParameterMode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @BelongsProject: docus-unified-message
 * @BelongsPackage: com.docus.server.message.busservice.impl
 * @Author: chierhao
 * @CreateTime: 2024-03-20  08:57
 * @Description: TODO
 * @Version: 1.0
 */
@Slf4j
@Service
public class NkBusinessServiceImpl implements NkBusinessService {

    @Resource
    private TBasicMapper tBasicMapper;

    @Autowired
    private CqcPushConfigMapper cqcPushConfigMapper;

    @Autowired
    private HospitalSubmitNodeServiceApi hospitalSubmitNodeServiceApi;

    @Resource
    private CollectTaskService collectTaskService;
    @Override
    public MessageResponse recordSubmitHandle(Message message) {
        try {
            CollectTaskConfig.TaskConfig taskConfig = CollectTaskConfig.getTaskConfig("WS_RECORD_SUBMIT");
            if (taskConfig == null || Func.isEmpty(taskConfig.getCollectorIds())) {
                throw new RuntimeException("任务配置未配置采集器id,WS_RECORD_SUBMIT");
            }
            NkRecordSubmitDTO dto = NkWsRecordSubmitMessageConvert.convert(message.getMessage());
            NkRecordSubmitValidate.verifyRecordSubmitDTO(dto);
            TbasicQrPreciseCondition condition = NkWsRecordSubmitMessageConvert.convert(dto);
            List<String> patientIds = tBasicMapper.getGznkPatientIdByPreciseConditions(condition);
            verifyPatientIds(patientIds);

            String submitDate = dto.getSubmitDate();
            tBasicMapper.insertOrUpdateDoctorSubmitTime(patientIds.get(0), Func.parseDate(submitDate, DateUtil.PATTERN_DATETIME));

            compensateTask("电子病历提交",patientIds, taskConfig.getCollectorIds());
            tBasicMapper.updateEmrSubmitState(patientIds.get(0), 1);

            String submitName = dto.getSubmitName();
            String submitNo = dto.getSubmitNo();
            // 添加提交记录
            HospitalSubmitNodeLogAddDTO nodeLogAddDTO = new HospitalSubmitNodeLogAddDTO();
            nodeLogAddDTO.setPatientId(patientIds.get(0));
            nodeLogAddDTO.setContent(new String[]{submitDate});
            nodeLogAddDTO.setSubmitNodeEnum(HospitalSubmitNodeEnum.EMR);
            nodeLogAddDTO.setCreater(submitName+"("+submitNo+")");
            nodeLogAddDTO.setCreaterName(submitName+"("+submitNo+")");
            hospitalSubmitNodeServiceApi.addLog(nodeLogAddDTO);

            //归档推送
            pushWebService(patientIds.get(0),dto);
            return new MessageResponse(ResultCode.SUCCESS.getCode(), success());
        } catch (BaseException baseException) {
            log.error(baseException.getMessage(), baseException);
            // 业务异常，不希望重试，直接消息返回错误
            MessageResponse response = new MessageResponse(ResultCode.FAILED.getCode(), fail(baseException.getMessage()));
            response.setRetry(0);
            return response;
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            // 不可知的错误，希望重试
            MessageResponse response = new MessageResponse(ResultCode.FAILED.getCode(), fail("系统错误"));
            response.setRetry(1);
            return response;
        }
    }
    private void verifyPatientIds(List<String> patientIds) {
        if (Func.isEmpty(patientIds)) {
            throw new BaseException("系统无此患者！");
        }
        if (patientIds.size() > 1) {
            throw new BaseException("系统中患者有多个,无法确认！");
        }
    }

    private void compensateTask(String source,List<String> patientIds, List<String> collectorIds) {
        log.info("{},补偿任务 patientIds:{} collectId:{}",source, patientIds, collectorIds);
        CompensateTasRequest dto = new CompensateTasRequest();
        dto.setPatientIds(patientIds);
        dto.setCollectorIds(collectorIds);
        dto.setPriority(3);
        CommonResult<String> result = collectTaskService.compensateTask(dto);
        log.info("{}，补偿任务结果：{}", source,Func.toJson(result));
    }

    @Async
    public void pushWebService(String patientId,NkRecordSubmitDTO dto){
        CqcPushConfig config = cqcPushConfigMapper.getCqcPushConfigByBusinessType("14");
        if(Func.isEmpty(config)){
            return;
        }

        TBasic tBasicInfo = tBasicMapper.getTBasicInfo(patientId);
        ArchiveAndRecallPushVo vo=new ArchiveAndRecallPushVo();
        vo.setInpatientNo(tBasicInfo.getInpatientNo());
        vo.setAdmissTimes(tBasicInfo.getAdmissTimes());
        vo.setName(tBasicInfo.getName());
        vo.setExternalId(tBasicInfo.getExternalId());
        vo.setAdmissDate(tBasicInfo.getAdmissDate());
        vo.setDisDate(tBasicInfo.getDisDate());
        vo.setDisDept(tBasicInfo.getDisDept());
        vo.setDisDeptName(tBasicInfo.getDisDeptName());
        vo.setArchiveTime(dto.getSubmitDate());
        vo.setControlUserName(dto.getSubmitNo());
        vo.setControlName(dto.getSubmitName());
        vo.setIsArchive(1);

        String wsParam = NkWsRecordSubmitMessageConvert.getPushXml(vo);
        //请求地址
        String wsUrl = config.getUrl();
        //命名空间
        String namespance = config.getNamespace();
        // 推送方法名
        String wsMethod = config.getMethod();
        //参数
        String parameterListStr = config.getParameterList();
        parameterListStr=String.format(parameterListStr,JSON.toJSONString(wsParam));

        List<Map<String,Object>> parameterList=new ArrayList<>();

        parameterList=JSON.parseObject(parameterListStr,new TypeReference<List<Map<String,Object>>>() {});

        List<Object> parameters = parameterList.stream().map(e -> e.get("parameter")).collect(Collectors.toList());
        log.info("推送入参: parameterList:{}",JSON.toJSONString(parameterList));


        //回调值
        String result = "";
        for(int i=0;i<3;i++){
            try {
                Thread.sleep(i*5*100);
            } catch (InterruptedException e) {
                log.error(e.getMessage(),e);
            }
            result = requestFunctionWebServiceCXF(wsUrl, namespance, wsMethod, parameters);

            log.info("得到的结果:" + result);
            if (result.contains("成功") || result.contains("success")) {
                break;
            }
        }
        log.info("召回归档推送 vo："+ JSON.toJSONString(vo)+" result： "+result);
    }

    public String requestFunctionWebServiceCXF(String url, String namespace, String method, List<Object> params) {
        String result;
        try {
            //创建动态客户端工厂 创建客户端
            JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
            Client client = dcf.createClient(url);
            //命名空间和方法
            QName name = new QName(namespace, method);
            Object[] opAddEntryArgs;
            opAddEntryArgs = params.toArray();
            Object[] objects = client.invoke(name, opAddEntryArgs);
            result = objects[0].toString();
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            result = e.getMessage();
        }
        return result;
    }

    private String success() {
        return "<Response>" +
                "<RetInfo>" +
                "<RetCode>0</RetCode>" +
                "<RetCon>成功</RetCon>" +
                "</RetInfo>" +
                "</Response>";
    }

    private String fail(String message) {
        return "<Response>" +
                "<RetInfo>" +
                "<RetCode>1</RetCode>" +
                "<RetCon>" + message + "</RetCon>" +
                "</RetInfo>" +
                "</Response>";
    }
}
