package thyyxxk.webserver.service.examinations;

import com.baomidou.dynamic.datasource.annotation.DS;
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.ExceptionEnum;
import thyyxxk.webserver.dao.lis.AdiconDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.examinations.adicon.AdiconHeader;
import thyyxxk.webserver.entity.examinations.adicon.AdiconIndex;
import thyyxxk.webserver.entity.examinations.adicon.AdiconItem;
import thyyxxk.webserver.entity.examinations.inspections.InspectionsIndex;
import thyyxxk.webserver.entity.examinations.inspections.QueryInspectionParam;
import thyyxxk.webserver.entity.examinations.inspections.detail.*;
import thyyxxk.webserver.service.examinations.adicon.Proxy;
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.List;
import java.util.Map;

/**
 * @author dj
 */
@Service
@Slf4j
@DS("lis")
public class InspectionsService {
    private final AdiconDao 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(AdiconDao dao, ThmzSystem thmz) {
        this.dao = dao;
        this.thmz = thmz;
    }

    public ResultVo<List<AdiconIndex>> queryAdiconReportIndex(String patNo) {
        List<AdiconIndex> indexList = dao.selectAdiconReportIndex(patNo);
        if (ListUtil.isBlank(indexList)) {
            return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST);
        }
        return ResultVoUtil.success(indexList);
    }

    public ResultVo<InspectionDetail> queryAdiconReportDetail(String reportId) {
        AdiconHeader header = dao.selectAdiconReportHeader(reportId);
        List<AdiconItem> itemList = dao.selectAdiconReportItems(reportId);
        if (null == header || ListUtil.isBlank(itemList)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "数据库查询失败。");
        }
        InspectionDetail detail = new InspectionDetail();
        detail.setAdiconHeader(header);
        detail.setAdiconItems(itemList);
        return ResultVoUtil.success(detail);
    }

    public ResultVo<String> queryAdiconInspection(String barCode) {
        String xml = new Proxy().getProxySoap().getSampleRequest(ADICON_TOKEN, barCode);
        log.info("查询艾迪康：{}", xml);
        return ResultVoUtil.success(xml);
    }

    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.formatDatetime(param.getStart(), "yyyy-MM-dd") + "</START_TIME>" +
                "<END_TIME>" + DateUtil.formatDatetime(param.getEnd(), "yyyy-MM-dd") + "</END_TIME>" +
                "</message>";
        String xml = new PushService().getPushServiceSoap().getLabReportIndex(message);
        return analyzeReportIndex(xml);
    }

    public ResultVo<InspectionDetail> queryInspectionDetail(String orderId) {
        if (orderId == null || "".equals(orderId.trim()) || 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.size() > 0) {
                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.size() > 0) {
                        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;
    }
}
