package thyyxxk.webserver.service.heliyongyao;

import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import thyyxxk.webserver.config.envionment.SystemConfig;
import thyyxxk.webserver.config.exception.BizException;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.constants.Capacity;
import thyyxxk.webserver.dao.his.heliyongyao.RationalUseDao;
import thyyxxk.webserver.dao.his.zhuyuanyisheng.YiZhuLuRuDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.heliyongyao.RationalUsePatient;
import thyyxxk.webserver.entity.heliyongyao.XunHuanJieDian;
import thyyxxk.webserver.entity.heliyongyao.YaoPin;
import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.XinZhenYiZhu;
import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.XinZhenYzActOrder;
import thyyxxk.webserver.service.PublicServer;
import thyyxxk.webserver.utils.*;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 描述： 合理用药
 * </p>
 *
 * @author xc
 * @date 2022-03-29 11:27
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class RationalUseServer {
    private final RationalUseDao dao;
    private final YiZhuLuRuDao orderDao;
    private final SystemConfig systemConfig;

    public ResultVo<JSONObject> rationalUseOfMedicine(String patNo, Integer times) {
        if (systemConfig.getRationalUseUrl() == null) {
            return ResultVoUtil.success(JSONObject.parseObject("{\"result_lv\": 0}"));
        }
        QueryWrapper<?> qw = new QueryWrapper<>();
        // 查询药品医嘱
        qw.eq("a.inpatient_no", patNo)
                .eq("a.admiss_times", times)
                .eq("a.status_flag", "1")
                .eq("a.enter_oper", TokenUtil.getInstance().getTokenUserId())
                .eq("isnull(a.self_buy,'0')", "0")
                .ne("a.serial", "00");

        XinZhenYiZhu patInfo = orderDao.queryPatientInfo(patNo, times);

        // 获取新开的医嘱
        patInfo.setList(orderDao.selectOrderNo(qw));
        List<XinZhenYzActOrder> historicalData = dao.getHistoricalMedicalOrders(patNo, times);

        JSONObject js = verify(patInfo, historicalData);
        return ResultVoUtil.success(js);
    }

    // 获取用药人信息及医嘱
    public ResultVo<XinZhenYiZhu> getInfoRationalUseOfMedicine(String patNo, Integer times) {
//        if (systemConfig.getRationalUseUrl() == null) {
//            return ResultVoUtil.success(JSONObject.parseObject("{\"result_lv\": 0}"));
//        }
        QueryWrapper<?> qw = new QueryWrapper<>();
        // 查询药品医嘱
        qw.eq("a.inpatient_no", patNo)
                .eq("a.admiss_times", times)
                .eq("a.status_flag", "1")
                .eq("a.enter_oper", TokenUtil.getInstance().getTokenUserId())
                .eq("isnull(a.self_buy,'0')", "0")
                .ne("a.serial", "00");

        XinZhenYiZhu patInfo = orderDao.queryPatientInfo(patNo, times);

        // 获取新开的医嘱
        patInfo.setList(orderDao.selectOrderNo(qw));
        return ResultVoUtil.success(patInfo);
    }



    /**
     * 调用药品审方接口
     *
     * @param url 审方地址
     * @return 返回提示
     */
    public ResultVo<JSONObject> auditingInterface(String url) {
        if (systemConfig.getRationalUseUrl() == null) {
            return ResultVoUtil.success(ExceptionEnum.SUCCESS, null, null);
        }
        String body = HttpRequest.get(url).execute().body();
        return ResultVoUtil.success(JSONObject.parseObject(body));
    }

    public JSONObject verify(XinZhenYiZhu param, List<XinZhenYzActOrder> historicalData) {
        String userCode = TokenUtil.getInstance().getTokenUserId();
        // 医生信息
        Map<String, String> doctMap = doctorInfo(userCode);
        String baseXml = doctMap.get("baseXml");
        String doctXml = doctMap.get("doct");
        QueryWrapper<?> qw = new QueryWrapper<>();
        List<String> drugList = new ArrayList<>();
        addTheDrugCode(param.getList(), drugList);
        addTheDrugCode(historicalData, drugList);

        if (ListUtil.isBlank(drugList)) {
            return new JSONObject();
        }
        qw.in("rtrim(code) + rtrim(serial)", drugList);
        Map<String, YaoPin> drugMap = dao.selectDrug(qw).stream().collect(
                Collectors.toMap(YaoPin::getId, a -> a, (k1, k2) -> k1)
        );
        String detailsXml = drugInfoFunc(param.getInpatientNo(), param.getAdmissTimes(), param.getList(), doctXml, drugMap, historicalData);
        String js = String.format("{\"BaseXml\": \"%s\", \"DetailsXml\" : \"%s\"}", baseXml, detailsXml);

        String text = HttpRequest.post(systemConfig.getRationalUseUrl()).body(js).execute().body();

        return JSONObject.parseObject(text);
    }

    /**
     * 添加药品编码
     *
     * @param list
     * @param drugList
     */
    private static void addTheDrugCode(List<XinZhenYzActOrder> list, List<String> drugList) {
        for (XinZhenYzActOrder item : list) {
            if (StringUtil.notBlank(item.getSerial())) {
                String key = item.getOrderCode().trim() + item.getSerial().trim();
                if (!drugList.contains(key)) {
                    drugList.add(key);
                }
            }
        }
    }

    public Map<String, String> doctorInfo(String code) {
        Map<String, String> doctorInfo = dao.yiShenXinXi(code);
        if (doctorInfo == null || doctorInfo.isEmpty()) {
            doctorInfo = new HashMap<>(Capacity.TWO);
        }

        Map<String, String> map = new HashMap<>(Capacity.TWO);

        String baseXml = "<base_xml>" +
                         "<source>HIS</source>" +
                         "<hosp_code>H32132200561</hosp_code>" +
                         "<hosp_name>沭阳铭和医院</hosp_name>" +
                         "<dept_code>" + nullToBlank(doctorInfo.get("dept_code")) + "</dept_code>" +
                         "<dept_name>" + nullToBlank(doctorInfo.get("dept_name")) + "</dept_name>" +
                         "<doct>" +
                         "<code>" + nullToBlank(String.valueOf(doctorInfo.get("code"))) + "</code>" +
                         "<name>" + nullToBlank(doctorInfo.get("name")) + "</name>" +
                         "<type>" + nullToBlank(doctorInfo.get("type")) + "</type>" +
                         "<type_name>" + nullToBlank(doctorInfo.get("type_name")) + "</type_name>" +
                         "</doct>" +
                         "</base_xml>";
        map.put("baseXml", baseXml);
        String sb = "<dept_code>" + nullToBlank(doctorInfo.get("dept_code")) + "</dept_code>" +
                    "<dept_name>" + nullToBlank(doctorInfo.get("dept_name")) + "</dept_name>" +
                    "<doct_code>" + nullToBlank(String.valueOf(doctorInfo.get("code"))) + "</doct_code>" +
                    "<doct_name>" + nullToBlank(doctorInfo.get("name")) + "</doct_name>";
        map.put("doct", sb);
        return map;
    }

    public String nullToBlank(String str) {
        if (StringUtil.isBlank(str)) {
            return "";
        }
        return str.trim();
    }

    /**
     * @param patNo    住院号
     * @param times    住院次数
     * @param drugData 需要审核的药品
     * @param doct     文档节点
     * @param drugMap  药品的map用 编码和规格做key
     * @return 返回节点
     */
    public String drugInfoFunc(String patNo,
                               Integer times,
                               List<XinZhenYzActOrder> drugData,
                               String doct,
                               Map<String, YaoPin> drugMap,
                               List<XinZhenYzActOrder> historicalData) {
//        log.info("数据:{}", JSON.toJSONString(drugData));
        StringBuilder sb = new StringBuilder();
        RationalUsePatient patient = dao.huanZheXinXi(patNo, times);
        if (patient == null) {
            throw new BizException(ExceptionEnum.LOGICAL_ERROR, "没有找到对应患者的信息。");
        }
        XinZhenYiZhu patientInfo = orderDao.queryPatientInfo(patNo, times);
        // 中西药处方/医嘱类型标识
        // 就诊类型
        // 就诊号
        sb.append("<details_xml>")
                .append("<hosp_code>H32132200561</hosp_code>")
                .append("<his_time>").append(DateUtil.formatDatetime(new Date())).append("</his_time>")
                .append("<hosp_flag>ip</hosp_flag>")
                // 中西药处方/医嘱类型标识
                .append("<cf_type>").append("1").append("</cf_type>")
                // 就诊类型
                .append("<treat_type>").append("400").append("</treat_type>")
                // 就诊号
                .append("<treat_code>").append(patNo).append("_").append(times).append(DateUtil.formatDatetime(new Date(), "YYYYMMDD")).append("</treat_code>")
                .append("<is_repeat>").append("1").append("</is_repeat>")
                .append("<bed_no>").append(nullToBlank(patientInfo.getBedNo())).append("</bed_no>")
                .append("<patient>")
                .append("<pati_id>").append(patNo).append("_").append(times).append("</pati_id>")
                .append("<name>").append(nullToBlank(patient.getName())).append("</name>")
                .append("<is_infant>").append(PublicServer.getInfantFlag(patNo)).append("</is_infant>")
                .append("<birth>").append(nullToBlank(patient.getBirth())).append("</birth>")
                .append("<sex>").append(nullToBlank(patient.getSexName())).append("</sex>")
                .append("<weight>").append("</weight>")
                .append("<height>").append("</height>")
                .append("<id_card>").append(patient.getIdCard()).append("</id_card>")
                .append("<medical_record>").append("</medical_record>")
                .append("<card_type>").append("</card_type>")
                .append("<card_code>").append("</card_code>")
                .append("<pregnant_unit>").append("</pregnant_unit>")
                .append("<pregnant>").append("</pregnant>");
        //  过敏节点，可循环
        sb.append("<allergic_data>");

        List<XunHuanJieDian> allergyData = dao.guoMin(patNo);
        xunHuanJieDian(sb, allergyData, "allergic");
        sb.append("</allergic_data>");
        // 皮试节点，可循环
        sb.append("<skintest_data>");
        List<XunHuanJieDian> skinTestData = new ArrayList<>();
        if (ListUtil.isBlank(skinTestData)) {
            XunHuanJieDian skinTest = new XunHuanJieDian();
            skinTest.setCode("").setName("").setResult("");
            skinTestData.add(skinTest);
        }
        for (XunHuanJieDian item : skinTestData) {
            sb.append("<skintest>")
                    .append("<name>").append(nullToBlank(item.getName())).append("</name>")
                    .append("<code>").append(nullToBlank(item.getCode())).append("</code>")
                    .append("<result>").append(nullToBlank(item.getResult())).append("</result>")
                    .append("</skintest>");
        }
        sb.append("</skintest_data>");
        // 诊断
        sb.append("<diagnose_data>");
        List<XunHuanJieDian> diagnosticData = new ArrayList<>();
        JSONObject medicalRecordDiagnosticData = JSONObject.parseObject(dao.medicalRecordDiagnosticData(patNo, times));
        if (medicalRecordDiagnosticData != null) {
            try {
                JSONArray arr = medicalRecordDiagnosticData.getJSONObject("入院诊断").getJSONArray("value");
                if (arr != null && !arr.isEmpty()) {
                    for (int i = 0; i < arr.size(); i++) {
                        JSONObject item = arr.getJSONObject(i);
                        XunHuanJieDian temp = new XunHuanJieDian();
                        temp.setType("2");
                        temp.setCode(item.getString("code"));
                        temp.setName(item.getString("name"));
                        diagnosticData.add(temp);
                    }
                }
            } catch (Exception e) {
                throw new BizException(ExceptionEnum.NOT_EL_MESSAGE, "获取入院诊断错误");
            }

        }

        // 诊断节点
        xunHuanJieDian(sb, diagnosticData, "diagnose");
        sb.append("</diagnose_data>")
                .append("</patient>");
        sb.append("<prescription_data>");
        sb.append("<prescription>").append("<id>").append("0").append("</id>")
                .append("<reason>").append("</reason>")
                .append("<is_current>").append(1).append("</is_current>")
                .append("<pres_type>").append("</pres_type>")
                .append("<pres_time>").append(DateUtil.formatDatetime(new Date())).append("</pres_time>")
                // 药品信息节点，可循环
                .append("<medicine_data>");
        // 循环处方节点
        prescribingInformation(drugData, doct, drugMap, sb, 1);
        prescribingInformation(historicalData, doct, drugMap, sb, 0);
        sb.append("</medicine_data></prescription>");
        sb.append("</prescription_data></details_xml>");
        return sb.toString();
    }

    private void prescribingInformation(List<XinZhenYzActOrder> drugData, String doct, Map<String, YaoPin> drugMap, StringBuilder sb,
                                        int current) {
        for (XinZhenYzActOrder item : drugData) {
            YaoPin yp = drugMap.get(item.getOrderCode().trim() + item.getSerial().trim());
            if (null == yp) {
                yp = new YaoPin();
                yp.setPackRetprice(BigDecimal.valueOf(1));
            }
            sb.append("<medicine>")
                    .append("<cf_id>").append("0").append("</cf_id>")
                    .append("<oeridid>").append(item.getActOrderNo().stripTrailingZeros().toPlainString()).append("</oeridid>")
                    .append("<is_current>").append(current).append("</is_current>")
                    .append("<pres_type>").append("ONCE".equals(item.getFrequCode()) ? "T" : "L").append("</pres_type>")
                    .append("<pres_time>").append(DateUtil.formatDatetime(item.getOrderTime())).append("</pres_time>")
                    .append("<name>").append(item.getOrderName()).append("</name>")
                    .append("<his_code>").append(nullToBlank(item.getOrderCode() + "_" + item.getSerial())).append("</his_code>")
                    .append("<insur_code>").append(nullToBlank(yp.getNationalCode())).append("</insur_code>")
                    .append("<approval>").append(nullToBlank(yp.getPzwh())).append("</approval>")
                    .append("<spec>").append(nullToBlank(item.getDrugSpecification())).append("</spec>")
                    .append("<quantity>").append(nullToBlank(item.getDrugQuan() + item.getMiniUnitName())).append("</quantity>")
                    .append("<group>").append(item.getParentNo() == null ? item.getActOrderNo().stripTrailingZeros().toPlainString() : item.getParentNo().stripTrailingZeros().toPlainString()).append("</group>")
                    .append("<reason>").append("</reason>")
                    .append("<dose_unit>").append(nullToBlank(item.getDoseUnitName())).append("</dose_unit>")
                    .append("<dose>").append(item.getDose()).append("</dose>")
                    .append("<kyzl>").append(item.getDrugQuan()).append("</kyzl>")
                    .append("<zl_unit>").append(item.getDrugQuanName()).append("</zl_unit>")
                    .append("<freq>").append("ZY").append(nullToBlank(item.getFrequCode())).append("</freq>")
                    .append("<administer>").append("ZY").append(item.getSupplyCode()).append("</administer>")
                    .append("<begin_time>").append(DateUtil.formatDatetime(item.getStartTime())).append("</begin_time>")
                    .append("<end_time>").append(DateUtil.formatDatetime(item.getEndTime())).append("</end_time>")
                    .append("<days>").append("</days>")
                    .append(doct)
                    .append("<PREVENTIVE_TYPE>").append("2").append("</PREVENTIVE_TYPE>")
                    .append("<money>").append(yp.getPackRetprice().multiply(item.getDrugQuan())).append("</money>")
                    .append("<emergency>").append(item.getEmergencyFlag()).append("</emergency>")
                    .append("</medicine>");
        }
    }

    /**
     * 循环节点
     *
     * @param sb      字符串
     * @param jieDian 节点
     * @param name    节点名称
     */
    public void xunHuanJieDian(StringBuilder sb, List<XunHuanJieDian> jieDian, String name) {
        if (ListUtil.isBlank(jieDian)) {
            XunHuanJieDian zhenDuan = new XunHuanJieDian();
            zhenDuan.setType("").setCode("").setName("");
            jieDian.add(zhenDuan);
        }

        for (XunHuanJieDian item : jieDian) {
            sb.append("<").append(name).append(">").
                    append("<type>").append(nullToBlank(item.getType())).append("</type>")
                    .append("<name>").append(nullToBlank(item.getName())).append("</name>")
                    .append("<code>").append(nullToBlank(item.getCode())).append("</code>")
                    .append("</").append(name).append(">");
        }
    }
}
