package thyyxxk.webserver.service.zhuyuanyisheng;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
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.springframework.stereotype.Service;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.constants.GetDateFormat;
import thyyxxk.webserver.dao.his.zhuyuanyisheng.ShouShuShenQingDao;
import thyyxxk.webserver.dao.his.zhuyuanyisheng.YiZhuLuRuDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.datamodify.GetDropdownBox;
import thyyxxk.webserver.entity.dictionary.CodeName;
import thyyxxk.webserver.entity.zhuyuanyisheng.query.ChaXunJianChaHeJianYan;
import thyyxxk.webserver.entity.zhuyuanyisheng.shoushu.*;
import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.XinZhenYiZhu;
import thyyxxk.webserver.http.websocket.SocketV2;
import thyyxxk.webserver.service.PublicServer;
import thyyxxk.webserver.service.hutoolcache.ExtraCache;
import thyyxxk.webserver.utils.*;

import java.util.*;

/**
 * <p>
 * 描述： 手术申请
 * </p>
 *
 * @author xc
 * @date 2022-02-22 15:45
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class ShouShuShenQingService {
    private final ShouShuShenQingDao dao;
    private final PublicServer publicServer;
    private final YiZhuLuRuDao yiZhuLuRuDao;
    private final SocketV2 socketV2;
    private final ExtraCache extraCache;


    /**
     * 获取手术的项目 在
     *
     * @param name 搜索名称
     * @param type 搜索类型
     * @return
     */
    public ResultVo<List<ZdIcd9Cm3>> obtainSurgicalItems(String name, Integer type) {
        return ResultVoUtil.success(dao.obtainSurgicalItems(StringUtil.isContainChinese(name), type));
    }

    public ResultVo<List<CodeName>> getDoctorByOpCode(String opCode) {
        return ResultVoUtil.success(dao.getDoctorByOpCode(opCode));
    }


    public ResultVo<Boolean> preoperativeDiscussion(String patNo, Integer times, Integer count) {
        // 获取当前患者的手术次数
        int currentPatientOpCount = dao.currentPatientOpCount(patNo, times);
        // 当前患者的手术次数加上传入的count
        currentPatientOpCount += count;
        // 获取当前患者术前讨论的次数
        int currentEmrPreoperativelyDiscussCount = dao.currentEmrPreoperativelyDiscussCount(patNo, times);
        // 如果当前患者的手术次数大于术前讨论的次数，则返回true
        if (currentPatientOpCount > currentEmrPreoperativelyDiscussCount) {
            return ResultVoUtil.success(true);
        }
        // 否则返回false
        return ResultVoUtil.success(false);
    }


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

    public ResultVo<List<OpRecord>> getOpRecord(String patNo, Integer times) {
        // 创建查询条件
        QueryWrapper<OpRecord> qw = new QueryWrapper<>();
        // 查询条件：住院号等于patNo
        qw.eq("inpatient_no", patNo);
        // 查询条件：住院次数等于times
        qw.eq("admiss_times", times);
        // 查询条件：状态不等于"d"
        qw.ne("status", "d");
        // 查询条件：按申请日期降序排列
        qw.orderByDesc("apply_date");
        // 返回查询结果
        return ResultVoUtil.success(dao.selectOpRecord(qw));
    }

    public ResultVo<IPage<OpRecord>> huoQuShouShu(ChaXunJianChaHeJianYan param) {
        IPage<OpRecord> page = new Page<>(param.getCurrentPage(), param.getPageSize(), param.getTotal() == 0);
        QueryWrapper<OpRecord> qw = new QueryWrapper<>();
        qw.select("op_name, op_datetime, status,record_id");
        qw.eq("inpatient_no", param.getPatNo());
        qw.eq("admiss_times", param.getTimes());
        if (StringUtil.notBlank(param.getStartTime())) {
            qw.ge("req_date", param.getStartTime());
            qw.le("req_date", param.getEndTime());
        }
        if (StringUtil.notBlank(param.getOrderName())) {
            qw.eq("op_name", param.getOrderName());
        }
        qw.ne("status", "d");
        dao.selectPage(page, qw);
        return ResultVoUtil.success(page);
    }

    public ResultVo<JSONObject> getSurgeryDetail(String patNo, Integer times, Integer recordId) {
        // 根据患者编号、次数和记录ID查询手术记录
        OpRecord op = dao.daYingShouShu(patNo, times, recordId);
        // 根据记录ID查询手术诊断列表
        List<TReqSurgicalDiag> list = dao.selectReqSurgicalDiagByReqNo(recordId);
        // 创建一个JSON对象
        JSONObject json = new JSONObject();

        // 如果手术诊断列表为空
        if (ListUtil.isBlank(list)) {
            // 创建一个手术诊断对象，设置记录ID、排序、手术代码、手术名称和类型
            TReqSurgicalDiag tReqSurgicalDiag1 = new TReqSurgicalDiag() {{
                setReqNo(recordId);
                setSort(1);
                setCode(op.getOpCode());
                setName(op.getOpName());
                setType(1);
            }};

            // 将手术诊断对象添加到列表中
            list.add(tReqSurgicalDiag1);
            // 创建另一个手术诊断对象，设置记录ID、排序、术前诊断代码、术前诊断名称和类型
            TReqSurgicalDiag tReqSurgicalDiag2 = new TReqSurgicalDiag() {{
                setReqNo(recordId);
                setSort(1);
                setCode(op.getDiagBeforeCode());
                setName(op.getDiagBeforeOp());
                setType(2);
            }};
            // 将手术诊断对象添加到列表中
            list.add(tReqSurgicalDiag2);
        }

        // 将手术记录和手术诊断列表添加到JSON对象中
        json.put("opRecord", op);
        json.put("list", list);
        // 返回成功结果
        return ResultVoUtil.success(json);
    }


// 根据分类代码、名称、总记录数、当前页码、每页记录数查询分类详情
    public ResultVo<IPage<ShouShuFanHui>> fenLeiXiangQing(String code, String name, long total, long currentPage, long pageSize) {
        // 创建分页对象，设置当前页码、每页记录数、是否查询总记录数
        IPage<ShouShuFanHui> page = new Page<>(currentPage, pageSize, total == 0);
        // 调用dao层的方法，查询分类详情
        page = dao.fenLeiXiangQing(page, code, StringUtil.isContainChinese(name));
        // 返回查询结果
        return ResultVoUtil.success(page);
    }

    /**
     * 远程搜索手术部位
     *
     * @param name 名字
     * @return 返回
     */
    public ResultVo<List<GetDropdownBox>> huoQuShouShuBuWei(String name) {
        // 判断名字是否为空
        if (StringUtil.isBlank(name)) {
            // 如果为空，则返回所有手术部位
            return ResultVoUtil.success(dao.huoQuShouShuBuWei(name));
        }
        // 如果不为空，则判断名字是否包含中文
        return ResultVoUtil.success(dao.huoQuShouShuBuWei(StringUtil.isContainChinese(name)));
    }

    public ResultVo<String> applicationOpRecord(XinZengShouShu ss) {
        // 调用applyForVerification方法，传入手术记录，返回错误信息
        String error = applyForVerification(ss.getOpRecord());
        // 如果错误信息不为空，则返回失败结果
        if (StringUtil.notBlank(error)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, error);
        }

        // 调用publicServer的huanZheJieSuan方法，传入住院号和住院次数
        publicServer.huanZheJieSuan(ss.getInpatientNo(), ss.getAdmissTimes());
        // 获取当前用户的用户ID
        String userCode = TokenUtil.getInstance().getTokenUserId();
        // 申请次数
        Integer reqNo = dao.shouShuShenQingCiShu(ss.getInpatientNo(), ss.getAdmissTimes()) + 1;
        // 获取手术记录
        OpRecord op = ss.getOpRecord();

        // 获取手术号
        Integer recordId = publicServer.huoQuShouShuHao();

        // 设置手术记录的手术号、手术单号、申请次数
        op.setRecordId(recordId);
        op.setActOrderNo(publicServer.getActOrderNo());
        op.setOpTimes(reqNo);

        // 获取特殊医嘱标识
        Map<String, List<String>> yzZdOrderItemMap = extraCache.getYzZdOrderItemMap();

        // 如果特殊医嘱标识为空，则返回失败结果
        if (yzZdOrderItemMap == null) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "请联系管理员设置特殊医嘱标识。");
        }

        // 获取手术排斥和处置医嘱
        List<String> 手术排斥 = yzZdOrderItemMap.get("手术排斥");
        List<String> 处置医嘱 = yzZdOrderItemMap.get("处置医嘱");


        // 如果手术排斥为空，则返回失败结果
        if (手术排斥 == null) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "请联系管理员设置特殊【手术排斥】医嘱标识。");
        }

        // 如果处置医嘱为空，则返回失败结果
        if (处置医嘱 == null) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "请联系管理员设置特殊【处置医嘱】医嘱标识。");
        }

        // 获取患者信息
        XinZhenYiZhu patInfo = yiZhuLuRuDao.queryPatientInfo(ss.getInpatientNo(), ss.getAdmissTimes());
        // 获取医嘱代码
        String yzCode = ss.getGenerateRejectedOrders() ? 处置医嘱.get(0) : 手术排斥.get(0);

        // 创建手术诊断列表
        List<TReqSurgicalDiag> reqSurgicalDiagList = new ArrayList<>();
        // 添加手术诊断
        reqSurgicalDiagList.addAll(surgicalDiagnosisFor(ss.getOpCodeList(), recordId, TReqSurgicalDiag.SURGERY));
        // 添加诊断
        reqSurgicalDiagList.addAll(surgicalDiagnosisFor(ss.getDiagList(), recordId, TReqSurgicalDiag.DIAGNOSIS));

        try {
            // 插入手术记录
            dao.insertOpRecordJoin(op);
            // 插入手术记录
            dao.insertOpRecord(op,
                    ss.getInpatientNo(),
                    ss.getName(),
                    ss.getAdmissTimes(),
                    patInfo.getZkWard(),
                    patInfo.getDeptCode(),
                    userCode,
                    ss.getBedNo(),
                    ss.getAdmissWard());
            // 插入医嘱数据
            dao.insertYzOrderData(op, patInfo, userCode, ss.getExecDept(), yzCode);
            // 插入手术诊断
            dao.insertReqSurgicalDiag(reqSurgicalDiagList);
        } catch (Exception e) {
            // 如果插入失败，则删除手术记录
            dao.delOpRecord(op.getRecordId(), op.getActOrderNo());
            // 返回失败结果
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "手术申请错误，请联系管理员", e.getMessage());
        }

        // 返回成功结果
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
    }

// 根据传入的list、recordId和type，返回一个TReqSurgicalDiag的列表
    private List<TReqSurgicalDiag> surgicalDiagnosisFor(List<CodeName> list, int recordId, int type) {
        // 创建一个临时列表
        List<TReqSurgicalDiag> temp = new ArrayList<>();
        // 初始化索引
        int index = 0;
        // 遍历list
        for (CodeName codeName : list) {
            // 创建一个TReqSurgicalDiag对象
            TReqSurgicalDiag a = new TReqSurgicalDiag();
            // 设置reqNo、code、name、type和sort
            a.setReqNo(recordId)
                    .setCode(codeName.getCode())
                    .setName(codeName.getName())
                    .setType(type)
                    .setSort(++index);
            // 将TReqSurgicalDiag对象添加到临时列表中
            temp.add(a);
        }
        // 返回临时列表
        return temp;
    }


    public String applyForVerification(OpRecord param) {
        // 创建一个StringBuilder对象，用于拼接错误信息
        StringBuilder sb = new StringBuilder();

        // 判断手术编码是否为空
        if (StringUtil.isBlank(param.getOpCode())) {
            // 如果为空，拼接错误信息
            sb.append("手术编码不能为空。");
        }
        // 判断手术时间是否为空
        if (param.getOpDatetime() == null) {
            // 如果为空，拼接错误信息
            sb.append("手术时间不能为空。");
        } else if (DateUtil.shiJianDaXiao(param.getOpDatetime(), param.getApplyDate(), "<")) {
            // 如果手术时间小于申请时间，拼接错误信息
            sb.append("手术时间不能小于申请时间。");
        }
        // 判断术前诊断是否为空
        if (StringUtil.isBlank(param.getDiagBeforeCode())) {
            // 如果为空，拼接错误信息
            sb.append("术前诊断不能为空。");
        }
        // 判断手术部位是否为空
        if (StringUtil.isBlank(param.getPartCode())) {
            // 如果为空，拼接错误信息
            sb.append("手术部位不能为空。");
        }
        // 判断主刀医生是否为空
        if (StringUtil.isBlank(param.getDoctorZd())) {
            // 如果为空，拼接错误信息
            sb.append("主刀医生不能为空。");
        }
        // 判断手术等级是否为空
        if (StringUtil.isBlank(param.getOpScale())) {
            // 如果为空，拼接错误信息
            sb.append("手术等级不能为空。");
        }
        // 判断生成的医嘱名是否为空
        if (StringUtil.isBlank(param.getOrderName())) {
            // 如果为空，拼接错误信息
            sb.append("生成的医嘱名不能为空。");
        }
        // 返回拼接后的错误信息
        return sb.toString();
    }


    public ResultVo<String> shanChuShouShu(Integer recordId) {
        // 根据recordId查询手术信息
        OpRecord op = dao.shouShuXinXi(recordId);
        // 如果手术信息为空，则返回错误信息
        if (op == null) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有找到该手术的信息。");
        }
        // 如果手术状态不为1，则返回错误信息
        if (!"1".equals(op.getStatus().trim())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "无法删除该手术。");
        }
        // 生成删除标志
        dao.genXingShanChuBiaoZhi(recordId);
        // 记录日志
        log.info("删除手术==》操作人：{}，申请单号：{}", TokenUtil.getInstance().getTokenUserId(), recordId);
        // 返回成功信息
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
    }

    public ResultVo<String> addASurgicalSite(String name) {
        // 判断手术部位名称是否重复
        if (dao.repeatPartName(name)) {
            // 返回逻辑错误，手术部位名称重复
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "手术部位名称重复");
        }
        // 获取最大手术部位编码
        String maxCode = String.valueOf(dao.getTheMaximumSurgicalCode() + 1);
        // 如果最大手术部位编码大于1，则直接赋值，否则在前面加一个0
        String newCode = maxCode.length() > 1 ? maxCode : '0' + maxCode;
        // 插入新的手术部位
        dao.insertNewSurgicalSite(newCode, name, PingYinUtils.pyShouZiMuDaXie(name), PingYinUtils.getWBCode(name));
        // 记录日志，新增手术部位，操作人
        log.info("新增手术部位==>操作人:{}", TokenUtil.getInstance().getTokenUserId());
        // 返回成功，并返回新的手术部位编码
        return ResultVoUtil.success(newCode);
    }

    public ResultVo<String> removeSurgicalSite(String code) {
        // 调用dao层的方法，删除手术部位
        dao.removeSurgicalSite(code);
        // 返回成功的结果
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
    }
}
