package com.lantone.qc.trans.ywzxyy;

import com.google.common.collect.Lists;
import com.lantone.qc.dbanaly.util.KernelConstants;
import com.lantone.qc.dbanaly.util.SpecialStorageUtil;
import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
import com.lantone.qc.pub.model.doc.operation.OperationDoc;
import com.lantone.qc.pub.model.doc.operation.OperationRecordDoc;
import com.lantone.qc.pub.model.doc.operation.PreoperativeDiscussionDoc;
import com.lantone.qc.pub.model.doc.ward.AttendingDoctorWardDoc;
import com.lantone.qc.pub.model.doc.ward.DirectorDoctorWardDoc;
import com.lantone.qc.pub.model.doc.ward.GeneralDoctorWardDoc;
import com.lantone.qc.pub.model.vo.MedrecVo;
import com.lantone.qc.pub.util.FastJsonUtils;
import com.lantone.qc.pub.util.SpringContextUtil;
import com.lantone.qc.pub.util.StringUtil;
import com.lantone.qc.trans.ModelDocTrans;
import com.lantone.qc.trans.comsis.OrdinaryAssistant;
import com.lantone.qc.trans.ywzxyy.util.YwzxyyThreeLevelWardXmlAnalysis;
import com.lantone.qc.trans.ywzxyy.util.YwzxyyXmlAnalysis;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Description: 查房记录文档生成
 * @author: rengb
 * @time: 2020/3/17 13:27
 */
@Setter
@Slf4j
public class YwzxyyThreeLevelWardDocTrans extends ModelDocTrans {
    private List<OperationDoc> operationDocs;

    @Override
    public List<ThreeLevelWardDoc> extract(MedrecVo medrecVo) {
        List<ThreeLevelWardDoc> retList = Lists.newArrayList();
        ThreeLevelWardDoc threeLevelWardDoc = new ThreeLevelWardDoc();
        List<Map<String, Object>> contentMaps = (List) medrecVo.getContent().get("content");
        contentMaps.forEach(contentMap -> {
            try {
                classifyThreeLevelWardDoc(threeLevelWardDoc, contentMap);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        });
        retList.add(threeLevelWardDoc);
        return retList;
    }

    private void classifyThreeLevelWardDoc(ThreeLevelWardDoc result, Map<String, Object> contentMap) {
        String content = contentMap.get("xmlText").toString();
        Map<String, String> structureMap = null;
        if (contentMap.get("isParsed") != null && "1".equals(contentMap.get("isParsed").toString())) {
            structureMap = (Map) FastJsonUtils.getJsonToMap(content);
        } else {
            String recTitle = contentMap.get("recTitle").toString();
            String recTypeId = contentMap.get("recTypeId").toString();
            YwzxyyXmlAnalysis ywzxyyXmlAnalysis = new YwzxyyThreeLevelWardXmlAnalysis();
            Map<String, String> sourceMap = ywzxyyXmlAnalysis.analysis(content, recTitle, recTypeId);
            if (MapUtils.isNotEmpty(sourceMap)) {
                structureMap = OrdinaryAssistant.mapKeyContrast(sourceMap, keyContrasts, "4");
                structureMap.put("记录编号", contentMap.get("recId").toString());
                structureMap.put("病历号", contentMap.get("behospitalCode") == null ? null : contentMap.get("behospitalCode").toString());
            }
        }
        if (MapUtils.isEmpty(structureMap)) {
            return;
        }
        if (StringUtils.isEmpty(structureMap.get("查房日期"))) {
            return;
        }
        //不能简单的标准转化，如果有查房标题，优先使用
        if (StringUtils.isEmpty(structureMap.get("查房标题")) && StringUtils.isNotEmpty(structureMap.get("查房备注"))) {
            structureMap.put("查房标题", structureMap.get("查房备注"));
        }
        if (StringUtils.isEmpty(structureMap.get("查房标题")) && StringUtils.isNotEmpty(structureMap.get("查房类别"))) {
            structureMap.put("查房标题", structureMap.get("查房类别"));
        }
        if (StringUtils.isEmpty(structureMap.get("查房标题")) && StringUtils.isNotEmpty(structureMap.get("上级查房医生职称"))) {
            structureMap.put("查房标题", structureMap.get("上级查房医生职称"));
        }
        //总的查房记录 汇总
        ThreeLevelWardDoc allDoctorWradDoc = new ThreeLevelWardDoc();
        allDoctorWradDoc.setText(structureMap.get("病情记录"));
        allDoctorWradDoc.setStructureMap(structureMap);
        allDoctorWradDoc.setPageData((Map) structureMap);
        result.addAllDoctorWradDoc(allDoctorWradDoc);

        //主任医师查房
        DirectorDoctorWardDoc directorDoctorWardDoc = findDirectorDoctorWardDoc(structureMap);
        if (directorDoctorWardDoc != null) {
            result.addDirectorDoctorWardDoc(directorDoctorWardDoc);
        }
        //主治医师查房
        AttendingDoctorWardDoc attendingDoctorWardDoc = findAttendingDoctorWardDoc(structureMap);
        if (attendingDoctorWardDoc != null) {
            result.addAttendingDoctorWardDoc(attendingDoctorWardDoc);
        }
        //普通医师查房
        if (directorDoctorWardDoc == null && attendingDoctorWardDoc == null) {
            GeneralDoctorWardDoc generalDoctorWardDoc = new GeneralDoctorWardDoc();
            generalDoctorWardDoc.setText(structureMap.get("病情记录"));
            generalDoctorWardDoc.setStructureMap(structureMap);
            generalDoctorWardDoc.setPageData((Map) structureMap);
            result.addGeneralDoctorWardDoc(generalDoctorWardDoc);
        }
    }

    /**
     * 主任医师查房
     *
     * @param structureMap
     */
    private DirectorDoctorWardDoc findDirectorDoctorWardDoc(Map<String, String> structureMap) {
        String title = structureMap.get("查房标题");
        String recordDateStr = structureMap.get("查房日期");
        String chiefSurgeon = structureMap.get("主刀医师");
        Date recordDate = StringUtil.parseDateTime(recordDateStr);
        DirectorDoctorWardDoc directorDoctorWardDoc = null;
        if (StringUtils.isNotEmpty(title)) {
            if (title.contains("主刀")) {
                String doctorTitle = getDoctorTitle(chiefSurgeon, operationDocs, recordDate, "主刀医师");
                title = title.replace("主刀", doctorTitle);
            } else if (title.contains("一助")) {
                String doctorTitle = getDoctorTitle(chiefSurgeon, operationDocs, recordDate, "一助");
                title = title.replace("一助", doctorTitle);
            }
            if (StringUtils.isNotEmpty(subTitle(title)) && subTitle(title).contains("主任")) {    //标题有代字)
                directorDoctorWardDoc = new DirectorDoctorWardDoc();
                directorDoctorWardDoc.setText(structureMap.get("病情记录"));
                directorDoctorWardDoc.setStructureMap(structureMap);
                directorDoctorWardDoc.setPageData((Map) structureMap);
            }
        }
        return directorDoctorWardDoc;
    }

    /**
     * 主治医师查房
     *
     * @param structureMap
     */
    private AttendingDoctorWardDoc findAttendingDoctorWardDoc(Map<String, String> structureMap) {
        String title = structureMap.get("查房标题");
        String recordDateStr = structureMap.get("查房日期");
        String chiefSurgeon = structureMap.get("主刀医师");
        Date recordDate = StringUtil.parseDateTime(recordDateStr);
        AttendingDoctorWardDoc attendingDoctorWardDoc = null;
        if (StringUtils.isNotEmpty(title)) {
            if (title.contains("主刀")) {
                String doctorTitle = getDoctorTitle(chiefSurgeon, operationDocs, recordDate, "主刀医师");
                title = title.replace("主刀", doctorTitle);
            } else if (title.contains("一助")) {
                String doctorTitle = getDoctorTitle(chiefSurgeon, operationDocs, recordDate, "一助");
                title = title.replace("一助", doctorTitle);
            }
            if (StringUtils.isNotEmpty(subTitle(title)) && subTitle(title).contains("主治")) {    //标题有代字)
                attendingDoctorWardDoc = new AttendingDoctorWardDoc();
                attendingDoctorWardDoc.setText(structureMap.get("病情记录"));
                attendingDoctorWardDoc.setStructureMap(structureMap);
                attendingDoctorWardDoc.setPageData((Map) structureMap);
            }
        }
        return attendingDoctorWardDoc;
    }

    private List<String> keyContrasts = Lists.newArrayList(
            "病历记录时间=查房日期",
            "原始文本=病情记录",
            "病历记录标题=查房标题",
            "记录医师=记录医生"
    );

    public static String subTitle(String srcText) {
        String title = "";
        if (StringUtil.isNotBlank(srcText)) {
            //标题不包含代字，直接返回原标题
            if (!srcText.contains("代")) {
                return srcText;
            }
            //有携、兼字时，取携、兼字之前部分
            if (srcText.contains("携")) {
                title += srcText.substring(0, srcText.indexOf("携"));
            } else if (srcText.contains("兼")) {
                title += srcText.substring(0, srcText.indexOf("兼"));
            }
            //有代字时，取代字之后部分
            if (srcText.contains("代") && srcText.indexOf("代") != srcText.length() - 1) {
                title += srcText.substring(srcText.lastIndexOf("代") + 1);
            } else {
                return srcText;
            }
        }
        return title;
    }

    /**
     * 获取主刀医师/一助职称(取距离查房记录时间最近的一次手术记录)
     *
     * @param operationDocs
     * @return
     */
    public static String getDoctorTitle(String chiefSurgeonFromWard, List<OperationDoc> operationDocs, Date recordDate, String findTitle) {
        String title = "";
        SpecialStorageUtil specialStorageUtil = SpringContextUtil.getBean("specialStorageUtil");
        Map<String, Object> surgeon = specialStorageUtil.getJsonStringValue(KernelConstants.HOSPITAL_DOCTOR_MAP);
        if (surgeon == null) {
            return title;
        }
        //如果查房记录中有主刀医师姓名，直接用这个姓名获取对应职称
        if (StringUtil.isNotBlank(chiefSurgeonFromWard)) {
            Map<String, String> doctor = (Map) surgeon.get(chiefSurgeonFromWard);
            if (doctor != null) {
                title = doctor.get("professor");
                if (StringUtil.isNotBlank(title)) {
                    return title;
                }
            }
        }

        //只有术前小结，没有手术记录情况下，直接取术前小结的医师姓名
        long operationCount = operationDocs.stream().map(OperationDoc::getOperationRecordDoc).filter(Objects::nonNull).count();
        long preoperativeCount = operationDocs.stream().map(OperationDoc::getPreoperativeDiscussionDoc).filter(Objects::nonNull).count();
        if (operationCount == 0 && preoperativeCount > 0) {
            long timeDiff = 0L;
            List<PreoperativeDiscussionDoc> preoperativeDoc = operationDocs.stream().map(OperationDoc::getPreoperativeDiscussionDoc).filter(Objects::nonNull).collect(Collectors.toList());
            for (PreoperativeDiscussionDoc doc : preoperativeDoc) {
                Map<String, String> structureMap = doc.getStructureMap();
                String chiefSurgeon = structureMap.get(findTitle + "签名");
                String operatorEndDateStr = structureMap.get("主刀医师签字时间");
                if (StringUtil.isBlank(chiefSurgeon) || StringUtil.isBlank(operatorEndDateStr)) {
                    continue;
                }
                Map<String, String> doctor = (Map) surgeon.get(chiefSurgeon);
                if (doctor != null) {
                    String professor = doctor.get("professor");
                    Date operatorEndDate = StringUtil.parseDateTime(operatorEndDateStr);
                    if (operatorEndDate != null) {
                        long timeDifference = timeDifference(operatorEndDate, recordDate);
                        if (timeDifference == 0) {
                            continue;
                        }
                        if (timeDiff == 0 || timeDiff > timeDifference) {
                            /* 取距离此次主刀医师查房最近的一次术前讨论时间 */
                            timeDiff = timeDifference;
                            title = professor;
                        }
                    }
                }
            }
            if (StringUtil.isNotBlank(title)) {
                return title;
            }
        }

        /* 用于存放手术结束时间距离查房时间最近的一次时间差 */
        long timeDiff = 0L;
        for (
                OperationDoc operationDoc : operationDocs) {
            OperationRecordDoc operationRecordDoc = operationDoc.getOperationRecordDoc();
            if (operationRecordDoc == null) {
                continue;
            }
            Map<String, String> structureMap = operationRecordDoc.getStructureMap();
            String chiefSurgeon = structureMap.get(findTitle);
            String operatorEndDateStr = structureMap.get("手术结束时间");

            if (StringUtil.isBlank(chiefSurgeon) || StringUtil.isBlank(operatorEndDateStr)) {
                continue;
            }
            Map<String, String> doctor = (Map) surgeon.get(chiefSurgeon);
            if (doctor != null) {
                String professor = doctor.get("professor");
                Date operatorEndDate = StringUtil.parseDateTime(operatorEndDateStr);
                if (operatorEndDate != null) {
                    long timeDifference = timeDifference(operatorEndDate, recordDate);
                    if (timeDifference == 0) {
                        continue;
                    }
                    if (timeDiff == 0 || timeDiff > timeDifference) {
                        /* 取距离此次主刀医师查房最近的一次手术时间 */
                        timeDiff = timeDifference;
                        title = professor;
                    }
                }
            }
        }
        return title;
    }

    public static long timeDifference(Date firstDate, Date secondDate) {
        long timeDifference = 0L;
        if (firstDate == null || secondDate == null) {
            return timeDifference;
        }
        boolean flag = false;
        if (firstDate.before(secondDate)) {
            flag = true;
        }
        Calendar calendarS = Calendar.getInstance();
        Calendar calendarE = Calendar.getInstance();
        long timeS, timeE;
        try {
            calendarS.setTime(firstDate);
            calendarE.setTime(secondDate);

            timeS = calendarS.getTimeInMillis();
            timeE = calendarE.getTimeInMillis();

            if (flag) {
                timeDifference = (timeE - timeS) / (1000 * 60);
            } else {
                timeDifference = (timeS - timeE) / (1000 * 60);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return timeDifference;
    }

}