package thyyxxk.webserver.service.zhuyuanyisheng;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.db.DbUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import thyyxxk.webserver.config.envionment.YzConfig;
import thyyxxk.webserver.config.exception.BizException;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.dao.his.zhuyuanyisheng.YiZhuLuRuDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.RoleCode;
import thyyxxk.webserver.entity.casefrontsheet.request.SheetOverview;
import thyyxxk.webserver.entity.datamodify.GetDropdownBox;
import thyyxxk.webserver.entity.datamodify.SelectV2;
import thyyxxk.webserver.entity.datamodify.YzActOrder;
import thyyxxk.webserver.entity.datamodify.ZyDetailCharge;
import thyyxxk.webserver.entity.dictionary.CodeName;
import thyyxxk.webserver.entity.inpatient.patient.Overview;
import thyyxxk.webserver.entity.inpatient.patient.Patient;
import thyyxxk.webserver.entity.login.UserInfo;
import thyyxxk.webserver.entity.medicalinsurance.inpatient.SiLimitRequest;
import thyyxxk.webserver.entity.medicine.YpZdGroupName;
import thyyxxk.webserver.entity.medicine.vo.YpZdGroupNameVo;
import thyyxxk.webserver.entity.zhuyuanyisheng.OneClickOrder;
import thyyxxk.webserver.entity.zhuyuanyisheng.ZyOrderZk;
import thyyxxk.webserver.entity.zhuyuanyisheng.dto.doctorAuth.DoctorAuthParams;
import thyyxxk.webserver.entity.zhuyuanyisheng.jianyanjiancha.YshYjReq;
import thyyxxk.webserver.entity.zhuyuanyisheng.vo.doctorAuth.DoctorAuthRest;
import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.*;
import thyyxxk.webserver.http.drg.DrgWebApi;
import thyyxxk.webserver.service.PublicServer;
import thyyxxk.webserver.service.hutoolcache.DrugCache;
import thyyxxk.webserver.service.hutoolcache.ExtraCache;
import thyyxxk.webserver.service.hutoolcache.UserCache;
import thyyxxk.webserver.service.inpatient.casefrontsheet.CaseFrontSheetMainService;
import thyyxxk.webserver.service.medicalinsurance.SiChargeLimitService;
import thyyxxk.webserver.service.zhuyuanyisheng.yizhuverify.Repel;
import thyyxxk.webserver.service.zhuyuanyisheng.yizhuverify.YiZhuCheckData;
import thyyxxk.webserver.utils.*;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 描述： 医嘱录入
 * </p>
 *
 * @author xc
 * @date 2022-01-04 16:59
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class YiZhuLuRuServer {
    private final YiZhuLuRuDao dao;
    private final PublicServer publicServer;
    private final CaseFrontSheetMainService caseFrontSheetMainService;
    private final SqlSessionFactory sqlSessionFactory;
    private final SiChargeLimitService siChargeLimitService;
    private final UserCache userCache;
    private final ExtraCache extraCache;
    private final YzConfig yzConfig;
    private final DrgWebApi drgWebApi;

    private final String ITEM = "00";
    private final DrugCache drugCache;

    public ResultVo<String> getOrderNo() {
        return ResultVoUtil.success(publicServer.getActOrderNo().stripTrailingZeros().toPlainString());
    }

    public ResultVo<List<Patient>> getMyPatient() {
        return ResultVoUtil.success(dao.getMyPatient(TokenUtil.getInstance().getTokenUserId()));
    }

    /**
     * 获取患者的医嘱
     *
     * @param param 查询条件 住院号，住院时间
     * @return 返回医嘱数据
     */
    public ResultVo<List<XinZhenYzActOrder>> huoQuYiZhuShuJu(YiZhuFeiYongChaXunTiaoJian param) {
        List<XinZhenYzActOrder> xinZhenYzActOrders = dao.selectOrderNo(param.buildQw());
        return ResultVoUtil.success(xinZhenYzActOrders);
    }

    /**
     * 获取患者的医嘱
     *
     * @param actOrderNo 医嘱id
     * @return 返回医嘱数据
     */
    public List<YzActOrder> getYiZhuShuJuByOrderNo(List<String> actOrderNo) {
        List<YzActOrder> xinZhenYzActOrder = dao.getYiZhuShuJuByOrderNo(new QueryWrapper<YzActOrder>().in("act_order_no", actOrderNo));
        return xinZhenYzActOrder;
    }

    /**
     * 获取患者的待确费医嘱数
     * @return 返回医嘱数据
     */
    public Integer getledgerSnFromYiZhu(String inpatientNo, Integer admissTimes) {
        Integer  ledgerSn = dao.getledgerSnFromYiZhu(inpatientNo,admissTimes);
        return ledgerSn;
    }

    /**
     * 设置医嘱号的数状图
     *
     * @param yiZhuList 医嘱数据
     * @return s
     */
    @NotNull
    public static List<XinZhenYzActOrder> getOrderList(List<XinZhenYzActOrder> yiZhuList) {
        if (ListUtil.isBlank(yiZhuList)) {
            return new ArrayList<>();
        }
        // 还有那些没有被匹配的子级医嘱
        Map<BigDecimal, XinZhenYzActOrder> wuFuJiYiZhu = yiZhuList.stream().collect(Collectors.toMap(XinZhenYzActOrder::getActOrderNo, a -> a, (k1, k2) -> k1));
        // 做成树状图
        Map<BigDecimal, XinZhenYzActOrder> map = new HashMap<>(yiZhuList.size());
        List<XinZhenYzActOrder> tree = new ArrayList<>();
        for (XinZhenYzActOrder item : yiZhuList) {
            if (item.getParentNo() == null) {
                tree.add(item);
                wuFuJiYiZhu.remove(item.getActOrderNo());
            }
            map.put(item.getActOrderNo(), item);
            EntityStringTrim.beanAttributeValueTrim(item);
            if ("00".equals(item.getSerial())) {
                item.setGroupNoName("项目");
                item.setSerialName("项目");
            } else {
                if ("01".equals(item.getSerial())) {
                    item.setSerialName("小包装");
                } else if ("99".equals(item.getSerial())) {
                    item.setSerialName("大包装");
                }
            }
        }
        for (XinZhenYzActOrder item : yiZhuList) {
            XinZhenYzActOrder actOrder = map.get(item.getParentNo());
            if (actOrder == null) {
                continue;
            }
            if (actOrder.getParentNo() != null) {
                item.setParentNo(null);
                item.setOrderName("注意此医嘱成组有误，请重新选择父医嘱，父医嘱不能是其他医嘱的子医嘱。");
                item.setStatusFlag("6");
                continue;
            }
            wuFuJiYiZhu.remove(item.getActOrderNo());
            if (actOrder.getChildren() == null) {
                actOrder.setChildren(new ArrayList<>());
                actOrder.setOrderGroup("┌");
            }
            item.setOrderGroup("└");
            actOrder.getChildren().add(item);
        }
        if (!wuFuJiYiZhu.isEmpty()) {
            tree.addAll(wuFuJiYiZhu.values());
        }
        List<XinZhenYzActOrder> list = new ArrayList<>();
        for (XinZhenYzActOrder zy : tree) {
            list.add(zy);
            if (ListUtil.notBlank(zy.getChildren())) {
                zy.getChildren().get(zy.getChildren().size() - 1).setOrderGroup("└");
                list.addAll(zy.getChildren());
                zy.setChildren(null);
            }
        }
        return list;
    }

    /**
     * 获取搜索的项目信息，如药品和项目
     *
     * @param code 拼音首字母，中文，编码来进行搜索
     * @return 返回项目信息
     */
    public ResultVo<List<YiZhuMingChen>> huoQuXiangMu(String code, String groupNo) {
        code = StringUtil.isContainChinese(code);
        // 药品
        List<YiZhuMingChen> list = dao.yiZhuYaoPing(code, groupNo);
        // 项目
        list.addAll(dao.yiZhuXiangMu(code));
        // 模板
        list.addAll(dao.composeOrders(code, userCache.getUserInfoByToken().getDeptCode()));
        EntityStringTrim.beanAttributeValueTrimList(list);
        return ResultVoUtil.success(list);
    }

    /**
     * 把有错误的子医嘱纠正回来，子医嘱要跟随父医嘱的频率 等
     *
     * @param list 患者的数据
     */
    public void correctSubOrders(List<XinZhenYzActOrder> list) {
        // 父医嘱
        Map<BigDecimal, XinZhenYzActOrder> parentOrder = new HashMap<>(list.size());
        list.forEach(item -> parentOrder.put(item.getActOrderNo(), item));
        list.forEach(item -> {
            if (item.getParentNo() != null && parentOrder.containsKey(item.getParentNo())) {
                XinZhenYzActOrder order = parentOrder.get(item.getParentNo());
                // 判断是否需要更新
                if (updateSubOrders(order, item)) {
                    dao.updateSubOrderStatus(item.getActOrderNo(), order);
                }
            }
        });
    }

    private boolean updateSubOrders(XinZhenYzActOrder parent, XinZhenYzActOrder children) {
        if (!parent.getOrderTime().equals(children.getOrderTime())) {
            return true;
        }
        if (!parent.getStartTime().equals(children.getStartTime())) {
            return true;
        }
        if (parent.getEndTime() != null && !parent.getEndTime().equals(children.getEndTime())) {
            return true;
        }
        if (!parent.getFrequCode().equals(children.getFrequCode())) {
            return true;
        }
        return !parent.getGroupNo().equals(children.getGroupNo());
    }

    /**
     * xc确认医嘱 , 这个是最新的正确的
     *
     * @param param 数据
     * @return 返回提示
     */
    public ResultVo<Map<String, Object>> confirmOrders(XinZhenYiZhu param) {
        // 判断是否开了出院医嘱后的医嘱
        if (!yzConfig.getPrescribeMedicalAdviceAfterDischarge()) {
            YzActOrder ourOrderInfo = dao.selectFinallyOutOrderInfo(param.getInpatientNo(), param.getAdmissTimes());
            if (ourOrderInfo != null) {
                if (dao.prescribeMedicalAdviceAfterDischarge(param.getInpatientNo(), param.getAdmissTimes(), ourOrderInfo.getStartTime(), ourOrderInfo.getActOrderNo()) > 0) {
                    return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "有医嘱开在了出院医嘱后无法确认。");
                }
            }
        }

        QueryWrapper<?> qw = getConfirmQueryWrapper(param.getInpatientNo(), param.getAdmissTimes());

        param.setList(dao.selectOrderNo(qw));

        List<XinZhenYzActOrder> yiZhuList = param.getList();
        if (ListUtil.isBlank(yiZhuList)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有需要确认的医嘱.");
        }
        // 把错误的子医嘱更正回来
        correctSubOrders(param.getList());
        String userCode = TokenUtil.getInstance().getTokenUserId();
        XinZhenYiZhu patInfo = dao.queryPatientInfo(param.getInpatientNo(), param.getAdmissTimes());

        List<XinZhenYzActOrder> confirmYzList = new ArrayList<>();

        YiZhuCheckData checkData = new YiZhuCheckData(dao).checkForRestrictedMedication();
        checkData.init(yiZhuList, patInfo).judgeExclusion();

        Map<String, Object> checkMap = checkData.startCheck(confirmYzList::add);

        if (checkData.multipleExclusions()) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "一次性不能确认多条全排斥医嘱。");
        }

        if (checkData.getFailed()) {
            return ResultVoUtil.fail(ExceptionEnum.ERROR_MESSAGE, "请修改错误的医嘱", checkMap);
        }

        Repel repel = checkData.getRepel();

        if (repel != null && repel.getCount() > 0) {
            // 把全排斥医嘱变成临时防止给药方式错误，并且停止其他医嘱
            dao.stopOrder(param.getInpatientNo(), param.getAdmissTimes(), repel.getDate(), userCode, repel.getOrderNo());
        }

        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        YiZhuLuRuDao mapper = sqlSession.getMapper(YiZhuLuRuDao.class);

        Date now = new Date();
        try {
            ListUtil.partitionAndFunc(confirmYzList, 50, (list) -> {
                for (XinZhenYzActOrder item : list) {
                    if (StringUtil.notBlank(item.getSuperiorDoctor())) {
                        mapper.confirmOrdersSuperiorDoctor(item.getActOrderNo(), item.getSuperiorDoctor(), now);
                    } else {
                        mapper.confirmOrders(item.getActOrderNo(), userCode, now);
                    }
                }
                sqlSession.commit();
            });
        } finally {
            sqlSession.close();
        }
        drgOrderUpdate(patInfo.getInpatientNo() + "_" + patInfo.getAdmissTimes() + "_" + patInfo.getLedgerSn());
        sendAMessageToTheNurse(param, userCode, patInfo, "新增医嘱");
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
    }

    /**
     * 出院医嘱质控校验
     * 暂时废弃
     *
     * @param param 患者信息
     */
    @Deprecated
    private void dischargeQCVerification(XinZhenYiZhu param) {
        if (param.getInpatientNo().contains("$")) {
            return;
        }
        if (dao.selectDischargeOrde(param, TokenUtil.getInstance().getTokenUserId()) > 0) {
            SheetOverview overview = new SheetOverview();
            overview.setBah(param.getInpatientNo());
            overview.setTimes(param.getAdmissTimes());
            overview.setInOutFlag(1);
            ResultVo<Map<String, List<CodeName>>> result = caseFrontSheetMainService.sheetVerification(overview);
            if (!result.getCode().equals(ExceptionEnum.SUCCESS.getCode())) {
                throw new BizException(ExceptionEnum.LOGICAL_ERROR, result.getMessage());
            }
            if (!result.getData().get("force").isEmpty()) {
                throw new BizException(ExceptionEnum.LOGICAL_ERROR, "未通过病案首页质控，无法确认出院医嘱。");
            }
        }
    }

    /**
     * 在开医嘱时 drg 需要调用一下这个接口,接口已经做了异步的请求
     *
     * @param patientNo 患者id
     */
    public void drgOrderUpdate(String patientNo) {
        try {
            JSONObject jsonDrg = new JSONObject();
            jsonDrg.put("visit_id", Collections.singletonList(patientNo));
            jsonDrg.put("scene_type", 1);
            drgWebApi.etlClient(jsonDrg);
        } catch (Exception ignored) {
        }
    }

    private void sendAMessageToTheNurse(XinZhenYiZhu param, String inputCode, XinZhenYiZhu patInfo, String name) {
        List<String> content = new ArrayList<>();
        for (XinZhenYzActOrder item : param.getList()) {
            String sb = notificationStyle("医嘱名", "409eff", item.getOrderName()) +
                        notificationStyle("医嘱时间", "409eff", DateUtil.formatDatetime(item.getStartTime())) +
                        notificationStyle("床位", "409eff", patInfo.getBedNo()) +
                        notificationStyle("患者姓名", "409eff", patInfo.getName()) +
                        notificationStyle("频次", "409eff", item.getFrequCode());
            content.add(sb);
        }
        publicServer.faSongXiaoXi(patInfo, content, name, inputCode);
    }

    private String notificationStyle(String name, String color, String content) {
        return String.format("%s：<span style='color: #%s'>%s</span><br>", name, color, content);
    }

    /**
     * 录入 单条医嘱  新的 下面的保存医嘱的都无效了
     *
     * @param param 参数
     * @return 错误信息和提示
     */
    public ResultVo<Map<String, Object>> enterOrders(XinZhenYiZhu param) {
        XinZhenYzActOrder oldOrderNo = dao.getActOrderNoOne(param.getActOrderNo());
        String userCode = TokenUtil.getInstance().getTokenUserId();
        if (oldOrderNo != null) {
            if (!"1".equals(oldOrderNo.getStatusFlag().trim())) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "该医嘱不是录入状态无法保存.");
            }
            if (!oldOrderNo.getInpatientNo().trim().equals(param.getInpatientNo())) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "两次医嘱录入时患者不一致。");
            }
            if (!oldOrderNo.getEnterOper().equals(userCode)) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医嘱录入人不是您，无法修改。");
            }
        }
        XinZhenYiZhu huanZheXinXi = dao.queryPatientInfo(param.getInpatientNo(), param.getAdmissTimes());
        XinZhenYzActOrder data = param.getData();
        if (ITEM.equals(data.getSerial().trim())) {
            data.setGroupNo("00");
        }

        YiZhuCheckData checkData = new YiZhuCheckData(dao);

        Map<String, Object> errorMessageMap = checkData.init(data, huanZheXinXi)
                .startCheck(null);

        if (checkData.getFailed()) {
            return ResultVoUtil.fail(ExceptionEnum.ERROR_MESSAGE, "请修改有错误的医嘱。", errorMessageMap);
        }

        // 如果是 子医嘱 的话就拿到父医嘱的频率
        if (data.getParentNo() != null) {
            String frequCode = dao.selectParentNo(data.getParentNo().stripTrailingZeros().toPlainString());
            if (StringUtil.notBlank(frequCode)) {
                data.setFrequCode(frequCode);
            }
        }

        if (checkData.getPassTheAudit()) {
            List<String> ZK_CODE_LIST = new ArrayList<>();
            List<YzZdOrderItemConfirm> value = extraCache.getYzZdOrderItemConfirm();
            if (value != null) {
                for (YzZdOrderItemConfirm yzCode : value) {
                    if (yzCode.getItemName().equals("转科")) {
                        ZK_CODE_LIST.add(yzCode.getOrderCode());
                    }
                }
            }

            if (ZK_CODE_LIST.contains(data.getOrderCode())) {
                ZyOrderZk transferData = new ZyOrderZk();
                transferData
                        .setActOrderNo(param.getActOrderNo())
                        .setNewDept(data.getZkDeptCode())
                        .setNewWard(data.getZkWardCode())
                        .setOldWard(huanZheXinXi.getDeptCode())
                        .setOldDept(huanZheXinXi.getZkWard());
                // 先删除转科在插入
                dao.deleteTransferOrder(param.getActOrderNo());
                dao.insertDoctorSOrder(transferData);
            }
            // 判断是不是抗菌药物
            XinZhenYzActOrder kssItem = checkData.getDrugData(data.getOrderCode().trim() + data.getSerial().trim() + data.getGroupNo().trim());
            if (kssItem != null && kssItem.getKjywFlag() != null && kssItem.getKjywFlag() == 1) {
                YzActRecordKss kss = new YzActRecordKss();
                kss.setActOrderNo(data.getActOrderNo());
                kss.setChargeCode(data.getOrderCode());
                kss.setYyfs(data.getYyfs());
                kss.setSsqk(data.getSsqk());
                kss.setYysj(data.getYysj());
                // 删除抗菌药物信息
                dao.deleteAntimicrobialInformation(param.getActOrderNo());
                dao.insertAntimicrobialInformation(param.getActOrderNo(),
                        kss, userCode, param.getInpatientNo(), param.getAdmissTimes());
            }
        }

        dao.deleteOrderNo(param.getActOrderNo());
        dao.insertEntryOrder(huanZheXinXi, param.getData(), userCode);

        // 更新授权医生
        if (StringUtil.notBlank(param.getData().getSuperiorDoctor())) {
            dao.updateAuthorizedDoctor(param.getData().getActOrderNo(), param.getData().getSuperiorDoctor());
        }

        // 项目不触发
        if (param.getData().getParentNo() == null && !param.getData().getSerial().equals("00")) {
            String selectSupplyCode = dao.selectSupplyCode(param.getData().getSupplyCode().trim());
            if (StringUtil.isBlank(selectSupplyCode)) {
                selectSupplyCode = "044";
            }
            // 子医嘱跟随父医嘱
            dao.howOftenTheSubPhysicianOrderIsModified(param.getData(), selectSupplyCode);
        }

        QueryWrapper<?> qw = getQueryWrapper(param, data);

        Map<String, Object> successMap = new HashMap<>();
        successMap.put("code", 200);
        successMap.put("data", getOrderList(dao.selectOrderNo(qw)));

        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "添加成功。", successMap);
    }

    @NotNull
    private static QueryWrapper<?> getQueryWrapper(XinZhenYiZhu param, XinZhenYzActOrder data) {
        QueryWrapper<?> qw = new QueryWrapper<>();

        qw.eq("a.inpatient_no", param.getInpatientNo());
        qw.eq("a.admiss_times", param.getAdmissTimes());
        qw.eq("a.status_flag", "1");

        // 不是子节点，就需要查询 子节点
        if (data.getParentNo() == null) {
            qw.and(wrapper -> wrapper.eq("a.act_order_no", param.getActOrderNo())
                    .or()
                    .eq("a.parent_no", param.getActOrderNo())
            );
        } else {
            // 如果是子节点就返回自己
            qw.eq("a.act_order_no", data.getActOrderNo());
        }

        qw.orderByAsc("a.act_order_no");
        return qw;
    }

    /**
     * 把医嘱模板中的数据插入到 患者的医嘱表中
     *
     * @param param 参数
     * @return 返回插入的医嘱
     */
    public ResultVo<JSONObject> insertTemplateOrder(XinZhenYiZhu param) {
        if (StringUtil.isBlank(param.getInpatientNo())) {
            return ResultVoUtil.fail(ExceptionEnum.ERROR_MESSAGE, "请先选择患者.");
        }

        XinZhenYiZhu patInfo = dao.queryPatientInfo(param.getInpatientNo(), param.getAdmissTimes());
        if (patInfo == null) {
            return ResultVoUtil.fail(ExceptionEnum.ERROR_MESSAGE, "请先选择患者.");
        }

        List<BigDecimal> returnOrderList = new ArrayList<>();
        List<XinZhenYzActOrder> list = param.getList();

        List<XinZhenYzActOrder> resList = new ArrayList<>();
        Map<BigDecimal, XinZhenYzActOrder> map = new HashMap<>(list.size());
        String userCode = TokenUtil.getInstance().getTokenUserId();

        for (XinZhenYzActOrder item : list) {
            if (item.getParentNo() == null) {
                resList.add(item);
            }
            map.put(item.getActOrderNo(), item);
        }

        list.forEach(item -> {
            if (item.getParentNo() != null) {
                XinZhenYzActOrder mapItem = map.get(item.getParentNo());
                if (mapItem != null) {
                    if (mapItem.getChildren() == null) {
                        mapItem.setChildren(new ArrayList<>());
                    }
                    mapItem.getChildren().add(item);
                }
            }
        });

        templateInsertToOrder(resList, patInfo, userCode, returnOrderList);
        JSONObject js = getNewOrderData(returnOrderList);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "插入模板数据成功。", js);
    }


    /**
     * 把模板数据插入到医嘱中
     *
     * @param resList         医嘱数据
     * @param patInfo         患者信息
     * @param userCode        用户编码
     * @param returnOrderList 返回的医嘱号
     */
    public void templateInsertToOrder(List<XinZhenYzActOrder> resList,
                                      XinZhenYiZhu patInfo,
                                      String userCode,
                                      List<BigDecimal> returnOrderList) {

        CacheOnce<XinZhenYzActOrder> drug = new CacheOnce<>();

        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        YiZhuLuRuDao mapper = sqlSession.getMapper(YiZhuLuRuDao.class);

        for (XinZhenYzActOrder item : resList) {
            setTempInfo(drug, item, patInfo);
            item.setActOrderNo(publicServer.getActOrderNo());
            returnOrderList.add(item.getActOrderNo());
            mapper.insertEntryOrder(patInfo, item, userCode);

            if (ListUtil.notBlank(item.getChildren())) {
                for (XinZhenYzActOrder children : item.getChildren()) {
                    setTempInfo(drug, children, patInfo);
                    children.setActOrderNo(publicServer.getActOrderNo());
                    returnOrderList.add(children.getActOrderNo());
                    children.setParentNo(item.getActOrderNo());
                    mapper.insertEntryOrder(patInfo, children, userCode);
                }
            }
        }

        try {
            sqlSession.commit();
        } finally {
            DbUtil.close(sqlSession);
        }

    }

    private void setTempInfo(CacheOnce<XinZhenYzActOrder> drug, XinZhenYzActOrder data, XinZhenYiZhu patInfo) {
        XinZhenYzActOrder feiYongXinXi = drug.get(
                data.getOrderCode().trim() + data.getSerial().trim() + data.getGroupNo().trim(),
                (temp) -> dao.drugDataOne(temp, patInfo.getZkWard(), null)
        );
        YiZhuCheckData.calculateDrugAmount(data, feiYongXinXi);
    }


    /**
     * 删除单条医嘱
     *
     * @param orderNo 医嘱号
     * @return 提示
     */
    public ResultVo<String> toDeleteAnOrder(String orderNo) {
        XinZhenYzActOrder oldData = dao.getActOrderNoOne(orderNo);
        String message = judgeWhetherItCanBeDeleted(oldData);
        if (StringUtil.notBlank(message)) {
            return ResultVoUtil.fail(ExceptionEnum.ERROR_MESSAGE, message);
        }
        dao.toDeleteAnOrder(orderNo, oldData.getInpatientNo());
        dao.deleteGroup(orderNo);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
    }


    /**
     * 删除多条录入的医嘱
     *
     * @param param 参数
     * @return 返回提示
     */
    public ResultVo<Map<String, String>> deleteMultipleOrders(XinZhenYiZhu param) {
        QueryWrapper<?> qw = new QueryWrapper<>();
        List<BigDecimal> list = new ArrayList<>();
        param.getList().forEach(item -> {
            list.add(item.getActOrderNo());
        });
        qw.in("act_order_no", list);
        List<XinZhenYzActOrder> deleteOrderList = dao.getOrdersToDelete(qw);
        if (ListUtil.isBlank(deleteOrderList)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有找到原医嘱可能已经被删除了");
        }
        Map<String, String> map = new HashMap<>();
        deleteOrderList.forEach(item -> {
            String error = judgeWhetherItCanBeDeleted(item);
            if (StringUtil.notBlank(error)) {
                map.put(item.getActOrderNo().stripTrailingZeros().toPlainString(), error);
            }
        });
        if (map.isEmpty()) {
            dao.deleteParentChildRelationship(param.getInpatientNo(), param.getAdmissTimes(), list);
            dao.deleteMultipleOrders(qw);
            return ResultVoUtil.fail(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
        }
        return ResultVoUtil.fail(ExceptionEnum.ERROR_MESSAGE, "删除失败", map);
    }

    private String judgeWhetherItCanBeDeleted(XinZhenYzActOrder oldData) {
        StringBuilder str = new StringBuilder();
        if (oldData == null) {
            return "没有找到原医嘱可能已经被删除了";
        }
        if (!("1".equals(oldData.getStatusFlag()) || "2".equals(oldData.getStatusFlag()))) {
            str.append("该医嘱不是录入或确认状态,无法删除");
        }
        if (!oldData.getEnterOper().equals(TokenUtil.getInstance().getTokenUserId())) {
            str.append("该医嘱录入人不是您,无法删除.");
        }
        return str.toString();
    }


    public ResultVo<Map<BigDecimal, String>> stopOrder(XinZhenYiZhu param) {
        if (ListUtil.isBlank(param.getList())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "请先选择数据");
        }
        Map<BigDecimal, String> map = new HashMap<>();

        param.getList().forEach(item -> {
            BigDecimal id = item.getActOrderNo();
            if (item.getEndTime() == null) {
                map.put(id, "停止时间不能为空，或该医嘱已经停止了。");
            } else {
                if (DateUtil.shiJianDaXiao(item.getEndTime(), item.getStartTime(), "<")) {
                    map.put(id, "停止时间不能小于医嘱的开始时间。");
                }
            }
        });

        if (map.isEmpty()) {
            String tokenUserId = TokenUtil.getInstance().getTokenUserId();
            dao.setStopTime(param.getList(), tokenUserId, param.getInpatientNo(), param.getAdmissTimes());
            XinZhenYiZhu patInfo = dao.queryPatientInfo(param.getInpatientNo(), param.getAdmissTimes());
            publicServer.faSongXiaoXi(patInfo, StrUtil.format("停止【{}】条", param.getList().size()), "停止医嘱", tokenUserId);
            return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
        }

        return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "请修改错误", map);
    }

    /**
     * 获取某一个费用的详细信息
     *
     * @param code         编码
     * @param serial       00-项目 01-小包装的药品 99-大包装
     * @param deptCode     科室编码
     * @param groupNo      药房编码
     * @param seniorDoctor 授权医生
     * @param flag         医嘱状态标志
     * @return 返回该费用的一些详细信息，以及一些提示信息。
     */
    public ResultVo<Map<String, Object>> huoQuFeiYongXinXi(String code, String serial,
                                                           String deptCode,
                                                           String groupNo,
                                                           String seniorDoctor,
                                                           String flag) {
        Map<String, Object> map = new HashMap<>();
        // 一些提示
        List<String> prompt = new ArrayList<>();
        boolean permissionPrompt = false;
        // 加载项目信息
        if (ITEM.equals(serial.trim())) {
            List<XinZhenYzActOrder> xiangMu = dao.huoQuXiangMu(code);
            for (XinZhenYzActOrder item : xiangMu) {
                if (item.getDelFlag() == 1) {
                    return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, String.format("该医嘱下的【%s】，已经被停用了，请联系物价科。", item.getOrderName()));
                } else if (StringUtil.isBlank(item.getNationalCode())) {
                    prompt.add(String.format("该医嘱下面的【%s】，没有医保编码，请注意。", item.getOrderName()));
                } else {
                    prompt.add(String.format("该医嘱下【%s】，医保码为：【%s】。", item.getOrderName(), item.getNationalCode()));
                }
            }
            if (ListUtil.isBlank(xiangMu)) {
                if ("1".equals(flag)) {
                    Integer paiChiYiZhu = dao.shiFouPaiChiYiZhu(code);
                    if (paiChiYiZhu != null) {
                        switch (paiChiYiZhu) {
                            case 1:
                                prompt.add("全排斥医嘱");
                                break;
                            case 2:
                                prompt.add("单组排斥医嘱");
                                break;
                            case 3:
                                prompt.add("多组斥医嘱");
                                break;
                            default:
                                break;
                        }
                    }
                }
            }
        } else {
            String key = code.trim() + serial.trim();
            YaoPinXinXi yp = dao.huoQuYaoPin(key);
            // 新开的医嘱才需要判断这个
            if (flag.equals("1")) {
                if (yp == null) {
                    return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "该医嘱下的药品，可能已经被停用了，请联系药剂科。");
                }
                yp.setDrugFlag(getDrugFlagByLargeCategories(yp.getCategoriesFlag()));

                YaoPinXinXi disable = dao.huoQuJinYongXinXi(key, groupNo);

                if (disable != null && disable.getVisibleFlagZy() == 1) {
                    return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "该药品禁止住院使用。");
                }
                if (StringUtil.notBlank(deptCode)) {
                    if (dao.restrictedUseInTheDepartment(code.trim(), deptCode) > 0) {
                        return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "该药品禁止在患者所在的科室使用。");
                    }
                }
                Integer yiShenDengJi = dao.huoQuYiShenDengJi(TokenUtil.getInstance().getTokenUserId());
                int yiShen = yiShenDengJi == null ? 0 : yiShenDengJi;

                int superior = 0;

                if (StringUtil.notBlank(seniorDoctor) && !"null".equals(seniorDoctor)) {
                    Integer superiorRank = dao.huoQuYiShenDengJi(seniorDoctor);
                    superior = superiorRank == null ? 0 : superiorRank;
                }

                if (yp.getYpLevel() > yiShen && yp.getYpLevel() > superior) {
                    permissionPrompt = true;
                }

                if (yp.getKjywFlag() == 1) {
                    prompt.add("抗菌药物，需填写抗菌药物医嘱附注");
                }
                if (yp.getSelfFlagYb() == 1) {
                    prompt.add("该药品医保自费药品，如符合条件请填写记账，不是请填写自费");
                }
                if (StringUtil.isBlank(yp.getNationalCode())) {
                    prompt.add("该药品医保没有匹配医保码");
                } else {
                    prompt.add(String.format("药品医保码为：【%s】", yp.getNationalCode()));
                }
                if (disable != null && disable.getStockAmount() != null && BigUtils.bigXiaoYu(disable.getStockAmount(), 10)) {
                    prompt.add(String.format("该药品剩余数量为:【%s】", disable.getStockAmount().stripTrailingZeros().toPlainString()));
                }
                if (yp.getPsFlag() == 1) {
                    prompt.add("此药品为皮试药品");
                }
                flagEquals1AddPrompt(prompt, yp.getJbFlag(), "该药品为【国家基本药物】");
                flagEquals1AddPrompt(prompt, yp.getHighWarningFlag(), "该药品为【高警示药品】");
                flagEquals1AddPrompt(prompt, yp.getWinningBidderFlag(), "该药品为【国家组织药品集中采购中标药品】");
                flagEquals1AddPrompt(prompt, yp.getFocusMonitorFlag(), "该药品为【重点监控药品】");
            }
            List<YaoPingJiLiang> yaoPingJiLiang = new ArrayList<>();
            if (StringUtil.notBlank(yp.getWeighUnit())) {
                yaoPingJiLiang.add(new YaoPingJiLiang(yp.getWeighUnit(), yp.getWeighUnitName(), yp.getWeight()));
            }
            if (StringUtil.notBlank(yp.getVolUnit())) {
                yaoPingJiLiang.add(new YaoPingJiLiang(yp.getVolUnit(), yp.getVolUnitName(), yp.getVolum()));
            }
            if (StringUtil.notBlank(yp.getPackUnit())) {
                yaoPingJiLiang.add(new YaoPingJiLiang(yp.getPackUnit(), yp.getPackUnitName(), yp.getPackSize()));
            }
            map.put("yaoPingJiLiang", yaoPingJiLiang);
            map.put("data", yp);
        }
        map.put("prompt", prompt);
        map.put("permissionPrompt", permissionPrompt);
        return ResultVoUtil.success(map);
    }


    public DrugCache.YpInfo getYaoPingJiLiang(String code, String serial) {
        String key = code.trim() + serial.trim();
        return drugCache.get(key);
    }

    private void flagEquals1AddPrompt(List<String> prompt, String flag, String message) {
        if ("1".equals(flag)) {
            prompt.add(message);
        }
    }


    private String getDrugFlagByLargeCategories(String val) {
        if (StringUtil.isBlank(val)) {
            return "z";
        }
        switch (val) {
            case "0":
                return "d";
            case "1":
                return "i";
            default:
                return "z";
        }
    }


    /**
     * 获取医嘱频率
     *
     * @return 返回频率
     */
    public ResultVo<List<GetDropdownBox>> getFrequency() {
        return ResultVoUtil.success(dao.selectFrequency());
    }

    /**
     * @return 给药方式
     */
    public ResultVo<List<SelectV2>> getSupplyType() {
        return ResultVoUtil.success(dao.selectSupplyType());
    }

    /**
     * 获取执行科室
     *
     * @param code 五笔，拼音，中文，编码
     * @return 返回对应的数据
     */
    public ResultVo<List<GetDropdownBox>> huoQuZhiXinKeShi(String code) {
        return ResultVoUtil.success(dao.huoQuZhiXinKeShi(StringUtil.isContainChinese(code)));
    }

    /**
     * 这里是校验模板的数据
     *
     * @param param 模板数据
     * @return 返回提示信息
     */
    public ResultVo<Map<String, Object>> singleDataCheck(XinZhenYiZhu param) {
        param.getList().get(0).setActOrderNo(new BigDecimal(param.getList().get(0).getId()));
        YiZhuCheckData checkData = new YiZhuCheckData(dao);
        checkData.init(param.getList(), null);
        Map<String, Object> errorMessage = checkData.startCheck(null);
        Map<String, Object> returnMap = new HashMap<>();
        returnMap.put("data", param.getList().get(0));
        returnMap.put("message", errorMessage.get(param.getList().get(0).getId()));
        return ResultVoUtil.success(returnMap);
    }


    public ResultVo<String> doesTheTemplateExist(String name) {
        if (dao.duplicateTemplateName(name, TokenUtil.getInstance().getTokenUserId()) == 0) {
            return ResultVoUtil.success();
        }
        return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "模板名称重复");
    }

    /**
     * 保存模板 数据
     *
     * @param param 模板数据
     * @return 成功
     */
    public ResultVo<String> saveTemplate(YzOrderPattern param) {
        // 如果名字重复了，那么就修改原来的模板
        YzOrderPattern yzOrderPattern = dao.yuanLaiDeMuBanBianMa(param.getPatternName(), TokenUtil.getInstance().getTokenUserId());
        UserInfo userInfo = userCache.getUserInfoByToken();

        if (null == yzOrderPattern) {
            yzOrderPattern = new YzOrderPattern();
        }

        String patternCode = yzOrderPattern.getPatternCode();

        // 有原来的模板名称而且 还要是自己创建的才能删除,否则就只能创建新的模板了
        if (StringUtil.notBlank(patternCode) && userInfo.getCode().equals(yzOrderPattern.getInputId())) {
            // 更新的时候先删除模板 原来的模板
            dao.shanChuLaoMuBan(patternCode);
            param.setPatternCode(patternCode);
        } else {
            // 设置新的模板号
            param.setPatternCode(publicServer.getPatternCode());
        }

        String py = PingYinUtils.pyShouZiMuDaXie(param.getPatternName());
        String wb = PingYinUtils.getWBCode(param.getPatternName());

        param.setPyCode(py.length() > 9 ? py.substring(0, 9) : py);
        param.setDCode(wb.length() > 9 ? wb.substring(0, 9) : wb);

        param.setInputId(TokenUtil.getInstance().getTokenUserId());
        param.setDeptCode(userInfo.getDeptCode());
        dao.chaRuMuBan(param);

        Map<String, XinZhenYzActOrder> map = param.getList().stream().collect(Collectors.toMap(XinZhenYzActOrder::getId, a -> a, (k1, k2) -> k1));

        for (XinZhenYzActOrder item : param.getList()) {
            // 设置模板号
            item.setActOrderNo(publicServer.getPatternOrderCode());
            if (item.getParentNo() != null && map.containsKey(item.getParentNo().stripTrailingZeros().toPlainString())) {
                item.setParentNo(map.get(item.getParentNo().stripTrailingZeros().toPlainString()).getActOrderNo());
            }
        }
        dao.chaRuMuBanShuJu(param.getList(), param.getPatternCode());
        return ResultVoUtil.success();
    }

    /***
     * 获取项目信息
     * @param xiangMuCode 项目编码
     * @return 返回数据
     */
    public Map<String, List<XinZhenYzActOrder>> getProjectInformation(Set<String> xiangMuCode) {
        if (!xiangMuCode.isEmpty()) {
            return dao.huoQuXiangMuXinXi(xiangMuCode).stream().collect(Collectors.groupingBy(item -> item.getOrderCode().trim()));
        }
        return new HashMap<>(0);
    }

    /**
     * 获取药品信息
     *
     * @param yaoPingCode 药品编码
     * @return 返回数据
     */
    public Map<String, XinZhenYzActOrder> getDrugInformation(Set<String> yaoPingCode, String dept) {
        if (!yaoPingCode.isEmpty()) {
            return dao.huoQuYaoPinXinXi(yaoPingCode, dept).stream().collect(Collectors.toMap(item -> item.getOrderCode().trim() + item.getSerial().trim() + item.getGroupNo(), a -> a, (k1, k2) -> k1));
        }
        return new HashMap<>(0);
    }


    /**
     * 获取医嘱录入的模板
     *
     * @param code         模板编码
     * @param deptCode     科室编码
     * @param muBanLeiXing 项目类型
     * @param currentPage  当前页
     * @param total        总数
     * @return 返回模板
     */
    public ResultVo<IPage<YzOrderPattern>> huoQuYiZhuMuBan(String code, String deptCode, Integer muBanLeiXing, long currentPage, long total) {
        IPage<YzOrderPattern> page = new Page<>();
        if (total == 0) {
            page.setTotal(dao.huoQuMuBanTotal(StringUtil.isContainChinese(code), TokenUtil.getInstance().getTokenUserId(), deptCode, muBanLeiXing));
        }
        page.setRecords(dao.huoQuMuBan(StringUtil.isContainChinese(code), TokenUtil.getInstance().getTokenUserId(), deptCode, muBanLeiXing, currentPage));
        return ResultVoUtil.success(page);
    }

    /**
     * 获取 我的医嘱模板的最大医嘱码
     *
     * @return 最大排序码
     */
    public ResultVo<Integer> getDoctorSOrderTemplateMaxSortNo() {
        Integer sortCode = dao.getMyTemplateMaxSortNo(TokenUtil.getInstance().getTokenUserId());
        return ResultVoUtil.success(sortCode == null ? 0 : sortCode);
    }


    private String getActOrderNo() {
        Random random = new Random();
        String a = String.valueOf(random.nextInt(5) + 1);
        String b = String.valueOf(random.nextInt(99999));
        return a + b;
    }

    /**
     * 获取模板数据
     *
     * @param code 模板的编码
     * @return 返回数据
     */
    public ResultVo<List<YzActOrder>> huoQuMuBanShuJu(String code) {
        List<YzActOrder> muBanShuJu = dao.huoQuMuBanShuJu(code);
        Map<BigDecimal, YzActOrder> map = new HashMap<>(muBanShuJu.size());
        List<YzActOrder> tree = new ArrayList<>();
        for (YzActOrder item : muBanShuJu) {
            item.setId(getActOrderNo());
            if (item.getParentNo() == null) {
                tree.add(item);
            }
            map.put(item.getActOrderNo(), item);
        }
        for (YzActOrder item : muBanShuJu) {
            YzActOrder yzActOrder = map.get(item.getParentNo());
            if (yzActOrder != null) {
                item.setParentNo(new BigDecimal(yzActOrder.getId()));
                item.setIsChildren(true);
                if (yzActOrder.getChildren() == null) {
                    yzActOrder.setChildren(new ArrayList<>());
                }
                yzActOrder.getChildren().add(item);
                // 没有副医嘱的就返回到最上层
            } else if (!tree.contains(item)) {
                item.setParentNo(null);
                tree.add(item);
            }
        }
        return ResultVoUtil.success(tree);
    }


    /**
     * 删除医嘱模板
     *
     * @param patternCode 模板的编码
     * @return 提示
     */
    public ResultVo<String> deleteADoctorSOrderTemplate(String patternCode) {
        if (StringUtil.isBlank(patternCode)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "模板编号为空。");
        }
        YzOrderPattern yzOrderPattern = dao.huoQuMuBanXinXi(patternCode);
        EntityStringTrim.beanAttributeValueTrim(yzOrderPattern);
        if (yzOrderPattern == null) {
            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有查询到对应的模板信息。");
        }
        String userId = TokenUtil.getInstance().getTokenUserId();
        List<Integer> role = publicServer.getRoleCode().getData();
        if (publicServer.needRule(role, RoleCode.PHYSICIAN_S_ORDER_TEMPLATEEDIT)) {
            return startDeletingTemplates(patternCode);
        }
        if (userId.equals(yzOrderPattern.getInputId())) {
            return startDeletingTemplates(patternCode);
        }
        //   主任可以删除本科室的任意模板
        if (publicServer.needRule(role, RoleCode.DIRECTOR) && dao.userDeptCode(userId).equals(yzOrderPattern.getDeptCode())) {
            return startDeletingTemplates(patternCode);
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "您没有权限删除这个模板。");
    }

    /**
     * 删除父模板以及下面的子模板 数据
     *
     * @param patternCode 模板编码
     */
    private ResultVo<String> startDeletingTemplates(String patternCode) {
        dao.shanChuMuBan(patternCode);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "删除成功。");
    }

    /**
     * 收藏医嘱模板或者取消收藏
     * 如果以及收藏了就删除,没有就收藏
     *
     * @param patternCode 模板号
     * @return 提示
     */
    public ResultVo<String> collectDoctorSOrderTemplate(String patternCode) {
        String userId = TokenUtil.getInstance().getTokenUserId();
        String saveTheDoctorSOrderNumber = dao.whetherToSaveTheDoctorSOrderTemplate(patternCode, userId);
        if (StringUtil.notBlank(saveTheDoctorSOrderNumber)) {
            dao.shanChuMuBan(saveTheDoctorSOrderNumber);
            return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "已取消删除。");
        } else {
            YzOrderPattern yzOrderPattern = dao.huoQuMuBanXinXi(patternCode);
            EntityStringTrim.beanAttributeValueTrim(yzOrderPattern);
            dao.chaRuShouCang(publicServer.getPatternCode(), yzOrderPattern.getPatternName() + "(收藏)", yzOrderPattern.getPyCode(), yzOrderPattern.getDCode(), dao.userDeptCode(userId), userId, yzOrderPattern.getPatternCode());
            return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "收藏成功。");
        }
    }


    /**
     * 删除或修改模板
     *
     * @param patternCode 模板点吗
     * @param patternName 模板名称
     * @param sortNo      排序号
     * @param flag        标志 1-修改 2- 删除 3-收藏和取消收藏
     * @return 返回给前端提示
     */
    public ResultVo<String> muBanCaoZuo(String patternCode, String patternName, String deptCode, Integer sortNo, Integer flag) {
        if (StringUtil.isBlank(patternCode)) {
            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "模板编码为空。");
        }
        YzOrderPattern yzOrderPattern = dao.huoQuMuBanXinXi(patternCode);
        if (yzOrderPattern == null) {
            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有查询到对应的模板信息。");
        }
        EntityStringTrim.beanAttributeValueTrim(yzOrderPattern);
        String inputId = TokenUtil.getInstance().getTokenUserId();
        List<Integer> role = publicServer.getRoleCode().getData();
        // 管理员 和 医务部的无视 规则
        if (!role.contains(1) && !role.contains(38) && flag != 3) {
            // 只有模板在不等于 自己的时候触发
            if (!inputId.equals(yzOrderPattern.getInputId())) {
                if ("2".equals(yzOrderPattern.getInputType()) && !role.contains(11)) {
                    return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "该模板为科室模板您没有权限修改或删除，请联系科主任进行修改。");
                } else if ("1".equals(yzOrderPattern.getInputType())) {
                    return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "该模板为全院模板，无法删除或修改。");
                }
            }
        }
        if (flag == 1) {
            if (StringUtil.isBlank(patternName)) {
                return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "模板名称不能为空。");
            }
            if (patternName.trim().equals(yzOrderPattern.getPatternName().trim()) && sortNo.equals(yzOrderPattern.getSortNo())) {
                return ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, "数据没有变化，请勿点击。");
            }
            dao.genXingMuBan(patternName.trim(), PingYinUtils.pyShouZiMuDaXie(patternName), PingYinUtils.getWBCode(patternName), yzOrderPattern.getPatternCode(), sortNo);
            return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "修改成功。");
        } else if (flag == 2) {
            // 删除父模板以及下面的子模板 数据
            dao.shanChuMuBan(yzOrderPattern.getPatternCode());
            return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "删除成功。");
        } else if (flag == 3) {
            // 收藏模板
            String collectCode = dao.chongFuShouCang(inputId, patternCode);
            if (collectCode == null) {
                dao.chaRuShouCang(publicServer.getPatternCode(), yzOrderPattern.getPatternName() + "(收藏)", yzOrderPattern.getPyCode(), yzOrderPattern.getDCode(), deptCode, inputId, yzOrderPattern.getPatternCode());
                return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "收藏成功。");
            } else {
                dao.shanChuMuBan(yzOrderPattern.getPatternCode());
                return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "已取消收藏。");
            }
        }
        return ResultVoUtil.success();
    }

    /**
     * 设置患者三级医生
     *
     * @param param 参数
     * @return 返回值
     */
    public ResultVo<String> saveTheThirdLevelDoctor(Overview param) {
        dao.updateTheThirdLevelDoctor(param);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
    }

    /**
     * 设置父子医嘱
     *
     * @param param 主医嘱 和 多个子医嘱
     * @return 返回数据
     */
    public ResultVo<List<XinZhenYzActOrder>> associateOrders(XinZhenYiZhu param) {
        XinZhenYzActOrder order = dao.getActOrderNoOne(param.getActOrderNo());
        if (order.getParentNo() != null) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "操作失败，父医嘱不能为子医嘱。");
        }
        Set<BigDecimal> orderList = new HashSet<>();
        orderList.add(order.getActOrderNo());

        param.getAssociatedGroup().forEach(item -> {
            dao.associateOrders(item, order);
            orderList.add(item);
        });

        QueryWrapper<?> qw = new QueryWrapper<>();
        qw.in("a.act_order_no", orderList);

        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "关联成功。", dao.selectOrderNo(qw));
    }

    /**
     * 确认 出院带药医嘱
     *
     * @param patNo 住院号
     * @param times 住院次数
     * @return
     */
    public ResultVo<Map<String, Object>> confirmTheDoctorSOrderWithMedicine(String patNo, Integer times) {

        // 判断是否开了出院医嘱后的医嘱
        if (!yzConfig.getPrescribeMedicalAdviceAfterDischarge()) {
            YzActOrder ourOrderInfo = dao.selectFinallyOutOrderInfo(patNo, times);
            if (ourOrderInfo != null) {
                if (dao.prescribeMedicalAdviceAfterDischarge(patNo, times, ourOrderInfo.getStartTime(), ourOrderInfo.getActOrderNo()) > 0) {
                    return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "有医嘱开在了出院医嘱后无法确认。");
                }
            }
        }

        QueryWrapper<?> qw = new QueryWrapper<>();
        String 出院带药 = "007";
        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.supply_code,'0')", 出院带药);
        XinZhenYiZhu patInfo = dao.queryPatientInfo(patNo, times);
        patInfo.setList(dao.selectOrderNo(qw));

        if (ListUtil.isBlank(patInfo.getList())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "未查询到医嘱。");
        }

        String userCode = TokenUtil.getInstance().getTokenUserId();
        // 出院带药需要生成药单 key 是不同的药房。不同的药房就要

        YiZhuCheckData checkData = new YiZhuCheckData(dao)
                .checkForRestrictedMedication();

        checkData.init(patInfo.getList(), patInfo);
        Map<String, Object> map = checkData.startCheck(null);

        if (checkData.getPassTheAudit()) {
            sendAMessageToTheNurse(patInfo, userCode, patInfo, "出院带药");
            Date now = new Date();
            ListUtil.batchList(patInfo.getList(), YiZhuLuRuDao.class, (mapper, item) -> {
                if (StringUtil.notBlank(item.getSuperiorDoctor())) {
                    mapper.takeMedicineAfterDischargeStopOrderAndSuperiorDoctor(item.getActOrderNo(), item.getSuperiorDoctor(), now);
                } else {
                    // 出院带药 确认了直接停止医嘱
                    mapper.takeMedicineAfterDischargeStopOrder(item.getActOrderNo(), userCode, now);
                }

            });
            return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
        } else {
            return ResultVoUtil.fail(ExceptionEnum.ERROR_MESSAGE, "请修改有错误的医嘱。", map);
        }

    }

    public void insertATemplate(List<XinZhenYzActOrder> list, XinZhenYiZhu patInfo) {
        String userCode = TokenUtil.getInstance().getTokenUserId();
        list.forEach(item -> {
            dao.insertEntryOrder(patInfo, item, userCode);
        });
    }

    private void revertToTheDefaultState(XinZhenYzActOrder param, UserInfo us, BigDecimal parentNo) {
        param.setActOrderNo(publicServer.getActOrderNo());
        param.setStatusFlag("1");
        Date newDate = new Date();
        param.setOrderTime(newDate);
        param.setStartTime(newDate);
        param.setEndTime(null);
        param.setEnterOper(us.getCode());
        param.setSigner("");
        param.setModifier("");
        param.setParentNo(parentNo);
    }


    public ResultVo<JSONObject> copyOrder(CopyOrder copyOrder) {
        QueryWrapper<?> qw = new QueryWrapper<>();
        qw.eq("a.act_order_no", copyOrder.getActOrderNo());
        List<XinZhenYzActOrder> yiZhuList = dao.selectOrderNo(qw);
        if (ListUtil.isBlank(yiZhuList)) {
            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "原医嘱已经不存在了。");
        }
        // 个人信息
        UserInfo us = userCache.getUserInfoByToken();

        // 存放生成的医嘱容器
        List<BigDecimal> orderList = new ArrayList<>();

        // 原来的医嘱
        XinZhenYzActOrder fatherOrder = yiZhuList.get(0);
        // 设置默认值
        revertToTheDefaultState(fatherOrder, us, null);
        fatherOrder.setExecUnit(copyOrder.getDeptCode());
        fatherOrder.setFrequCode(copyOrder.getFrequCode());
        orderList.add(fatherOrder.getActOrderNo());
        // 查询子医嘱
        QueryWrapper<?> childQw = new QueryWrapper<>();
        // 根据父医嘱的住院号和住院次数查询医嘱，设置默认值会重新生成 actOrderNo ，所以需要使用 CopyOrder 中的 actOrderNo
        childQw.eq("a.parent_no", copyOrder.getActOrderNo());
        childQw.eq("a.inpatient_no", fatherOrder.getInpatientNo());
        childQw.eq("a.admiss_times", fatherOrder.getAdmissTimes());

        // 保存的子医嘱
        List<XinZhenYzActOrder> childOrderList = dao.selectOrderNo(childQw);

        // 存放医嘱容器
        List<XinZhenYzActOrder> addOrderList = new ArrayList<>();
        // 存放父医嘱
        addOrderList.add(fatherOrder);

        // 设置子医嘱默认值
        if (ListUtil.notBlank(childOrderList)) {
            childOrderList.forEach(item -> {
                item.setExecUnit(copyOrder.getDeptCode());
                item.setFrequCode(copyOrder.getFrequCode());
                revertToTheDefaultState(item, us, fatherOrder.getActOrderNo());
                orderList.add(item.getActOrderNo());
                addOrderList.add(item);
            });
        }

        // 获取患者信息
        XinZhenYiZhu patInfo = dao.queryPatientInfo(copyOrder.getInpatientNo(), copyOrder.getAdmissTimes());
        insertATemplate(addOrderList, patInfo);

        JSONObject js = getNewOrderData(orderList);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "复制成功。", js);
    }

    @NotNull
    private JSONObject getNewOrderData(List<BigDecimal> orderList) {
        QueryWrapper<?> newList = new QueryWrapper<>();
        newList.in("a.act_order_no", orderList);
        newList.orderByAsc("a.act_order_no");
        List<XinZhenYzActOrder> newOrderList = getOrderList(dao.selectOrderNo(newList));
        JSONObject js = new JSONObject();
        js.put("list", orderList);
        js.put("data", newOrderList);
        return js;
    }


    public ResultVo<List<ZyDetailCharge>> queryFeeByOrderNo(BigDecimal actOrderNo) {
        XinZhenYzActOrder yz = dao.getActOrderNoOne(actOrderNo.stripTrailingZeros().toPlainString());
        if (yz == null) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "该医嘱未产生费用。");
        }
        List<ZyDetailCharge> feeList = dao.selectOrderFee(yz);
        return ResultVoUtil.success(feeList);
    }

    public ResultVo<String> oneClickStopOrder(OneClickOrder param) {
        param.setOrderNo(publicServer.getActOrderNo());
        param.setNowDate(new Date());
        param.setUserCode(TokenUtil.getInstance().getTokenUserId());
        return executeOneClickStopOrder(param);
    }

    public ResultVo<String> executeOneClickStopOrder(OneClickOrder param) {
        // 10507 固定医嘱号
        int count = dao.oneClickStopOrder(param, param.getUserCode());
        if (count > 0) {
            // 生成医嘱
            XinZhenYiZhu patInfo = dao.queryPatientInfo(param.getPatNo(), param.getTimes());
            dao.insertOneClickStopOrder(param, patInfo);
            return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "操作成功，正在执行的长期医嘱停止到了【" + param.getDateStr() + "】");
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有需要停止的长期医嘱操作失败。");
    }

    /**
     * 上级医生登录
     *
     * @return 信息
     */
    public ResultVo<DoctorAuthRest> doctorAuthorizationLogin(DoctorAuthParams userInfo) {
        DoctorAuthRest u;
        if (StrUtil.isNotBlank(userInfo.getPassword())) {
            userInfo.setPassword(SecureUtil.md5(userInfo.getPassword()));
            u = dao.doctorAuthorizationLogin(userInfo);
        } else {
            u = dao.doctorAuthorizationLoginByEmrSignPwd(userInfo);
        }

        if (u == null) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "密码错误或用户不存在。");
        }

        // 如果是项目
        if (userInfo.getDrugCode().endsWith("_00")) {
            return ResultVoUtil.success(u);
        }

        Integer drugLeven = dao.selectYpLevel(userInfo.getDrugCode());

        if (drugLeven > (u.getDoctorLevel() + 1)) {
            return ResultVoUtil.success(ExceptionEnum.LOGICAL_ERROR, StrUtil.format("该医生等级不足，药品等级【{}】，医生等级：【{}】", drugLeven, u.getDoctorLevel()));
        }

        return ResultVoUtil.success(u);
    }


    public ResultVo<String> updateOrderInstruction(BigDecimal orderNo, String str) {
        dao.updateOrderInstruction(orderNo, str);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "更新成功。");
    }

    public ResultVo<JSONObject> copyTableOrder(XinZhenYiZhu param) {
        if (StringUtil.isBlank(param.getInpatientNo())) {
            return ResultVoUtil.fail(ExceptionEnum.ERROR_MESSAGE, "请先选择患者.");
        }

        XinZhenYiZhu patInfo = dao.queryPatientInfo(param.getInpatientNo(), param.getAdmissTimes());
        if (patInfo == null) {
            return ResultVoUtil.fail(ExceptionEnum.ERROR_MESSAGE, "请先选择患者.");
        }

        List<XinZhenYzActOrder> list = param.getList();
        Queue<BigDecimal> queue = new LinkedList<>();
        // 保存 老 新 医嘱
        Map<BigDecimal, BigDecimal> map = new HashMap<>();

        for (XinZhenYzActOrder item : list) {
            BigDecimal orderNo = publicServer.getActOrderNo();
            queue.offer(orderNo);
            map.put(item.getActOrderNo(), orderNo);
        }

        List<BigDecimal> returnOrderList = new LinkedList<>();

        String userCode = TokenUtil.getInstance().getTokenUserId();

        ListUtil.batchList(list, YiZhuLuRuDao.class, (mapper, item) -> {
            item.setActOrderNo(queue.poll());
            if (item.getParentNo() != null) {
                item.setParentNo(map.get(item.getParentNo()));
            }
            returnOrderList.add(item.getActOrderNo());
            mapper.insertEntryOrder(patInfo, item, userCode);
        });

        JSONObject js = getNewOrderData(returnOrderList);
        return ResultVoUtil.success(js);
    }

    public ResultVo<String> analyzeSiChargeLimit(SiLimitRequest request) {
        return ResultVoUtil.success(siChargeLimitService.analyzeSiChargeLimit(request));
    }

    public QueryWrapper<?> getConfirmQueryWrapper(String patNo, Integer times) {
        return new QueryWrapper<>().eq("a.inpatient_no", patNo)
                .eq("a.admiss_times", times)
                .eq("a.status_flag", "1")
                .eq("a.enter_oper", TokenUtil.getInstance().getTokenUserId())
                // 排除出院带药的医嘱
                .ne("isnull(a.self_buy,'0')", "4")
                .orderByAsc("a.act_order_no");
    }

    public ResultVo<String> confirmYzCheck(String patNo, Integer times, Integer ledgerSn) {
        QueryWrapper<?> qw = getConfirmQueryWrapper(patNo, times);

        Set<String> orderCode = dao.selectOrderCode(qw);

        if (orderCode == null || orderCode.isEmpty()) {
            return ResultVoUtil.success("OK");
        }

        List<String> collect = orderCode
                .stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        if (collect.isEmpty()) {
            return ResultVoUtil.success("OK");
        }

        SiLimitRequest request = SiLimitRequest.builder()
                .patNo(patNo).times(times)
                .ledgerSn(ledgerSn)
                .chargeList(collect)
                .build();

        return ResultVoUtil.success(siChargeLimitService.analyzeSiChargeLimit(request));
    }

    public ResultVo<Integer> getExceedingDischargeDays() {
        return ResultVoUtil.success(yzConfig.getExceedingDischargeDays());
    }

    /**
     * 更新手术病区的申请科室
     *
     * @param patNo 住院号
     * @param times 次数
     */
    public void updateChargeByWardCode(String patNo, Integer times) {
        if (StrUtil.isBlank(yzConfig.getShoushubingqu())) {
            return;
        }
        String opRecordWard = dao.getOpRecordWard(patNo, times);
        if (opRecordWard == null) {
            return;
        }
        dao.updateChargeWard(patNo, times, opRecordWard, yzConfig.getShoushubingqu());
    }

    /**
     * <el-option value="71" label="门诊" />
     * <el-option value="73" label="住院" />
     *
     * @return
     */
    public Map<String, List<YpZdGroupNameVo>> getYpZdGroup() {
        Map<String, List<YpZdGroupName>> value = extraCache.getYf();
        String now = DateUtil.formatDate(new Date(), "HH:mm:ss");
        Map<String, List<YpZdGroupNameVo>> map = new HashMap<>();
        for (Map.Entry<String, List<YpZdGroupName>> item : value.entrySet()) {
            item.getValue().forEach(i -> {
                YpZdGroupNameVo vo = new YpZdGroupNameVo();
                vo.setCode(i.getGroupNo());
                vo.setName(i.getGroupName());
                vo.setIsDefault(false);
                if (StrUtil.isNotBlank(i.getStartTime()) && StrUtil.isNotBlank(i.getEndTime())) {
                    vo.setIsDefault(DateUtil.isInTimeRange(now, i.getStartTime(), i.getEndTime()));
                }
                map.computeIfAbsent(item.getKey(), (k) -> new ArrayList<>()).add(vo);
            });
        }
        return map;
    }
}
