package com.docus.server.reportmanager.webservice;

import cn.hutool.core.util.StrUtil;
import com.docus.core.util.Func;
import com.docus.infrastructure.core.exception.BaseException;
import com.docus.infrastructure.core.utils.SpringUtil;
import com.docus.infrastructure.redis.service.IdService;
import com.docus.server.reportmanager.dto.BasicQrDto;
import com.docus.server.reportmanager.entity.AfCollectTask;
import com.docus.server.reportmanager.entity.AfReportDeleteLog;
import com.docus.server.reportmanager.mapper.CollectTaskMapper;
import com.docus.server.reportmanager.mapper.ScanAssortMapper;
import com.docus.server.reportmanager.mapper.TbasicMapper;
import com.docus.server.reportmanager.util.XmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.w3c.dom.Node;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 英德中医院报告管理服务接口
 *
 * @author YongBin Wen
 * @date 2024/1/3 16:11
 */
@Service("YdZyyReportManagerService")
@Slf4j
public class YingDeZyyReportManagerServiceImpl implements ReportManagerService {
    private final static String operator = "yingde-ws-delete";
    @Resource
    private CollectTaskMapper collectTaskMapper;
    @Resource
    private ScanAssortMapper scanAssortMapper;
    @Resource
    private IdService idService;
    @Resource
    private TbasicMapper tbasicMapper;

    @Override
    public String DeleteReport(String message) {

        log.info("英德中医报告管理，收到作废报告的信息：{}", message);
        try {
            AfReportDeleteLog deleteLog = insertDeleteLog(message);


            String inpatientNo = null;
            Integer admissTimes = null;
            String admissDateBegin = null;
            String admissDateEnd = null;
            String disDateBegin = null;
            String disDateEnd = null;
            String name = null;
            String idCard = null;
            String jzh = null;


            XmlUtil xmlUtil = XmlUtil.of(message);
            Node inpatientNoNode = xmlUtil.getNode("/Request/Msg/INPATIENT_NO");
            if (Func.isNotEmpty(inpatientNoNode)) {
                inpatientNo = inpatientNoNode.getTextContent();
            }
            Node admissionsNode = xmlUtil.getNode("/Request/Msg/ADMISSIONS");
            if (Func.isNotEmpty(admissionsNode)) {
                String admissions = admissionsNode.getTextContent();
                if (Func.isNotBlank(admissions)) {
                    admissTimes = Integer.parseInt(admissions);
                }
            }
            Node admissionDateNode = xmlUtil.getNode("/Request/Msg/ADMISSION_DATE");
            if (Func.isNotEmpty(admissionDateNode)) {
                String admissDate = admissionDateNode.getTextContent();
                if (Func.isNotBlank(admissDate)) {
                    Date parseAdmissDate = Func.parseDate(admissDate, "yyyy-MM-dd HH:mm:ss");
                    String formatAdmissDate = Func.formatDate(parseAdmissDate);
                    admissDateBegin = formatAdmissDate + " 00:00:00";
                    admissDateEnd = formatAdmissDate + " 23:59:59";
                }
            }
            Node disDateNode = xmlUtil.getNode("/Request/Msg/DIS_DATE");
            if (Func.isNotEmpty(disDateNode)) {
                String disDate = disDateNode.getTextContent();
                if (Func.isNotBlank(disDate)) {
                    Date parseDisDate = Func.parseDate(disDate, "yyyy-MM-dd HH:mm:ss");
                    String formatDisDate = Func.formatDate(parseDisDate);
                    disDateBegin = formatDisDate + " 00:00:00";
                    disDateEnd = formatDisDate + " 23:59:59";
                }
            }
            Node nameNode = xmlUtil.getNode("/Request/Msg/NAME");
            if (Func.isNotEmpty(nameNode)) {
                name = nameNode.getTextContent();
            }
            Node idCardNode = xmlUtil.getNode("/Request/Msg/ID_CARD");
            if (Func.isNotEmpty(idCardNode)) {
                idCard = idCardNode.getTextContent();
            }
            Node jzhNode = xmlUtil.getNode("/Request/Msg/JZH");
            if (Func.isNotEmpty(jzhNode)) {
                jzh = jzhNode.getTextContent();
            }

            BasicQrDto basicQrDto = new BasicQrDto();
            basicQrDto.setInpatientNo(inpatientNo);
            basicQrDto.setAdmissTimes(admissTimes);
            basicQrDto.setAdmissDateBegin(admissDateBegin);
            basicQrDto.setAdmissDateEnd(admissDateEnd);
            basicQrDto.setDisDateBegin(disDateBegin);
            basicQrDto.setDisDateEnd(disDateEnd);
            basicQrDto.setName(name);
            basicQrDto.setIdCard(idCard);
            basicQrDto.setJzh(jzh);

            String patientId = getPatientId(basicQrDto);
            deleteLog.setPatientId(patientId);
            scanAssortMapper.updateDleteLog(deleteLog);

            cancelReport(patientId, xmlUtil);
            return success();
        } catch (BaseException baseException) {
            log.error(baseException.getMessage(), baseException);
            return error(baseException.getMessage());
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            return error("系统内部错误，请联系开发人员");
        }
    }

    private void cancelReport(String patientId, XmlUtil xmlUtil) {
        String reportNo = null;
        String bcjlType = null;
        String bcjlDelete = null;
        String reportName = null;
        String reportSource = null;
        Node reportNoNode = xmlUtil.getNode("/Request/Msg/REPORT_NO");
        if (Func.isNotEmpty(reportNoNode)) {
            reportNo = reportNoNode.getTextContent();
        }
        // 当报告是病程记录或者术后病程记录时，此字段为必传 （1、病程记录2、术后病程记录）
        Node bcjlTypeNode = xmlUtil.getNode("/Request/Msg/BCJL_TYPE");
        if (Func.isNotEmpty(bcjlTypeNode)) {
            bcjlType = bcjlTypeNode.getTextContent();
        }
        Node bcjlDeleteNode = xmlUtil.getNode("/Request/Msg/BCJL_DELETE");
        if (Func.isNotEmpty(bcjlDeleteNode)) {
            bcjlDelete = bcjlDeleteNode.getTextContent();
        }


        Node reportNameNode = xmlUtil.getNode("/Request/Msg/CATALOG_NAME");
        if (Func.isNotEmpty(reportNameNode)) {
            reportName = reportNameNode.getTextContent();
        }
        // 报告来源类型，为空默认电子病历
        Node reportSourceNode = xmlUtil.getNode("/Request/Msg/REPORT_SOURCE");
        if (Func.isNotEmpty(reportSourceNode)) {
            reportSource = reportSourceNode.getTextContent();
        }

        if (Objects.isNull(reportNo) || Func.isBlank(reportNo)) {
            throw new BaseException("病历报告号不能为空！");
        }
        if (Objects.isNull(reportName) || Func.isBlank(reportName)) {
            throw new BaseException("病历报告名称不能为空！");
        }

        // 电子病历
        if (Func.isBlank(reportSource) || isEmrSource(reportSource)) {
            // 病程记录和术后病程记录
            final String bcjl = "1";
            final String shubcjl = "2";
            // 病程记录
            if (bcjl.equals(bcjlType)) {
                cancelBcjlEMRReport(patientId,bcjlDelete);
                return;
            }
            // 术后病程记录
            if (shubcjl.equals(bcjlType)) {
                cancelShuBcjlEMRReport(patientId,bcjlDelete);
                return;
            }
            // 体温单
            if (isTiWenDan(reportName)) {
                cancelTiWenDanEMRReport(patientId, reportName);
                return;
            }
            // 医嘱
            if (isYiZhu(reportName)) {
                cancelYiZhuEMRReport(patientId, reportName);
                return;
            }
            // 会诊申请
            if (isHuiZhen(reportName)) {
                cancelHuiZhenEMRReport(patientId, reportName);
                return;
            }
            // 普通的电子病历
            cancelNormalEMRReport(patientId, reportNo);
            return;
        }

        // 其他来源类型
        if (isOtherSource(reportSource)) {
            log.warn("该来源：{} 未实现功能!", reportSource);
        }
    }

    private void cancelNormalEMRReport(String patientId, String reportNo) {
        AfCollectTask task = new AfCollectTask();
        task.setPatientId(patientId);
        task.setC7(reportNo);
        task.setSysflag("2");
        List<AfCollectTask> tasks = collectTaskMapper.getTasks(task);
        if (Func.isEmpty(tasks)) {
            return;
        }
        List<Long> fileIds = tasks.stream().map(AfCollectTask::getAfArchiveDetailId).collect(Collectors.toList());
        List<Long> taskIds = tasks.stream().map(AfCollectTask::getId).collect(Collectors.toList());
        scanAssortMapper.cancel(fileIds);
        // 任务移动作废表，删除任务
        moveTaskAndDel(taskIds);
    }

    private void cancelHuiZhenEMRReport(String patientId, String reportName) {
        AfCollectTask task = new AfCollectTask();
        task.setPatientId(patientId);
        task.setC6(reportName);
        task.setSysflag("12");
        List<AfCollectTask> tasks = collectTaskMapper.getTasks(task);
        if (Func.isEmpty(tasks)) {
            return;
        }
        List<Long> taskIds = tasks.stream().map(AfCollectTask::getId).collect(Collectors.toList());
        List<String> serialNum = tasks.stream().map(t -> patientId + t.getC6()).collect(Collectors.toList());
        scanAssortMapper.cancelBySerialNum(serialNum, patientId, "-2");
        collectTaskMapper.cancel(taskIds);
    }

    private void cancelYiZhuEMRReport(String patientId, String reportName) {
        AfCollectTask task = new AfCollectTask();
        task.setPatientId(patientId);
        task.setC6(reportName);
        task.setSysflag("12");
        List<AfCollectTask> tasks = collectTaskMapper.getTasks(task);
        if (Func.isEmpty(tasks)) {
            return;
        }
        List<Long> taskIds = tasks.stream().map(AfCollectTask::getId).collect(Collectors.toList());
        List<String> serialNum = tasks.stream().map(t -> patientId + t.getC6()).collect(Collectors.toList());
        scanAssortMapper.cancelBySerialNum(serialNum, patientId, "-2");
        collectTaskMapper.cancel(taskIds);
    }

    private void cancelTiWenDanEMRReport(String patientId, String reportName) {
        AfCollectTask task = new AfCollectTask();
        task.setPatientId(patientId);
        task.setC6(reportName);
        task.setSysflag("12");
        List<AfCollectTask> tasks = collectTaskMapper.getTasks(task);
        if (Func.isEmpty(tasks)) {
            return;
        }
        List<Long> taskIds = tasks.stream().map(AfCollectTask::getId).collect(Collectors.toList());
        List<String> serialNum = tasks.stream().map(t -> patientId + t.getC6()).collect(Collectors.toList());
        scanAssortMapper.cancelBySerialNum(serialNum, patientId, "-2");
        collectTaskMapper.cancel(taskIds);
    }


    /**
     * 作废病程记录报告
     *
     * @param patientId 病案主键
     */
    private void cancelBcjlEMRReport(String patientId,String delete) {
        AfCollectTask task = new AfCollectTask();
        task.setPatientId(patientId);
        task.setC6("病程记录");
        task.setSysflag("2");
        List<AfCollectTask> tasks = collectTaskMapper.getTasks(task);
        if (Func.isEmpty(tasks)) {
            return;
        }
        List<Long> fileIds = tasks.stream().map(AfCollectTask::getAfArchiveDetailId).collect(Collectors.toList());
        List<Long> taskIds = tasks.stream().map(AfCollectTask::getId).collect(Collectors.toList());
        scanAssortMapper.cancel(fileIds);
        if("1".equals(delete)){
            moveTaskAndDel(taskIds);
        }else {
            updateTaskForRecollect(taskIds);
        }
    }


    /**
     * 作废术后病程记录报告
     *
     * @param patientId 病案主键
     */
    private void cancelShuBcjlEMRReport(String patientId,String delete) {
        AfCollectTask task = new AfCollectTask();
        task.setPatientId(patientId);
        task.setC6("术后病程记录");
        task.setSysflag("2");
        List<AfCollectTask> tasks = collectTaskMapper.getTasks(task);
        if (Func.isEmpty(tasks)) {
            return;
        }
        List<Long> fileIds = tasks.stream().map(AfCollectTask::getAfArchiveDetailId).collect(Collectors.toList());
        List<Long> taskIds = tasks.stream().map(AfCollectTask::getId).collect(Collectors.toList());
        scanAssortMapper.cancel(fileIds);
        if("1".equals(delete)){
            moveTaskAndDel(taskIds);
        }else {
            updateTaskForRecollect(taskIds);
        }
    }

    /**
     * 是否会诊申请
     */
    private boolean isHuiZhen(String reportName) {
        return reportName.contains("会诊申请");
    }

    /**
     * 是否体温单
     */
    private boolean isTiWenDan(String reportName) {
        return reportName.contains("体温单");
    }

    /**
     * 是否医嘱
     */
    private boolean isYiZhu(String reportName) {
        return reportName.contains("长期医嘱") ||
                reportName.contains("中药医嘱") ||
                reportName.contains("临时医嘱");
    }

    private boolean isOtherSource(String reportSource) {
        return true;
    }

    private boolean isEmrSource(String reportSource) {
        return true;
    }

    private String getPatientId(BasicQrDto basicQrDto) {
        List<String> patientIds = tbasicMapper.getPatientIds(basicQrDto, 0, 10);
        if (Func.isEmpty(patientIds)) {
            throw new BaseException("系统中无此患者，请确认患者信息！");
        }
        if (patientIds.size() > 1) {
            throw new BaseException("系统中找到多条患者信息，请确认患者信息！");
        }
        return patientIds.get(0);
    }

    private AfReportDeleteLog insertDeleteLog(String message) {
        Date now = new Date();
        long id = idService.getDateSeq();
        AfReportDeleteLog reportDeleteLog = new AfReportDeleteLog();
        reportDeleteLog.setId(id);
        reportDeleteLog.setPatientId("");
        reportDeleteLog.setType(operator);
        reportDeleteLog.setDeleteContent(message);
        reportDeleteLog.setCreateTime(now);
        reportDeleteLog.setUpdateTime(now);
        scanAssortMapper.insertDeleteLog(reportDeleteLog);
        return reportDeleteLog;
    }

    /**
     * 更新任务信息，重新采集
     */
    private void moveTaskAndDel(List<Long> taskIds) {
        collectTaskMapper.moveCancel(taskIds);
        collectTaskMapper.del(taskIds);
    }

    /**
     * 更新任务信息，重新采集
     */
    private void updateTaskForRecollect(List<Long> taskIds) {
        String collectionState = collectTaskMapper.getCollectionState();
        String state = "0";
        if (StrUtil.isNotBlank(collectionState)) {
            state = collectionState;
        }
        collectTaskMapper.updateTaskForRecollect(taskIds, operator, state);
    }

    /**
     * 作废电生理的报告，电生理采集来源id为 13
     *
     * @param reportNo 报告唯一号
     * @date 2024/1/3 17:19
     * @author YongBin Wen
     */
    private void cancelReport(String reportNo) {
        final String sysFlag = "13";
        AfCollectTask task = new AfCollectTask();
        task.setC1(reportNo);
        task.setSysflag(sysFlag);
        List<AfCollectTask> tasks = collectTaskMapper.getTasks(task);
        if (Func.isEmpty(tasks)) {
            throw new BaseException("无纸化系统没有可作废的电生理报告任务:" + reportNo);
        }
        ArrayList<Long> taskIds = new ArrayList<>();
        ArrayList<Long> scanAssortIds = new ArrayList<>();
        for (AfCollectTask collectTask : tasks) {
            taskIds.add(collectTask.getId());
            List<Long> scanAssortIdsByTask = scanAssortMapper.getIdByPatientTask(collectTask.getPatientId(), collectTask.getId());
            scanAssortIds.addAll(scanAssortIdsByTask);
        }
        YingDeZyyReportManagerServiceImpl service = SpringUtil.getBean(YingDeZyyReportManagerServiceImpl.class);
        service.cancelReportTaskAndFile(taskIds, scanAssortIds);
    }


    @Transactional(rollbackFor = Exception.class)
    public void cancelReportTaskAndFile(List<Long> taskIds, List<Long> scanAssortIds) {
        if (Func.isNotEmpty(taskIds)) {
            collectTaskMapper.cancel(taskIds);
        }
        if (Func.isNotEmpty(scanAssortIds)) {
            scanAssortMapper.cancel(scanAssortIds);
        }
    }

    private String error(String msg) {
        return "<Response>\n" +
                "    <RetInfo>\n" +
                "        <RetCode>1</RetCode>\n" +
                "        <RetCon>" + msg + "</RetCon>\n" +
                "    </RetInfo>\n" +
                "</Response>";
    }

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