package thyyxxk.webserver.service.examinations;

import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import thyyxxk.webserver.config.exception.BizException;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.dao.his.examinations.InspectionsDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.examinations.inspections.InspectionsIndex;
import thyyxxk.webserver.entity.examinations.inspections.QueryInspectionParam;
import thyyxxk.webserver.entity.examinations.inspections.detail.*;
import thyyxxk.webserver.entity.examinations.inspections.request.PatType;
import thyyxxk.webserver.entity.examinations.inspections.request.ReportDetailInquiry;
import thyyxxk.webserver.entity.examinations.inspections.request.ReportIndexInquiry;
import thyyxxk.webserver.entity.examinations.inspections.response.TestReport;
import thyyxxk.webserver.factory.electro.ElectroService;
import thyyxxk.webserver.factory.electro.model.ElectroIndex;
import thyyxxk.webserver.factory.examreport.ExamReportService;
import thyyxxk.webserver.factory.examreport.model.ExamDetailResponse;
import thyyxxk.webserver.factory.examreport.model.ExamIndexRequest;
import thyyxxk.webserver.factory.examreport.model.ExamIndexResponse;
import thyyxxk.webserver.factory.pathology.PathologyService;
import thyyxxk.webserver.factory.pathology.model.PathologyIndex;
import thyyxxk.webserver.service.examinations.lis.PushService;
import thyyxxk.webserver.service.externalhttp.ThmzSystem;
import thyyxxk.webserver.utils.*;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

/**
 * @author dj
 */
@Service
@Slf4j
public class InspectionsService {
    private final InspectionsDao dao;
    private final ThmzSystem thmz;
    private static final String ADICON_TOKEN = "Iou928g32dhs6FDs#!jd(dd$jdHH9hye";
    private static final String UNDEFINED = "undefined";
    private static final String SUCCESS = "1";
    private static final String ERROR = "0";
    @Value("${thmz-api-url}")
    private String thmzApiUrl;

    @Autowired
    public InspectionsService(InspectionsDao dao, ThmzSystem thmz) {
        this.dao = dao;
        this.thmz = thmz;
    }

    public ResultVo<List<InspectionsIndex>> queryInspectionsIndex(QueryInspectionParam param) {
        if (param.getType() == 0) {
            Map<String, Object> parent = thmz.getParentIdByPatientId(thmzApiUrl, param.getContent());
            if ((int) parent.get("code") == 0) {
                List<Map<String, String>> list = FilterUtil.cast(parent.get("data"));
                param.setContent(list.get(0).get("parentPatientId"));
            }
        }
        String message = "<message>" + "<PATIENT_TYPE>" + param.getType() + "</PATIENT_TYPE>" + "<PTNT_NO>" + param.getContent() + "</PTNT_NO>" + "<START_TIME>" + DateUtil.formatDate(param.getStart()) + "</START_TIME>" + "<END_TIME>" + DateUtil.formatDate(param.getEnd()) + "</END_TIME>" + "</message>";
        String xml = new PushService().getPushServiceSoap().getLabReportIndex(message);
        return analyzeReportIndex(xml);
    }

    public ResultVo<InspectionDetail> queryInspectionDetail(String orderId) {
        if (orderId == null || orderId.trim().isEmpty() || UNDEFINED.equals(orderId.trim())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "报告ID不能为空！");
        }
        String message = "<message><ORDR_ID>" + orderId + "</ORDR_ID></message>";
        String xml = new PushService().getPushServiceSoap().getLabReport(message);
        return analyzeReportDetail(xml);
    }

    private Element getReturnElement(String xml) {
        try {
            Document document = DocumentHelper.parseText(xml);
            Element root = document.getRootElement();
            return root.element("return");
        } catch (DocumentException e) {
            log.error("解析检验报告返回内容出错", e);
        }
        return null;
    }

    private ResultVo<List<InspectionsIndex>> analyzeReportIndex(String xml) {
        Element retEle = getReturnElement(xml);
        if (retEle == null) {
            return null;
        }
        Element codeEl = retEle.element("Code");
        String code = codeEl.getStringValue();
        if (SUCCESS.equals(code)) {
            List<InspectionsIndex> list = new ArrayList<>();
            Element resEl = retEle.element("Result");
            List<Element> reports = FilterUtil.cast(resEl.elements("ReportList"));
            reports.forEach(item -> {
                InspectionsIndex pojo = new InspectionsIndex();
                Field[] fields = pojo.getClass().getDeclaredFields();
                for (Field field : fields) {
                    try {
                        field.setAccessible(true);
                        String name = field.getName();
                        Method m = pojo.getClass().getMethod("set" + name, String.class);
                        m.invoke(pojo, item.elementTextTrim(name));
                    } catch (Exception e) {
                        log.error("解析检验报告列表出错", e);
                    }
                }
                list.add(pojo);
            });
            return ResultVoUtil.success(list);
        } else {
            Element errorMsgEl = retEle.element("ErrorMsg");
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, errorMsgEl.getStringValue());
        }
    }

    private ResultVo<InspectionDetail> analyzeReportDetail(String xml) {
        Element retEle = getReturnElement(xml);
        if (retEle == null) {
            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "结果集为空！");
        }
        String code = retEle.elementTextTrim("Code");
        if (ERROR.equals(code)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, retEle.elementTextTrim("ErrorMsg"));
        }
        InspectionDetail detail = new InspectionDetail();
        Element reportListEle = retEle.element("Result").element("ReportList");
        InspectionHeader header = new InspectionHeader();
        detail.setInspectionHeader((InspectionHeader) reflect(header, reportListEle.element("ReportHeader")));
        List<InspectionItem> inspectionItems = new ArrayList<>();
        List<Element> reportItemElements = FilterUtil.cast(reportListEle.elements("ReportItem"));
        reportItemElements.forEach(reportItemElement -> {
            InspectionItem inspectionItem = new InspectionItem();
            reflect(inspectionItem, reportItemElement);
            List<Element> bacteriaResultElements = FilterUtil.cast(reportItemElement.elements("BacteriaResult"));
            if (!bacteriaResultElements.isEmpty()) {
                List<BacteriaResult> bacteriaResults = new ArrayList<>();
                bacteriaResultElements.forEach(bacterialResultElement -> {
                    BacteriaResult bacteriaResult = new BacteriaResult();
                    reflect(bacteriaResult, bacterialResultElement);
                    List<Element> antibioticResultElements = FilterUtil.cast(bacterialResultElement.elements("AntibioticResult"));
                    if (!antibioticResultElements.isEmpty()) {
                        List<AntibioticResult> antibioticResults = new ArrayList<>();
                        antibioticResultElements.forEach(antibioticResultElement -> {
                            AntibioticResult antibioticResult = new AntibioticResult();
                            antibioticResults.add((AntibioticResult) reflect(antibioticResult, antibioticResultElement));
                        });
                        bacteriaResult.setAntibioticResults(antibioticResults);
                    }
                    if (StringUtil.notBlank(bacteriaResult.getBAC_ID())) {
                        bacteriaResults.add(bacteriaResult);
                    }
                });
                inspectionItem.setBacteriaResults(bacteriaResults);
            }
            if (StringUtil.notBlank(inspectionItem.getITM_VALUE()) || StringUtil.notBlank(inspectionItem.getITM_STR_VALUE()) || inspectionItem.getBacteriaResults().size() > 0) {
                inspectionItems.add(inspectionItem);
            }
        });
        detail.setInspectionItems(inspectionItems);
        return ResultVoUtil.success(detail);
    }

    private Object reflect(Object pojo, Element element) {
        Field[] fields = pojo.getClass().getDeclaredFields();
        for (Field field : fields) {
            try {
                String name = field.getName();
                if ("bacteriaResults".equals(name) || "antibioticResults".equals(name)) {
                    continue;
                }
                Method m = pojo.getClass().getMethod("set" + name, String.class);
                m.invoke(pojo, element.elementTextTrim(name));
            } catch (Exception e) {
                log.error("解析检验报告详情出错", e);
            }
        }
        return pojo;
    }




    public List<ExamIndexResponse> checkExamIndex(ReportIndexInquiry inquiry) {
        ExamIndexRequest request = new ExamIndexRequest.Builder()
                .patientNumType(inquiry.getPatType()).patientNum(inquiry.getPatNo())
                .startDate(inquiry.getReqStartTime()).endDate(inquiry.getReqEndTime()).build();
        ExamReportService examReportService = new ExamReportService();
        List<ExamIndexResponse> list = examReportService.queryExamIndex(request);
        list.sort(Comparator.comparing(ExamIndexResponse::getTrscDate));
        return list;
    }

    public ExamDetailResponse checkExamDetail(ReportDetailInquiry param) {
        if (StringUtil.isBlank(param.getReportId())) {
            throw new BizException("报告ID不能为空！");
        }
        return new ExamReportService().queryExamDetail(param.getReportId());
    }

    public List<TestReport> checkTestIndex(ReportIndexInquiry inquiry) {
        return dao.selectTestReportIndex(inquiry);
    }

    public TestReport checkTestDetail(ReportDetailInquiry request) {
        if (StringUtil.isBlank(request.getReportId())) {
            throw new BizException(ExceptionEnum.NULL_POINTER, "报告ID不能为空！");
        }
        TestReport result = dao.selectTestReport(request.getReportId());
        result.setExaminationSee(
                result.getExaminationSee()
                        .replaceAll("\r\n", "<br/>")
                        .replaceAll("\n", "<br/>")
        );
        result.setExaminationreSult(
                result.getExaminationreSult()
                        .replaceAll("\r\n", "<br/>")
                        .replaceAll("\n", "<br/>")
        );
        return result;
    }

    public List<PathologyIndex> checkPathologyIndex(ReportIndexInquiry request) {
        PathologyService pathologyService = new PathologyService();
        request.setSocialNo(getPatSocialNo(request.getPatType(), request.getPatNo()));
        List<PathologyIndex> list = pathologyService.queryOutpatientPathologyIndex(request);
        list.sort(Comparator.comparing(PathologyIndex::getApplyDate).reversed());
        return list;
    }

    public List<ElectroIndex> checkElectroIndex(ReportIndexInquiry request) {
        ElectroService electroService = new ElectroService();
        request.setSocialNo(getPatSocialNo(request.getPatType(), request.getPatNo()));
        List<ElectroIndex> list = electroService.queryOutpatientElectroIndex(request);
        list.forEach(item -> item.setApplyDate(formatNumericDate(item.getApplyDate())));
        list.sort(Comparator.comparing(ElectroIndex::getApplyDate).reversed());
        return list;
    }

    private String getPatSocialNo(PatType patType, String patNo) {
        if (patType == PatType.InPatient) {
            return dao.selectInpatientSocialNo(patNo);
        }
        return dao.selectOutpatientSocialNo(patNo);
    }

    private String formatNumericDate(String date) {
        return date.substring(0, 4) + "-" + date.substring(4, 6) + "-" + date.substring(6);
    }
}
