package thyyxxk.webserver.service.zhuyuanyisheng;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.SerializeUtil;
import cn.hutool.core.util.StrUtil;
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.checkerframework.checker.units.qual.C;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import thyyxxk.webserver.config.exception.BizException;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.constants.Capacity;
import thyyxxk.webserver.constants.Message;
import thyyxxk.webserver.dao.his.zhuyuanyisheng.CheckTheCallbackDao;
import thyyxxk.webserver.dao.his.zhuyuanyisheng.JianYanJianChaDao;
import thyyxxk.webserver.dao.his.zhuyuanyisheng.YiZhuLuRuDao;
import thyyxxk.webserver.entity.CodeName;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.datamodify.GetDropdownBox;
import thyyxxk.webserver.entity.dictionary.CyComboGrid;
import thyyxxk.webserver.entity.login.UserInfo;
import thyyxxk.webserver.entity.zhuyuanyisheng.jianyanjiancha.*;
import thyyxxk.webserver.entity.zhuyuanyisheng.jianyanjiancha.dto.JyJcCheckItemDto;
import thyyxxk.webserver.entity.zhuyuanyisheng.jianyanjiancha.vo.PrintYshReqVo;
import thyyxxk.webserver.entity.zhuyuanyisheng.jianyanjiancha.vo.ViewInspectionItemDetailsVo;
import thyyxxk.webserver.entity.zhuyuanyisheng.query.ChaXunJianChaHeJianYan;
import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.PatientTemp;
import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.XinZhenYiZhu;
import thyyxxk.webserver.http.websocket.SocketV2;
import thyyxxk.webserver.http.websocket.dto.WebSocketByUserCode;
import thyyxxk.webserver.service.PublicServer;
import thyyxxk.webserver.service.hutoolcache.UserCache;
import thyyxxk.webserver.utils.*;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 描述： 住院医生，检查申请
 * </p>
 *
 * @author xc
 * @date 2022-02-10 15:37
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class JianYanJianChaShenQingService {
    private final JianYanJianChaDao dao;
    private final PublicServer publicServer;
    private final YiZhuLuRuDao yiZhuLuRuDao;
    private final CheckTheCallbackDao checkTheCallbackDao;
    private final SocketV2 socketV2;
    private final UserCache userCache;
    public static final String JC_TYPE = "3";

    /*-------------------------------------------------------------- 下面是检查的逻辑 -----------------------------------------------------------------------------------------------------*/

    /**
     * 获取检查申请
     *
     * @param param 检查申请
     * @return 返回数据
     */
    public ResultVo<List<YshYjReq>> huoQuJianChaShenQing(ChaXunJianChaHeJianYan param) {
        QueryWrapper<?> qw = new QueryWrapper<>();
        qw.eq("inpatient_no", param.getPatNo());
        qw.eq("admiss_times", param.getTimes());
        qw.eq("req_type", JC_TYPE);

        if (StringUtil.notBlank(param.getOrderName())) {
            qw.like("order_name", param.getOrderName());
        }

        if (StringUtil.notBlank(param.getStartTime())) {
            qw.ge("start_time", param.getStartTime())
                    .le("start_time", param.getEndTime());
        }

        qw.orderByDesc("req_date");
        List<YshYjReq> list = dao.huoQuJianChaShenQingV2(qw);
        return ResultVoUtil.success(list);
    }

    public ResultVo<Map<String, Object>> huoQuShengQingXiangQing(Integer reqNo) {
        List<YshYjReq> reqList = dao.huoQuShengQingXiangQing(new QueryWrapper<YshYjReq>().eq("req_no", reqNo));
        if (ListUtil.isBlank(reqList)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_HTML_ERROR, "没有查询到有效信息，可能已经被删除了。");
        }

        YshYjReq req = reqList.get(0);

        Map<String, Object> map = new HashMap<>();
        StringBuilder zhuYiShiXiang = new StringBuilder();

        JcZdClass jc = dao.daYingXiangQing(req.getOrderType());

        if (jc == null) {
            jc = new JcZdClass();
            jc.setComm("检查申请单");
        }
        if (StringUtil.isBlank(jc.getComm())) {
            jc.setComm("检查申请单");
        }

        if (req.getReqType().trim().equals("2") && req.getClasses() != null && req.getClasses().equals("038")) {
            jc = new JcZdClass();
            jc.setComm("病理检验申请单");
        } else if (req.getReqType().trim().equals("2")) {
            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "非病理无需打印");
        }

        // 获取患者的住址和性别
        PatientTemp patient = dao.huoQuHuanZheXinXi(req.getInpatientNo());
        req.setSex(patient.getSex());
        // 地址
        req.setHomeStreet(patient.getHomeStreet());
        //联系电话
        req.setHomeTel(patient.getHomeTel());
        map.put("title", jc.getComm());

        Field[] fields = jc.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            // 输出属性名和属性值
            try {
                String key = field.getName();
                Object value = EntityStringTrim.getFieldValue(jc, key);
                if (key.startsWith("comment") && StringUtil.notBlank((String) value)) {
                    zhuYiShiXiang.append(((String) value).trim()).append("\n");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        map.put("mattersNeedingAttention", zhuYiShiXiang.toString());
        map.put("data", req);
        return ResultVoUtil.success(map);
    }

    public List<YshYjReq> huoQuShengQingXiangQingDemo(List<Integer> reqNo) {
        return dao.huoQuShengQingXiangQing(new QueryWrapper<YshYjReq>().in("req_no", reqNo));
//        if (ListUtil.isBlank(reqList)huoQuShengQingXiangQing) {
//            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_HTML_ERROR, "没有查询到有效信息，可能已经被删除了。");
//        }
//
//        YshYjReq req = reqList.get(0);
//
//        Map<String, Object> map = new HashMap<>();
//        StringBuilder zhuYiShiXiang = new StringBuilder();
//
//        JcZdClass jc = dao.daYingXiangQing(req.getOrderType());
//
//        if (jc == null) {
//            jc = new JcZdClass();
//            jc.setComm("检查申请单");
//        }
//        if (StringUtil.isBlank(jc.getComm())) {
//            jc.setComm("检查申请单");
//        }
//
//        if (req.getReqType().trim().equals("2") && req.getClasses() != null && req.getClasses().equals("038")) {
//            jc = new JcZdClass();
//            jc.setComm("病理检验申请单");
//        } else if (req.getReqType().trim().equals("2")) {
//            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "非病理无需打印");
//        }
//
//        // 获取患者的住址和性别
//        PatientTemp patient = dao.huoQuHuanZheXinXi(req.getInpatientNo());
//        req.setSex(patient.getSex());
//        // 地址
//        req.setHomeStreet(patient.getHomeStreet());
//        //联系电话
//        req.setHomeTel(patient.getHomeTel());
//        map.put("title", jc.getComm());
//
//        Field[] fields = jc.getClass().getDeclaredFields();
//        for (Field field : fields) {
//            field.setAccessible(true);
//            // 输出属性名和属性值
//            try {
//                String key = field.getName();
//                Object value = EntityStringTrim.getFieldValue(jc, key);
//                if (key.startsWith("comment") && StringUtil.notBlank((String) value)) {
//                    zhuYiShiXiang.append(((String) value).trim()).append("\n");
//                }
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//        }
//        map.put("mattersNeedingAttention", zhuYiShiXiang.toString());
//        map.put("data", req);
//        return ResultVoUtil.success(map);
    }

    public ResultVo<Object> printListReqNo(List<Integer> reqNo) {
        List<YshYjReq> reqList = dao.huoQuShengQingXiangQing(new QueryWrapper<YshYjReq>().in("req_no", reqNo));
        if (ListUtil.isBlank(reqList)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有查询到有效信息，可能已经被删除了。");
        }
        YshYjReq req = reqList.get(0);
        PatientTemp patient = dao.huoQuHuanZheXinXi(req.getInpatientNo());

        Map<String, List<YshYjReq>> orderType = reqList.stream().collect(
                Collectors.groupingBy(YshYjReq::getOrderType, Collectors.toList())
        );
        //临时缓存
        CacheOnce<JcZdClass> cacheOnce = new CacheOnce<>();
        // 返回值
        List<PrintYshReqVo> rstList = new ArrayList<>();
        for (Map.Entry<String, List<YshYjReq>> item : orderType.entrySet()) {
            YshYjReq itemYsh = item.getValue().get(0);
            PrintYshReqVo vo = printPageData(patient, itemYsh);
            JcZdClass temp = getCacheJcClass(cacheOnce, itemYsh.getOrderType());
            vo.setPrecautions(temp.getCommentAll());
            vo.setTitle(temp.getComm());
            item.getValue().forEach(i -> {
                PrintYshReqVo.Item voItem = new PrintYshReqVo.Item();
                voItem.setItemName(i.getOrderName());
                voItem.setReqNo(i.getReqNo());
                voItem.setInspectStuffName(i.getInspectStuffName());
                voItem.setInspectPartName(i.getInspectPartName());
                if (vo.getItems() == null) {
                    vo.setItems(new ArrayList<>());
                }
                vo.getItems().add(voItem);
            });
            rstList.add(vo);
        }
        return R.ok(rstList);
    }

    private JcZdClass getCacheJcClass(CacheOnce<JcZdClass> cacheOnce, String key) {
        return cacheOnce.get(key, (keyStr) -> {
            StringBuilder zhuYiShiXiang = new StringBuilder();
            JcZdClass jcZdClass = dao.daYingXiangQing(key);
            if (jcZdClass == null) {
                JcZdClass aa = new JcZdClass();
                aa.setCommentAll("");
                aa.setComm("检查申请单");
                return aa;
            }
            Map<String, Field> fieldMap = ReflectUtil.getFieldMap(JcZdClass.class);
            for (Map.Entry<String, Field> item : fieldMap.entrySet()) {
                String name = item.getKey();
                if (name.startsWith("comment")) {
                    String value = ReflectUtil.invoke(jcZdClass, StringUtil.getMethodName(name));
                    if (StringUtil.notBlank(value)) {
                        zhuYiShiXiang.append(value.trim()).append("\n");
                    }
                }
            }
            jcZdClass.setCommentAll(zhuYiShiXiang.toString());
            return jcZdClass;
        });
    }


    private PrintYshReqVo printPageData(PatientTemp patient, YshYjReq req) {
        return PrintYshReqVo.builder()
                .age(req.getPAge())
                .name(req.getPName())
                .sex(patient.getSex())
                .homeStreet(patient.getHomeStreet())
                .homeTel(patient.getHomeTel())
                .reqComment(req.getReqComment())
                .reqTzComment(req.getReqTzComment())
                .reqOtherResult(req.getReqOtherResult())
                .bedNo(req.getBedNo())
                .diagText(req.getDiagText())
                .inpatientNo(req.getInpatientNo())
                .responceTypeName(patient.getResponceTypeName())
                .reqDept(req.getReqDeptName())
                .reqDoctor(req.getReqDoctorName())
                .reqDate(DateUtil.format(req.getReqDate(), DatePattern.NORM_DATETIME_MINUTE_PATTERN))
                .reqWard(req.getReqWardName())
                .build();
    }

    public ResultVo<List<JcZdClass>> getTemplateGrouping(Integer itemType, Integer templateType) {
        QueryWrapper<?> qw = templateQueryWrapper(itemType, templateType);
        return ResultVoUtil.success(dao.getTemplate(qw));
    }

    public ResultVo<List<Map<String, String>>> getTemplateByCodeAndType(String code, String type) {
        return ResultVoUtil.success(dao.getTemplateByCodeAndType(code, type, type.equals("2") ? "jy_zd_item" : "jc_zd_item"));
    }

    private QueryWrapper<?> templateQueryWrapper(Integer itemType, Integer templateType) {
        QueryWrapper<?> qw = new QueryWrapper<>();
        qw.eq("c.req_type", itemType);
        if (templateType == 2) {
            qw.eq("c.op_id", TokenUtil.getInstance().getTokenUserId());
        } else {
            UserInfo info = userCache.getUserInfoByToken();
            qw.eq("c.tc_exec", info.getDeptCode());
        }
        return qw;
    }


    /**
     * @param itemType     3-检查 2-检验
     * @param templateType 2 个人 3 科室模板
     * @return
     */
    public ResultVo<List<JcZdClass>> getTemplate(Integer itemType, Integer templateType) {
        QueryWrapper<?> qw = templateQueryWrapper(itemType, templateType);
        List<JcZdClass> parentNode = dao.getTemplate(qw);
        Map<String, JcZdClass> map = parentNode
                .stream()
                .collect(Collectors.toMap(JcZdClass::getCode, a -> a, (k1, k2) -> k1));
        List<Map<String, String>> tempContent = dao.selectTemplateContent(qw);
        tempContent.forEach(item -> {
            JcZdClass jcZdClass = map.get(item.get("tc_no"));
            if (jcZdClass != null) {
                if (jcZdClass.getList() == null) {
                    jcZdClass.setList(new ArrayList<>());
                }
                jcZdClass.getList().add(item);
            }
        });
        return ResultVoUtil.success(parentNode);
    }


    /**
     * 删除检查或检验模板
     *
     * @param code     要删除的模板 code
     * @param deptCode 当前患者的科室编码
     * @return 返回提示
     */
    public ResultVo<String> shanShuJianChaMuBan(String code, String deptCode) {
        ZyTcYj yj = dao.jianChaLuRuRen(code);
        if (yj == null) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有找对应的记录可能已经被删除了。");
        }
        if (jianChaMuBanPanDuan(yj.getOpId(), yj.getTcExec(), deptCode)) {
            dao.shanChuJianChaMuBan(code);
            return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "您没有权限执行这个操作。");
    }

    /**
     * 检查模板的判断
     *
     * @param opId     录入人
     * @param tcExec   模板的科室
     * @param deptCode 当前用户的科室
     * @return boolean
     */
    public boolean jianChaMuBanPanDuan(String opId, String tcExec, String deptCode) {
        List<Integer> userRole = publicServer.getRoleCode().getData();
        // 医务部
        if (userRole.contains(38)) {
            return true;
        }
        // 科主任 可以删除自己科室任意模板
        if (userRole.contains(11) && tcExec.trim().equals(deptCode)) {
            return true;
        }
        // 普通的只能删除自己的
        return opId.trim().equals(TokenUtil.getInstance().getTokenUserId());
    }

    /**
     * 获取说明，模板的一下信息
     *
     * @param name        根据说明模板来 搜索
     * @param fenLei      分类
     * @param total       总数
     * @param currentPage 当前页
     * @return 返回提示
     */
    public ResultVo<IPage<YshZdYjTemplate>> huoMuShuoMingMuBan(String name, Integer fenLei, long total, long currentPage) {
        Page<YshZdYjTemplate> page = new Page<>(currentPage, 20, total == 0);
        page = dao.huoQuShuoMingMuBan(page, StringUtil.isContainChinese(name), fenLei, TokenUtil.getInstance().getTokenUserId());
        return ResultVoUtil.success(page);
    }

    /**
     * 对于说明模板的操作
     *
     * @param param 说明模板的内容
     * @return 返回提示
     */
    public ResultVo<String> shouMingMuBanChaoZuo(YshZdYjTemplate param) {
        switch (param.getLeiXing()) {
            case "修改":
                return xiuGaiMuBan(param, dao.muBanShuJu(param.getCode()));
            case "删除":
                return shanChuMuBan(dao.muBanShuJu(param.getCode()));
            case "新增":
                return xinZengShouMingMuBan(param);
            default:
                return ResultVoUtil.success();
        }

    }

    /**
     * 修改说明模板
     *
     * @param param 修改的数据
     * @param mb    原来的数据
     * @return 返回提示
     */
    private ResultVo<String> xiuGaiMuBan(YshZdYjTemplate param, YshZdYjTemplate mb) {
        if (publicServer.noNeedRule(38)) {
            if (!TokenUtil.getInstance().getTokenUserId().equals(mb.getOpId().trim())) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "该模板创建人不是你，无法操作。");
            }
        }
        dao.genXingShouMingMuBan(param.getJcText(), param.getName(),
                PingYinUtils.pyShouZiMuDaXie(param.getName()),
                PingYinUtils.getWBCode(param.getName()), param.getCode());
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
    }

    /**
     * 删除说明模板
     *
     * @param mb 通过数据库查找 原来的模板
     * @return 返回提示
     */
    private ResultVo<String> shanChuMuBan(YshZdYjTemplate mb) {
        List<Integer> userRole = publicServer.getRoleCode().getData();
        if (publicServer.noNeedRule(userRole, 38)) {
            if (TokenUtil.getInstance().getTokenUserId().equals(mb.getOpId().trim()) || (userRole.contains(11) && mb.getDeptCode().trim().equals(mb.getUserDeptCode().trim()))) {
                dao.shanChuShouMingMuBan(mb.getCode());
                return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
            } else {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "您没有权限修改。");
            }
        }
        dao.shanChuShouMingMuBan(mb.getCode());
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
    }

    /**
     * 新增说明模板
     *
     * @param param 新增的数据
     * @return 返回提示
     */
    private ResultVo<String> xinZengShouMingMuBan(YshZdYjTemplate param) {
        if (param.getWhFlag().trim().equals(JC_TYPE) && publicServer.noNeedRule(38)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "您没有权限创建全院模板。");
        }
        param.setCode(publicServer.getYjTemplateNo().toString());
        param.setPyCode(PingYinUtils.pyShouZiMuDaXie(param.getName(), 8));
        param.setDCode(PingYinUtils.getWBCode(param.getName(), 8));
        param.setOpId(TokenUtil.getInstance().getTokenUserId());
        dao.xinZengShouMingMuBan(param);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
    }


    /**
     * 搜索临床诊断
     *
     * @param name 搜索的名字
     * @return 返回搜索的数据
     */
    public ResultVo<List<GetDropdownBox>> diagnosisInOurHospital(String name) {
        return ResultVoUtil.success(dao.diagnosisInOurHospital(StringUtil.isContainChinese(name)));
    }

    /**
     * 判断检查模板是否有重复的
     *
     * @param name 名称
     * @return 返回有没有
     */
    public ResultVo<Boolean> jianChaJianYanMuBanMing(String name, String reqType) {
        return ResultVoUtil.success(!dao.huoQuJianChaJianYanChongFuMuBanMing(name, TokenUtil.getInstance().getTokenUserId(), reqType).isEmpty());
    }

    /**
     * 保存检查或检验模板
     *
     * @param param 数据
     * @return 返回提示
     */
    public ResultVo<String> baoCunJianChaJianYanMuBan(ZyTcYj param) {
        param.setOpId(TokenUtil.getInstance().getTokenUserId());
        param.setTcNo(publicServer.huoQuJianYanJianChaXuHao().toString());
        param.setPyCode(PingYinUtils.pyShouZiMuDaXie(param.getTcName(), 8));
        param.setDCode(PingYinUtils.getWBCode(param.getTcName(), 8));
        List<String> yuanShuJu = dao.huoQuJianChaJianYanChongFuMuBanMing(param.getTcName(), param.getOpId(), param.getReqType());
        if (ListUtil.notBlank(yuanShuJu)) {
            for (String s : yuanShuJu) {
                dao.shanChuJianChaMuBan(s);
            }
        }
        dao.chaRuJCJYMuBan(param);
        dao.chaRuJCJYMuBanNeiRong(param.getList(), param.getTcNo(), param.getReqType().trim());
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
    }

    public ResultVo<List<Integer>> baoCunJianYanJianCha(TianJiaJianChaJianYan param) {
        if (ListUtil.isBlank(param.getList())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "请选择需要保存的数据。");
        }
        XinZhenYiZhu huanZheXinXi = yiZhuLuRuDao.queryPatientInfo(param.getInpatientNo(), param.getAdmissTimes());
        publicServer.huanZheJieSuan(param.getInpatientNo(), param.getAdmissTimes());
        int index = 1;
        List<String> content = new ArrayList<>();
        StringBuilder cuoWuXinXi = new StringBuilder();

        Set<String> jcCodes = new HashSet<>();
        Set<String> jyCodes = new HashSet<>();

        Map<String, Integer> itemCount = new HashMap<>();

        for (YshYjReq item : param.getList()) {
            boolean isCheck = JC_TYPE.equals(param.getReqType());
            item.setForeachIndex(index);
            item.setReqType(param.getReqType());

            if (item.getQuantity() == null) {
                item.setQuantity(BigDecimal.ONE);
            }
            if (StringUtil.notBlank(item.getJzFlag()) && "0".equals(item.getJzFlag())) {
                item.setJzFlag(null);
            }
            if (StringUtil.notBlank(item.getYbSelfFlag()) && "0".equals(item.getYbSelfFlag())) {
                item.setYbSelfFlag(null);
            }
            if (StringUtil.isBlank(item.getOrderCode())) {
                cuoWuXinXi.append(baoCunCuoWuXinXi(index, "项目编码不能为空"));
            }
            if (StringUtil.isBlank(item.getOrderName())) {
                cuoWuXinXi.append(baoCunCuoWuXinXi(index, "项目名称不能为空"));
            }
            if (item.getStartTime() == null) {
                cuoWuXinXi.append(baoCunCuoWuXinXi(index, "检查时间不能为空"));
            } else if (DateUtil.shiJianDaXiao(huanZheXinXi.getAdmissDate(), item.getStartTime(), ">")) {
                cuoWuXinXi.append(baoCunCuoWuXinXi(index, "医嘱时间不能小于入院时间"));
            }
            if (StringUtil.isBlank(item.getExecDept())) {
                cuoWuXinXi.append(baoCunCuoWuXinXi(index, "执行科室不能为空。"));
            }
            if (isCheck) {
                jcCodes.add(item.getOrderCode());
                if (StringUtil.isBlank(item.getReqComment())) {
                    cuoWuXinXi.append(baoCunCuoWuXinXi(index, "病室摘要不能为空。"));
                }
                if (StringUtil.isBlank(item.getReqTzComment())) {
                    cuoWuXinXi.append(baoCunCuoWuXinXi(index, "体征信息不能为空。"));
                }
                if (StringUtil.isBlank(item.getReqOtherResult())) {
                    cuoWuXinXi.append(baoCunCuoWuXinXi(index, "相关辅检结果不能为空。"));
                }
                if (StringUtil.isBlank(item.getDiagCode())) {
                    cuoWuXinXi.append(baoCunCuoWuXinXi(index, "临床诊断不能为空。"));
                }
            } else {
                if (StringUtil.isBlank(item.getInspectStuff())) {
                    cuoWuXinXi.append(baoCunCuoWuXinXi(index, "标本不能为空。"));
                }
                jyCodes.add(item.getOrderCode());
            }
            if (cuoWuXinXi.length() > 0) {
                cuoWuXinXi.append("<br>");
            }
            content.add(String.format("%s：<span style='color:#409eff'>【%s】</span><br>" +
                                      "患者姓名：<span style='color:#409eff'>【%s】</span><br>" +
                                      "床位：<span style='color:#409eff'>【%s】</span>",
                    JC_TYPE.equals(item.getReqType()) ? "检查名" : "检验名",
                    item.getOrderName(), huanZheXinXi.getName(), huanZheXinXi.getBedNo()));
            index++;
        }

        Map<String, JyJcCheckItemDto> jc = getItemInfo(jcCodes, true);
        Map<String, JyJcCheckItemDto> jy = getItemInfo(jyCodes, false);

        List<String> needPart = new ArrayList<>();

        if (JC_TYPE.equals(param.getReqType())) {
            needPart = dao.selectBuWeiParentCode();
            List<YshYjReq> yshYjReqs = handleSurcharge(param.getList(), jc);
            param.getList().addAll(yshYjReqs);
        }

        for (int i = 0; i < param.getList().size(); i++) {
            YshYjReq item = param.getList().get(i);
            int finalI = item.getForeachIndex();
            if (item.getJzFlag() == null) {
                item.setJzFlag("0");
            }
            JyJcCheckItemDto itemInfo;
            // 检查
            if (JC_TYPE.equals(param.getReqType())) {
                itemInfo = jc.get(item.getOrderCode());
                if (needPart.contains(itemInfo.getOrderType())) {
                    if (StringUtil.isBlank(item.getInspectPart())) {
                        cuoWuXinXi.append(baoCunCuoWuXinXi(finalI, "此项目部位不能为空，请选择。"));
                    }
                }
            } else {
                // 检验
                itemInfo = jy.get(item.getOrderCode());
            }

            if (itemInfo == null) {
                cuoWuXinXi.append(baoCunCuoWuXinXi(finalI, "未查询到此项目，请删除"));
                continue;
            }

            Integer age = huanZheXinXi.patientAge();

            if (itemInfo.getDelFlag()) {
                cuoWuXinXi.append(baoCunCuoWuXinXi(finalI, "项目已停用：【" + itemInfo.getName() + "】"));
            }

            if (itemInfo.getZyFlag()) {
                cuoWuXinXi.append(baoCunCuoWuXinXi(finalI, "项目在住院已停用：【" + itemInfo.getName() + "】"));
            }

            if (itemInfo.getLimitTimes() != null && itemInfo.getLimitTimes() > 0) {
                Integer merge = itemCount.merge(item.getOrderCode(), 1, Integer::sum);
                if (merge > itemInfo.getLimitTimes()) {
                    item.setChargeFee(BigDecimal.ZERO);
                    item.setQuantity(BigDecimal.ZERO);
                } else {
                    item.setChargeFee(null);
                }
            }

            if (itemInfo.getGenderRestriction() != null && !itemInfo.getGenderRestriction().equals(huanZheXinXi.getSex())) {
                cuoWuXinXi.append(baoCunCuoWuXinXi(finalI, "患者的性别不能开这个项目。"));
            }

            if (itemInfo.getMaxAgeRestriction() != null && itemInfo.getMaxAgeRestriction() <= age) {
                cuoWuXinXi.append(baoCunCuoWuXinXi(finalI, "项目最大年龄限制" + itemInfo.getMaxAgeRestriction() + "岁，患者年龄不符合。"));
            }

            if (itemInfo.getMinAgeRestriction() != null && itemInfo.getMinAgeRestriction() >= age) {
                cuoWuXinXi.append(baoCunCuoWuXinXi(finalI, "项目最小年龄限制" + itemInfo.getMinAgeRestriction() + "岁，患者年龄不符合。"));
            }

            if (itemInfo.getItemInfoList() == null) {
                // 项目里面没有关联任何费用
                continue;
            }

            itemInfo.getItemInfoList().forEach(value -> {
                if (value.getItemDelFlag()) {
                    cuoWuXinXi.append(baoCunCuoWuXinXi(finalI, "项目已停用：【" + value.getName() + "】"));
                }
                if (value.getOrderDelFlag()) {
                    cuoWuXinXi.append(baoCunCuoWuXinXi(finalI, "医嘱已停用：【" + value.getName() + "】"));
                }
            });

        }

        if (StringUtil.notBlank(cuoWuXinXi.toString())) {
            throw new BizException(ExceptionEnum.LOGICAL_HTML_ERROR, String.valueOf(cuoWuXinXi));
        }
        List<Integer> reqNos = new ArrayList<>();
        // 生成 医嘱号和申请号
        for (YshYjReq item : param.getList()) {
            item.setActOrderNo(publicServer.getActOrderNo());
            item.setReqNo(publicServer.getReqPageNo());
            reqNos.add(item.getReqNo());
        }
        insertData(param, huanZheXinXi, content);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "操作成功", reqNos);
    }

    private Map<String, JyJcCheckItemDto> getItemInfo(Set<String> itemCodes, Boolean isCheck) {
        Map<String, JyJcCheckItemDto> collect = new HashMap<>();
        if (!itemCodes.isEmpty()) {
            QueryWrapper<?> qw = new QueryWrapper<>();
            qw.in("zy_order_code", itemCodes);
            String col = "";
            String tableName = "jy_zd_item";
            if (isCheck) {
                col = ",limit_times,(select rtrim(c.zy_order_code) from jc_zd_item c where c.code = jc_zd_item.surcharge) as surcharge," +
                      "(select rtrim(c.name) from jc_zd_item c where c.code = jc_zd_item.surcharge) as surcharge_name ";
                tableName = "jc_zd_item";
            }

            Map<String, JyJcCheckItemDto> info = dao.selectJyJcCheckItemDtoByOrderCode(qw, tableName, col)
                    .stream()
                    .collect(
                            Collectors
                                    .toMap(JyJcCheckItemDto::getCode, a -> a, (a, b) -> a)
                    );
            collect.putAll(info);
            QueryWrapper<?> qw2 = new QueryWrapper<>();
            qw2.in("a.order_code", itemCodes);
            List<JyJcCheckItemDto.ItemInfo> itemInfos = dao.selectItemDetailsByOrderCode(qw2);
            for (JyJcCheckItemDto.ItemInfo item : itemInfos) {
                JyJcCheckItemDto jyJcCheckItemDtos = collect.get(item.getCode());
                if (jyJcCheckItemDtos != null) {
                    if (jyJcCheckItemDtos.getItemInfoList() == null) {
                        jyJcCheckItemDtos.setItemInfoList(new ArrayList<>());
                    }
                    jyJcCheckItemDtos.getItemInfoList().add(item);
                }
            }
        }
        return collect;
    }

    private List<YshYjReq> handleSurcharge(List<YshYjReq> list, Map<String, JyJcCheckItemDto> jc) {
        List<YshYjReq> tmp = new ArrayList<>();
        Set<String> jcCodes = new HashSet<>();
        for (YshYjReq item : list) {
            if (!(item.getSurchargeFlag() != null && item.getSurchargeFlag())) {
                continue;
            }
            JyJcCheckItemDto jyJcCheckItemDto = jc.get(item.getOrderCode());
            if (jyJcCheckItemDto == null) {
                continue;
            }
            if (StrUtil.isBlank(jyJcCheckItemDto.getSurcharge())) {
                continue;
            }
            YshYjReq clone = EntityCopy.Copy(item, YshYjReq.class);
            jcCodes.add(jyJcCheckItemDto.getSurcharge());

            clone.setOrderCode(jyJcCheckItemDto.getSurcharge());
            clone.setOrderName(jyJcCheckItemDto.getSurchargeName());
            clone.setGroupName(jyJcCheckItemDto.getSurchargeName());
            tmp.add(clone);
        }
        Map<String, JyJcCheckItemDto> itemInfo = getItemInfo(jcCodes, true);
        jc.putAll(itemInfo);
        return tmp;
    }

    public void insertData(TianJiaJianChaJianYan param, XinZhenYiZhu patInfo, List<String> content) {
        String userCode = TokenUtil.getInstance().getTokenUserId();

        Date reqDate = new Date();

        dao.chaRuShenQing(param.getList(),
                patInfo.getInpatientNo(),
                patInfo.getName(),
                patInfo.getAge() + "岁",
                patInfo.getAdmissTimes(),
                patInfo.getBedNo(),
                userCode,
                // 这里是坑爹的反过来的
                patInfo.getWardCode(),
                patInfo.getDeptCode(),
                param.getReqType(),
                JC_TYPE.equals(param.getReqType()) ? "jc_zd_item" : "jy_zd_item",
                reqDate);

        dao.chaRuShenQingYiZhu(param.getList(),
                patInfo.getInpatientNo(),
                patInfo.getAdmissTimes(),
                userCode,
                patInfo.getDeptCode(),
                patInfo.getDeptCode(),
                PublicServer.getInfantFlag(patInfo.getInpatientNo()),
                reqDate);
        try {
            publicServer.faSongXiaoXi(patInfo, content, "新增检查/检验", TokenUtil.getInstance().getTokenUserId());
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }


    public String baoCunCuoWuXinXi(int index, String xinXi) {
        return String.format("第【%d】个%s<br>", index, xinXi);
    }

    /*-------------------------------------------------------------- 下面是检验的逻辑 -----------------------------------------------------------------------------------------------------*/
    public ResultVo<List<YshYjReq>> huoQuJianYan(@NotNull ChaXunJianChaHeJianYan param) {
        QueryWrapper<?> qw = new QueryWrapper<>();
        qw.eq("inpatient_no", param.getPatNo());
        qw.eq("admiss_times", param.getTimes());
        qw.eq("req_type", "2");

        if (StringUtil.notBlank(param.getStartTime())) {
            qw.ge("start_time", param.getStartTime())
                    .le("start_time", param.getEndTime());
        }
        if (StringUtil.notBlank(param.getOrderName())) {
            qw.like("order_name", param.getOrderName());
        }

        qw.orderByDesc("act_order_no");

        List<YshYjReq> list = dao.huoQuJianYanV2(qw);
        return ResultVoUtil.success(list);
    }

    public ResultVo<IPage<JcZdClass>> huoQuJianYanMing(long total, long currentPage, Integer leiXing) {
        IPage<JcZdClass> page = new Page<>(currentPage, 20, total == 0);
        if (leiXing == 1) {
            page = dao.jianYanFenLei(page);
            return ResultVoUtil.success(page);
        }
        return ResultVoUtil.success();
    }

    public ResultVo<List<GetDropdownBox>> biaoBenShuJu(String name) {
        return ResultVoUtil.success(dao.biaoBenOrBuWei(StringUtil.isContainChinese(name), "jy_zd_sample"));
    }

    public ResultVo<List<GetDropdownBox>> buWeiShuJu(String name) {
        return ResultVoUtil.success(dao.biaoBenOrBuWei(StringUtil.isContainChinese(name), "ysh_zd_part_code"));
    }

    public ResultVo<ViewInspectionItemDetailsVo> viewInspectionItemDetails(String orderCode, Boolean isCheck) {
        String tableName = isCheck ? "jc_zd_item" : "jy_zd_item";
        ViewInspectionItemDetailsVo info = dao.selectJcJyItem(tableName, orderCode);

        if (info == null) {
            return ResultVoUtil.success();
        }
        info.setItems(dao.viewInspectionItemDetails(orderCode));
        return ResultVoUtil.success(info);
    }

    public ResultVo<String> shanChuJianChaJianYan(Integer reqNo, String patNo, Integer times) {

        if (StringUtil.isBlank(patNo)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "住院号不能为空。");
        }

        YshYjReq yj = dao.huoQuJianYanJianCha(reqNo, patNo, times);
        if (yj == null) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有查询到该数据的具体信息，已经被删除了。");
        }

        int feeCount = dao.selectedFeeCount(yj);

        if (feeCount > 0) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "费用已上账无法删除。");
        }

        int feePatientFee = dao.selecePatientFee(yj);
        if (feePatientFee > 0) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医技已确费无法删除。");
        }

        dao.shanChuJianYanJianCha(reqNo, patNo, times);
        dao.shanChuYiZhu(yj.getActOrderNo());
        dao.cancellationOfConfirmedFees(yj, TokenUtil.getInstance().getTokenUserId());

        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
    }

    public ResultVo<Map<String, Object>> queryCheckTextResults(String patNo, String reqNo) {
        String jcId = dao.getJcIdByPatNo(patNo);
        if (StringUtil.isBlank(jcId)) {
            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有获取到患者的检查id");
        }
        YjJcRecord yjJcRecord = dao.getJcRecord(reqNo, jcId);
        if (yjJcRecord == null) {
            return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "没有查询到检查结果。");
        }
        Map<String, String> textJc = dao.selectTextJc(yjJcRecord.getReportNo());
        if (textJc != null) {
            yjJcRecord.setDiagnosticOpinion(textJc.get("text_zd"));
            yjJcRecord.setCheckWhatYouSee(textJc.get("text_jc"));
        }

        Map<String, Object> map = new HashMap<>(Capacity.TWO);
        map.put("record", yjJcRecord);
        return ResultVoUtil.success(map);
    }


    /**
     * 检验检查 树状图
     *
     * @return 返回树
     */
    public ResultVo<Map<String, List<JyJcItem>>> getJyJcZdTree() {
        Map<String, List<JyJcItem>> map = new HashMap<>(Capacity.TWO);
        map.put("jy", getJyTree());
        map.put("jc", getJcTree());
        return ResultVoUtil.success(map);
    }

    private List<JyJcItem> getJyTree() {
        // 把 检验 项目大类做map的key
        Map<String, JyJcItem> jyMap = dao.queryInspectionClassification().stream().collect(
                Collectors.toMap(JyJcItem::getCode, a -> a, (k1, k2) -> k1)
        );
        // 获取检验的详细项目
        List<JyJcItem> jyDetailedItems = dao.getJyDetailedItems();
        grouping(jyMap, jyDetailedItems);
        return new ArrayList<>(jyMap.values());
    }

    private List<JyJcItem> getJcTree() {
        Map<String, JyJcItem> jcMap = dao.queryCheckClassification().stream().collect(
                Collectors.toMap(JyJcItem::getCode, a -> a, (k1, k2) -> k1)
        );
        List<JyJcItem> jcDetailedItems = dao.selectJcDetailItems();
        grouping(jcMap, jcDetailedItems);
        // 检查项目还需要根据部位细分
        List<JyJcItem> jcTree = new ArrayList<>();
        for (Map.Entry<String, JyJcItem> item : jcMap.entrySet()) {
            // 没有节点就不要添加
            if (item.getValue().getChildren() != null) {
                JyJcItem temp = new JyJcItem();
                temp.setName(item.getValue().getName());
                temp.setChildren(new ArrayList<>());
                // 通过部位进行详细的区分
                Map<String, List<JyJcItem>> tempMap = item.getValue().getChildren().stream().collect(
                        Collectors.groupingBy(JyJcItem::getBw)
                );
                for (Map.Entry<String, List<JyJcItem>> entry : tempMap.entrySet()) {
                    // 如果部位是空的就直接添加到父节点
                    if (StringUtil.isBlank(entry.getKey())) {
                        JyJcItem temp1 = new JyJcItem();
                        temp.getChildren().addAll(entry.getValue());
                    } else {
                        // 添加到指定的部位
                        JyJcItem temp1 = new JyJcItem();
                        temp1.setName(entry.getKey());
                        temp1.setChildren(entry.getValue());
                        temp.getChildren().add(temp1);
                    }
                }
                jcTree.add(temp);
            }
        }

        return jcTree;
    }

    private void grouping(Map<String, JyJcItem> jyMap, List<JyJcItem> jyDetailedItems) {
        for (JyJcItem item : jyDetailedItems) {
            if (jyMap.containsKey(item.getClasses())) {
                JyJcItem tempMap = jyMap.get(item.getClasses());
                if (tempMap.getChildren() == null) {
                    tempMap.setChildren(new ArrayList<>());
                }
                tempMap.getChildren().add(item);
            }
        }
    }

    public ResultVo<YshYjReq> getAncillaryInformation(String patNo, Integer times) {
        return ResultVoUtil.success(dao.getAncillaryInformation(patNo, times));
    }

    /**
     * 检查厂商回调检查结果
     *
     * @param param 数据
     * @return 提示
     */
    public ResultVo<String> checkTheCallbacks(CheckTheCallbacks param) {
        QueryWrapper<CheckTheCallbacks> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("patient_uid", param.getPatientUid())
                .eq("patient_from", param.getPatientFrom());

        boolean exist = checkTheCallbackDao.selectCount(queryWrapper) > 0;
        List<Integer> reqNos = param.getReqNo();
        if (reqNos.isEmpty()) {
            param.setTopReqNo(-1);
        } else {
            param.setTopReqNo(reqNos.get(0));
            if (param.getPatientFrom() == 1) {
                for (Integer reqNo : reqNos) {
                    dao.setCheckPatientUid(param.getPatientUid(), reqNo);
                }
            }
        }

        try {
            if (exist) {
                checkTheCallbackDao.update(param, queryWrapper);
            } else {
                checkTheCallbackDao.insert(param);
            }
        } catch (Exception e) {
            log.info("检查回传错误：{}", e.getMessage());
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "数据库执行错误：" + e.getMessage());
        }

        if (param.getPatientFrom() == 1) {
            final CheckTheCallbacks temp = new CheckTheCallbacks() {{
                setPatientName(param.getPatientName());
                setReportTime(param.getReportTime());
                setReqNo(reqNos);
                setReqName(param.getReqName());
                setCheckDoctorName(param.getCheckDoctorName());
            }};

            JSONObject js = new JSONObject() {{
                put("data", temp);
                put("isAdd", !exist);
            }};

            socketV2.sendMessageByUserCode(
                    WebSocketByUserCode.create(Message.CHECK_THE_CALLBACKS, param.getReqDoctor().trim(), js.toJSONString())
            );
        }
        return ResultVoUtil.success(exist ? "更新成功。" : "回传成功。");
    }

    public ResultVo<List<String>> getJcIdByPatNo(String patNo) {
        return ResultVoUtil.success(dao.getJcIdByPatNoList(patNo));
    }

    public ResultVo<List<JianChaJieGuo>> getExamineDetail(String jcId) {
        List<JianChaJieGuo> res = dao.selectJieGuo(jcId);
        return ResultVoUtil.success(res);
    }

    public ResultVo<JSONObject> getExamineIllustrate(String orderCode, Boolean isCheck) {
        return ResultVoUtil.success(dao.getExamineIllustrate(orderCode, isCheck ? "jc_zd_item" : "jy_zd_item"));
    }

    public ResultVo<List<GetDropdownBox>> selectBuWeiAll() {
        return ResultVoUtil.success(dao.selectBuWeiAll());
    }

}

