package thyyxxk.webserver.service.medicalinsurance;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.sidicts.*;
import thyyxxk.webserver.dao.his.medicalinsurance.DigitalReceiptDao;
import thyyxxk.webserver.dao.his.medicalinsurance.SiMzDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.markmtfees.*;
import thyyxxk.webserver.entity.medicalinsurance.digitalreceipt.*;
import thyyxxk.webserver.entity.medicalinsurance.digitalreceipt.request.*;
import thyyxxk.webserver.entity.medicalinsurance.manage.clinicinfo.RevokeRegRequest;
import thyyxxk.webserver.entity.medicalinsurance.outpatient.*;
import thyyxxk.webserver.entity.medicalinsurance.query.InsuInfo;
import thyyxxk.webserver.entity.medicalinsurance.query.PsnBaseInfo;
import thyyxxk.webserver.entity.medicalinsurance.query.QryPsnBsInfo;
import thyyxxk.webserver.entity.medicalinsurance.query.SiPatInfo;
import thyyxxk.webserver.entity.medicalinsurance.setlinfo.FundDetail;
import thyyxxk.webserver.entity.outpatient.medicalinfo.MzBlRecord;
import thyyxxk.webserver.service.externalhttp.SiMzSrvc;
import thyyxxk.webserver.service.externalhttp.ThmzSystem;
import thyyxxk.webserver.utils.*;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @description: 门诊医保交易
 * @author: DingJie
 * @create: 2021-05-28 16:11:19
 **/
@Slf4j
@Service
public class SiMzService {
    private final SiMzDao dao;
    private final DigitalReceiptDao rxDao;
    private final ThmzSystem thmz;
    private final SiMzSrvc mzSrvc;
    private final SiQueryService qryService;
    @Value("${si-mz-fee-url}")
    private String siMzFeeUrl;
    @Value("${thmz-api-url}")
    private String thmzApiUrl;

    @Autowired
    public SiMzService(SiMzDao dao, DigitalReceiptDao rxDao, ThmzSystem thmz, SiMzSrvc mzSrvc,
                       SiQueryService qryService) {
        this.dao = dao;
        this.rxDao = rxDao;
        this.thmz = thmz;
        this.mzSrvc = mzSrvc;
        this.qryService = qryService;
    }

    public ResultVo<String> outpatientRegistration(MzPatientInfo p) {
        p.setStaffId(TokenUtil.getInstance().getTokenUserId());
        String hisOrdNum = p.getPatNo() + "_" + p.getTimes() + "_" + 1;
        int mipCount = dao.selectMipayCount(hisOrdNum);
        if (mipCount > 0) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "患者已进行移动医保支付，请勿重复登记。");
        }
        return mzSrvc.outpatientRegistration(siMzFeeUrl, p);
    }

    public ResultVo<String> revokeOutpatientRegistration(MzPatientInfo p) {
        p.setStaffId(TokenUtil.getInstance().getTokenUserId());
        return mzSrvc.revokeOutpatientRegistration(siMzFeeUrl, p);
    }

    public ResultVo<String> executeOutpatientRegRevoke(RevokeRegRequest request) {
        request.setStaffId(TokenUtil.getInstance().getTokenUserId());
        return mzSrvc.executeOutpatientRegRevoke(siMzFeeUrl, request);
    }

    public ResultVo<List<Map<String, Object>>> getMzReceipts(MzPatientInfo p) {
        String patNo = p.getPatNo();
        JSONObject queryMzChargeListParam = new JSONObject();
        queryMzChargeListParam.put("patCardType", 21);
        queryMzChargeListParam.put("patCardNo", patNo);
        queryMzChargeListParam.put("hisOrdNum", "");
        queryMzChargeListParam.put("ybRequest", 1);

        Map<String, Object> mzChargeListMap = thmz.getMzChargeDetailForUnPaid(thmzApiUrl, queryMzChargeListParam);
        if (null == mzChargeListMap) {
            return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
        }
        if (0 != (int) mzChargeListMap.get("resultCode")) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, mzChargeListMap.get("resultMessage").toString());
        }
        List<Map<String, Object>> finalResult = new ArrayList<>();
        List<Map<String, String>> mzChargeList = FilterUtil.cast(mzChargeListMap.get("data"));
        for (Map<String, String> item : mzChargeList) {
            String hisOrdNum = item.get("hisOrdNum");
            if (null != hisOrdNum) {
                String[] hisOrdNumParts = hisOrdNum.split("_");
                int tempTimes = Integer.parseInt(hisOrdNumParts[1]);
                MzVisit mzVisit = dao.selectMzVisit(patNo, tempTimes);
                if (null == mzVisit) {
                    continue;
                }
                if (IdCardUtil.isValidatedIdCard(mzVisit.getSocialNo())) {
                    mzVisit.setAge(IdCardUtil.getAgeByIdCard(mzVisit.getSocialNo()));
                }
                String vipFlag = String.valueOf(item.get("vipFlag"));
                mzVisit.setReceiptNo(Integer.parseInt(hisOrdNumParts[2]));
                mzVisit.setTableClinicReceiptNo(0);
                mzVisit.setSettledFlag(calSettleFlag(mzVisit));
                mzVisit.setVipFlag(vipFlag);
                Map<String, Object> childResult = new HashMap<>(Capacity.FIVE);
                childResult.put("times", tempTimes);
                childResult.put("mzVisit", mzVisit);
                JSONObject queryMzChargeDetailParam = new JSONObject();
                queryMzChargeDetailParam.put("patientId", patNo);
                queryMzChargeDetailParam.put("times", tempTimes);
                queryMzChargeDetailParam.put("receiptNo", hisOrdNumParts[2]);
                Map<String, Object> mzChargeDetailMap = thmz.unPaidToFullChargeDetail(thmzApiUrl, queryMzChargeDetailParam);
                if (null != mzChargeDetailMap && 0 == (int) mzChargeDetailMap.get("resultCode")) {
                    List<Map<String, Object>> mzChargeDetailList = FilterUtil.cast(mzChargeDetailMap.get("data"));
                    mzChargeDetailList.removeIf(detail -> "TC".equals(detail.get("billItemCode")) ||
                            !"5".equals(detail.get("payMark")) || "BILL99".equals(detail.get("chargeItemCode")) ||
                            "四舍五入".equals(detail.get("tcName")));
                    if (mzChargeDetailList.isEmpty()) {
                        continue;
                    }
                    Map<Integer, List<MzReceipt>> orderReceiptsMap = new HashMap<>(Capacity.DEFAULT);
                    String doctorName = dao.selectDoctorName(mzChargeDetailList.get(0).get("doctorCode").toString());
                    mzChargeDetailList.forEach(detail -> {
                        MzReceipt receipt = fillMzReceipt(detail);
                        receipt.setPatientId(patNo);
                        receipt.setTimes(tempTimes);
                        receipt.setDoctorName(doctorName);
                        if (!orderReceiptsMap.containsKey(receipt.getOrderNo())) {
                            List<MzReceipt> list = new ArrayList<>();
                            list.add(receipt);
                            orderReceiptsMap.put(receipt.getOrderNo(), list);
                        } else {
                            orderReceiptsMap.get(receipt.getOrderNo()).add(receipt);
                        }
                    });
                    List<OrderNo> orderNos = getOrderNos(patNo, tempTimes, mzVisit.getReceiptNo(), orderReceiptsMap);
                    childResult.put("orderNos", orderNos);
                    childResult.put("mzReceipts", orderReceiptsMap);
                    finalResult.add(childResult);
                }
            }
        }
        return ResultVoUtil.success(finalResult);
    }

    public ResultVo<List<MzDepositFile>> getHistoryMzReceipts(String patNo, String start, String end) {
        List<MzDepositFile> mzChargeList = dao.selectMzDepositFiles(patNo, start, end);
        if (null == mzChargeList || mzChargeList.isEmpty()) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有找到历史处方！");
        }
        for (MzDepositFile depositFile : mzChargeList) {
            MzVisit mzVisit = new MzVisit();
            mzVisit.setPatientId(patNo);
            mzVisit.setTimes(depositFile.getTimes());
            mzVisit.setReceiptNo(depositFile.getReceiptNo());
        }
        return ResultVoUtil.success(mzChargeList);
    }

    public Map<String, Object> getHistoryReceiptDetail(MzDepositFile mzDepositFile) {
        MzVisit mzVisit = dao.selectMzVisit(mzDepositFile.getPatNo(), mzDepositFile.getTimes());
        if (null == mzVisit) {
            throw new BizException(ExceptionEnum.NULL_POINTER, "没有找到患者的就诊信息。");
        }
        if (IdCardUtil.isValidatedIdCard(mzVisit.getSocialNo())) {
            mzVisit.setAge(IdCardUtil.getAgeByIdCard(mzVisit.getSocialNo()));
        }
        mzVisit.setSettledFlag(calSettleFlag(mzVisit));
        List<MzReceipt> mzReceipts = dao.selectMzCharge(mzDepositFile.getPatNo(),
                mzDepositFile.getTimes(), mzDepositFile.getReceiptNo());
        mzReceipts.forEach(itm -> itm.setChecked(StringUtil.notBlank(itm.getNationalCode())));
        Map<String, Object> map = new HashMap<>();
        map.put("mzVisit", mzVisit);
        map.put("mzReceipts", mzReceipts);
        return map;
    }

    public MzDepositFile mergeReceipts(List<MzDepositFile> list) {
        MzDepositFile minTimesVisit = list.get(0);
        List<MzReceipt> mergedReceipts = new ArrayList<>();
        for (MzDepositFile mzDepositFile : list) {
            if (mzDepositFile.getTimes() < minTimesVisit.getTimes()) {
                minTimesVisit = mzDepositFile;
            }
            List<MzReceipt> mzReceipts = dao.selectMzCharge(mzDepositFile.getPatNo(),
                    mzDepositFile.getTimes(), mzDepositFile.getReceiptNo());
            mzReceipts.removeIf(item -> StringUtil.isBlank(item.getNationalCode()));
            mergedReceipts.addAll(mzReceipts);
        }

        String hasCovidExamFees = covidExamFeesDetect(mergedReceipts);
        if (StringUtil.notBlank(hasCovidExamFees)) {
            throw new BizException(ExceptionEnum.LOGICAL_ERROR, hasCovidExamFees);
        }

        for (int i = 0; i < mergedReceipts.size(); i++) {
            MzReceipt receipt = mergedReceipts.get(i);
            receipt.setTimes(minTimesVisit.getTimes());
            receipt.setItemNo(i + 1);
        }
        dao.deleteAllReceipts(list.get(0).getPatNo(), minTimesVisit.getTimes());
        insertBatchedMtReceipts(mergedReceipts);
        String message = "合并处方成功，请使用【第 " + minTimesVisit.getTimes() + " 次就诊】办理医保业务。";
        minTimesVisit.setMessage(message);
        return minTimesVisit;
    }

    private void insertBatchedMtReceipts(List<MzReceipt> receipts) {
        List<MzReceipt> tempList = new ArrayList<>();
        for (MzReceipt item : receipts) {
            tempList.add(item);
            if (tempList.size() == 50) {
                dao.insertMtReceipts(tempList);
                tempList.clear();
            }
        }
        if (!tempList.isEmpty()) {
            dao.insertMtReceipts(tempList);
        }
    }

    private int calSettleFlag(MzVisit f) {
        int siCount = dao.selectSiCount(f.getPatientId(), f.getTimes());
        if (siCount > 0) {
            return 1;
        }
        String hisOrdNum = f.getPatientId() + "_" + f.getTimes() + "_" + f.getReceiptNo();
        int mipay = dao.selectMipayCount(hisOrdNum);
        return mipay == 0 ? 0 : 2;
    }

    private MzReceipt fillMzReceipt(Map<String, Object> detail) {
        MzReceipt receipt = new MzReceipt();
        receipt.setReceiptNo((int) detail.get("receiptNo"));
        receipt.setOrderNo((int) detail.get("orderNo"));
        receipt.setItemNo((int) detail.get("itemNo"));
        receipt.setDrugName(detail.get("tcName").toString());
        receipt.setChargeItemCode(detail.get("chargeItemCode").toString());
        receipt.setPriceTime(DateUtil.formatPriceTime(detail.get("priceTime").toString()));
        receipt.setUnitPrice(new BigDecimal(detail.get("unitPrice").toString()).setScale(4, RoundingMode.HALF_UP));
        receipt.setQuantity(Double.valueOf(detail.get("quantity").toString()));
        receipt.setDrugWin((int) detail.get("drugWin"));
        receipt.setDoctorCode(detail.get("doctorCode").toString());
        receipt.setGroupNo(detail.get("groupNo").toString());
        receipt.setChargeDate(detail.get("priceTime").toString().split("\\+")[0].replace("T", " "));
        receipt.setBillItemCode(detail.get("billItemCode").toString());
        receipt.setChargeBillCode(detail.get("chargeBillCode").toString());
        String table = receipt.getGroupNo().trim().equals("00") ? "zd_charge_item" : "yp_zd_dict";
        receipt.setNationalCode(dao.selectNationalCode(receipt.getChargeItemCode(), table));
        receipt.setChecked(StringUtil.notBlank(receipt.getNationalCode()));
        if (null != detail.get("hospApprFlag")) {
            receipt.setHospApprFlag(detail.get("hospApprFlag").toString());
        }
        if (null != detail.get("serialNo")) {
            receipt.setSerialNo(detail.get("serialNo").toString());
        }
        if (null != detail.get("instructionText")) {
            receipt.setInstructionText(detail.get("instructionText").toString());
        }
        if (null != detail.get("specification")) {
            receipt.setSpecification(detail.get("specification").toString());
        }
        if (null != detail.get("frequency")) {
            receipt.setFrequency(detail.get("frequency").toString());
        }
        if (null != detail.get("drugQuan")) {
            receipt.setDrugQuan(Double.valueOf(detail.get("drugQuan").toString()));
        }
        if (null != detail.get("orderDays")) {
            receipt.setOrderDays((Integer) detail.get("orderDays"));
        }
        // groupNo：00-项目；其他-药品
        if ("00".equals(receipt.getGroupNo())) {
            receipt.setDrugUnit(dao.selectXmChargeUnit(receipt.getChargeItemCode()));
        } else {
            receipt.setYbComment(dao.selectYbComment(receipt.getChargeItemCode()));
            if (null != detail.get("serial")) {
                receipt.setSerial(detail.get("serial").toString());
                receipt.setSpecification(dao.selectSpecification(receipt.getChargeItemCode(), receipt.getSerial()));
            }
            if (null != detail.get("supplyCode")) {
                receipt.setSupplyCode(dao.selectSupplyName(detail.get("supplyCode").toString()));
            }
            if (null != detail.get("drugUnit")) {
                receipt.setDrugUnit(dao.selectDrugUnit(detail.get("drugUnit").toString()));
            }
        }
        return receipt;
    }

    private List<OrderNo> getOrderNos(String patientId, int times, int receiptNo, Map<Integer, List<MzReceipt>> orderReceiptsMap) {
        List<OrderNo> orderNos = new ArrayList<>();
        for (Map.Entry<Integer, List<MzReceipt>> entry : orderReceiptsMap.entrySet()) {
            OrderNo orderNo = new OrderNo();
            orderNo.setPatientId(patientId);
            orderNo.setTimes(times);
            orderNo.setReceiptNo(entry.getValue().get(0).getReceiptNo());
            orderNo.setOrderNo(entry.getKey());
            BigDecimal total = new BigDecimal("0.00");
            for (MzReceipt receipt : entry.getValue()) {
                total = total.add(receipt.getChargeFee());
            }
            orderNo.setTotalFee(total);
            int count = dao.selectFeeCount(patientId, times, receiptNo, entry.getKey());
            orderNo.setStatus(count > 0);
            orderNos.add(orderNo);
        }
        return orderNos;
    }

    public ResultVo<String> insertSiMzFees(List<MzReceipt> receipts) {
        receipts.removeIf(item -> !item.getChecked());
        if (receipts.isEmpty()) {
            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "患者没有可以报销的项目！");
        }
        String hasCovidExamFees = covidExamFeesDetect(receipts);
        if (StringUtil.notBlank(hasCovidExamFees)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, hasCovidExamFees);
        }
        dao.insertMtReceipts(receipts);
        return ResultVoUtil.success();
    }

    private String covidExamFeesDetect(List<MzReceipt> receipts) {
        StringBuilder message = new StringBuilder();
        for (MzReceipt receipt : receipts) {
            if (receipt.getChargeItemCode().trim().equals("019180")) {
                message.append("【019180，新型冠状病毒核酸检测】");
            }
            if (receipt.getChargeItemCode().trim().equals("019110")) {
                message.append("【019110，新型冠状病毒2019-ncov核酸检测试剂盒（荧光）】");
            }
        }
        if (message.length() > 0) {
            message.append("无法上传至医保中心，请单独开具处方。");
            return "因政策原因，" + message;
        }
        return null;
    }

    public ResultVo<String> insertSiMzFeesForSupplement(List<MzReceipt> receipts) {
        receipts.removeIf(item -> !item.getChecked() || item.getChargeItemCode().equals("019110")
                || item.getChargeItemCode().equals("019180"));
        if (receipts.isEmpty()) {
            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "患者没有可以报销的项目！");
        }
        MzReceipt receipt = receipts.get(0);
        List<Integer> receiptNos = dao.selectGeneratedReceiptNos(receipt.getPatientId(), receipt.getTimes());
        for (int receiptNo : receiptNos) {
            if (dao.isReceiptPayed(receipt.getPatientId(), receipt.getTimes(), receiptNo) == 0) {
                dao.deleteCertainReceipt(receipt.getPatientId(), receipt.getTimes(), receiptNo);
            }
        }
        dao.insertMtReceipts(receipts);
        return ResultVoUtil.success();
    }

    public ResultVo<String> deleteMzReceipt(OrderNo param) {
        dao.deleteMzReceipt(param);
        return ResultVoUtil.success();
    }

    public ResultVo<String> deleteAllMzReceipts(MzPatientInfo p) {
        if (null == p.getTimes()) {
            p.setTimes(dao.selectMaxTimes(p.getPatNo()));
        }
        log.info("【操作员：{}】删除所有门特处方：门诊号：{}，门诊次数：{}",
                TokenUtil.getInstance().getTokenUserId(), p.getPatNo(), p.getTimes());
        dao.deleteAllReceipts(p.getPatNo(), p.getTimes());
        return ResultVoUtil.success("删除成功。");
    }

    public ResultVo<SiPatInfo> uploadOutpatientFeeDetails(SpcChrDiseAcct p) {
        p.setStaffId(TokenUtil.getInstance().getTokenUserId());
        return mzSrvc.uploadOutpatientFeeDetails(siMzFeeUrl, p);
    }

    public ResultVo<String> revokeOutpatientFeeDetails(MzPatientInfo p) {
        p.setStaffId(TokenUtil.getInstance().getTokenUserId());
        return mzSrvc.revokeOutpatientFeeDetails(siMzFeeUrl, p);
    }

    public ResultVo<FundDetail> outpatientPreSettlement(MzPatientInfo p) {
        if (null == p.getStaffId()) {
            p.setStaffId(TokenUtil.getInstance().getTokenUserId());
        }
        return mzSrvc.outpatientPreSettlement(siMzFeeUrl, p);
    }

    public ResultVo<FundDetail> outpatientSettlement(MzPatientInfo p) {
        if (null == p.getStaffId()) {
            p.setStaffId(TokenUtil.getInstance().getTokenUserId());
        }
        return mzSrvc.outpatientSettlement(siMzFeeUrl, p);
    }

    public ResultVo<FundDetail> timeoutSetl(MzPatientInfo p) {
        if (null == p.getStaffId()) {
            p.setStaffId(TokenUtil.getInstance().getTokenUserId());
        }
        String logContent = dao.getLogContent(p.getMsgid());
        if (!logContent.contains("服务提供者后端服务响应超时")) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR,
                    "该笔交易不符合超时结算条件，无法进行超时结算（结算失败的原因为“服务提供者后端服务响应超时”时，方可进行超时结算）。");
        }
        return mzSrvc.timeoutSetl(siMzFeeUrl, p);
    }

    public boolean receiptAlreadyPrinted(MzPatientInfo p) {
        String receiptBill = dao.selectReceiptBill(p.getPatNo(), p.getTimes());
        return StringUtil.notBlank(receiptBill);
    }

    public ResultVo<FundDetail> revokeOutpatientSettlement(MzPatientInfo p) {
        if (null == p.getStaffId()) {
            p.setStaffId(TokenUtil.getInstance().getTokenUserId());
        }
        return mzSrvc.revokeOutpatientSettlement(siMzFeeUrl, p);
    }

    public void insertSiPatInfo(MzPatientInfo mz) {
        int count = dao.selectSiMzInfoCount(mz.getPatNo(), -1);
        if (count == 0) {
            PsnBaseInfo patinfo = dao.selectPsnBaseinfo(mz.getPatNo(), mz.getTimes());
            if (null != patinfo) {
                patinfo.setTimes(-1);
                dao.insertSiMzInfoPsnNo(patinfo);
            }
        }
    }

    public ResultVo<String> saveSiMzDiags(List<SiMzDiag> diags) {
        if (ListUtil.isBlank(diags)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有要保存的诊断！");
        }
        SiMzDiag diag = diags.get(0);
        dao.deleteMzDiags(diag.getPatNo(), diag.getTimes());
        String staffId = TokenUtil.getInstance().getTokenUserId();
        for (SiMzDiag itm : diags) {
            itm.setRealOpter(staffId);
            dao.insertNewMzDiag(itm);
        }
        return ResultVoUtil.success("门诊诊断保存成功。");
    }

    public Map<String, Object> queryInsuinfo(SiMzBusinessParams param) {
        Map<String, Object> result = new HashMap<>();
        QryPsnBsInfo mzptnt = new QryPsnBsInfo();
        mzptnt.setStaffId(param.getStaffId());
        mzptnt.setPatNo(param.getPatientId());
        mzptnt.setMedType(MedType.GENERAL_CLINIC.getCode());
        mzptnt.setOnlyQry(1);
        mzptnt.setTimes(-1);
        mzptnt.setReadCardResult(param.getReadCardResult());
        mzptnt.setBusCardInfo(param.getBusCardInfo());
        MdtrtCertType mdtrtCertType = MdtrtCertType.get(param.getReadCardType());
        if (null != mdtrtCertType) {
            mzptnt.setMdtrtCertType(mdtrtCertType.getLabel());
        } else {
            mzptnt.setMdtrtCertType(param.getReadCardType());
        }

        if (StringUtil.notBlank(param.getAdmdvs())) {
            mzptnt.setAdmdvs(param.getAdmdvs());
            mzptnt.setSocialNo(param.getSocialNo());
        }

        ResultVo<PsnBaseInfo> baseInfo = qryService.obtainBasicPersonInfo(mzptnt);
        if (null == baseInfo) {
            result.put("code", -2);
            result.put("msg", "网络异常。");
            return result;
        }
        if (!Objects.equals(baseInfo.getCode(), ExceptionEnum.SUCCESS.getCode())) {
            result.put("code", -2);
            result.put("msg", baseInfo.getMessage());
            return result;
        }
        // 如果有职工或居民保险，就入库
        PsnBaseInfo psninfo = baseInfo.getData();
        InsuInfo insuInfo = getResidantOrEmployeeInsuInfo(psninfo.getInsuinfo());
        if (null == insuInfo) {
            result.put("code", -1);
            result.put("msg", "患者没有职工/居民医保，如需报销请走医保科流程。");
            return result;
        }

        psninfo.setInsutype(insuInfo.getInsutype());
        int count = dao.selectSiMzInfoCount(mzptnt.getPatNo(), mzptnt.getTimes());
        if (count == 0) {
            psninfo.setMedType(MedType.GENERAL_CLINIC.getCode());
            psninfo.setInsuplc(insuInfo.getInsuplcAdmdvs());
            psninfo.setInsuplcAdmdvsName(insuInfo.getInsuplcAdmdvsName());
            psninfo.setLedgerSn(0);
            psninfo.setPsnType(insuInfo.getPsnType());
            psninfo.setEmpName(insuInfo.getEmpName());
            psninfo.setBalc(insuInfo.getBalc());
            dao.insertSiMzInfoPsnNo(psninfo);
        } else {
            dao.updateSiZyInfoPsnNo(mzptnt.getPatNo(), mzptnt.getTimes(), psninfo.getInsutype(),
                    insuInfo.getBalc(), insuInfo.getInsuplcAdmdvs(), insuInfo.getInsuplcAdmdvsName());
        }
        result.put("code", 0);
        result.put("expContentRequired", expContentRequired(insuInfo.getInsuplcAdmdvs()));
        result.put("msg", "查询参保信息成功。");
        return result;
    }

    private InsuInfo getResidantOrEmployeeInsuInfo(List<InsuInfo> list) {
        for (InsuInfo info : list) {
            Insutype insutype = Insutype.get(info.getInsutype());
            if (null == insutype) {
                continue;
            }
            if (insutype == Insutype.BASIC_MEDICAL_INSURANCE_FOR_EMPLOYEES ||
                    insutype == Insutype.BASIC_MEDICAL_INSURANCE_FOR_RURAL_RESIDENTS) {
                return info;
            }
        }
        return null;
    }

    private int expContentRequired(String insuplc) {
        return (insuplc.startsWith("4301") || insuplc.equals("439900")) ? 0 : 1;
    }

    public ResultVo<FundDetail> directRegistration(SiMzBusinessParams param) {
        return mzSrvc.directRegistration(siMzFeeUrl, param);
    }

    public ResultVo<FundDetail> mzgjAfterModifyReceipt(SiMzBusinessParams param) {
        PsnBaseInfo psnBaseInfo = dao.selectLatestPsnInfo(param.getPatientId());
        if (null == psnBaseInfo) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "无法办理，没有找到参保信息。");
        }
        dao.deleteAllReceipts(param.getPatientId(), param.getTimes());
        param.setStraitSettle(true);
        return mzSrvc.directRegistration(siMzFeeUrl, param);
    }

    public ResultVo<Integer> isPatientDuringSiSettle(String patientId) {
        return mzSrvc.isPatientDuringSiSettle(siMzFeeUrl, patientId);
    }

    public String queryModifyPermission(MzPatientInfo info) {
        int pre = dao.selectPresettleCount(info.getPatNo(), info.getTimes());
        if (pre > 0) {
            return "此患者的处方已上传医保，无法修改。";
        }
        String setlStaff = dao.selectSetlStaff(info.getPatNo(), info.getTimes());
        if (StrUtil.isEmpty(setlStaff)) {
            return "OK";
        }
        if (Objects.equals(info.getStaffId(), setlStaff)) {
            return "OK";
        }
        return "DENIED";
    }

    public Map<String, Object> modifyFundPayAmount(ModifyFundAmt amt) {
        amt.fixNullVal();
        int res = dao.modifyFundAmt(amt);
        Map<String, Object> resultMap = new HashMap<>();
        if (res > 0) {
            resultMap.put("code", 0);
            resultMap.put("msg", "更新成功，有" + res + "条数据受影响。");
        } else {
            resultMap.put("code", -1);
            resultMap.put("msg", "更新失败，有0条数据受影响。");
        }
        log.info("THMZ修改报销数据：\n参数：{}\n结果：{}", amt, resultMap);
        return resultMap;
    }

    public MzBlRecord getMzBlRecord(String patientId, Integer times) {
        return dao.selectMzBlRecord(patientId, times);
    }

    public ResultVo<FundDetail> ybRegForRx(SiMzBusinessParams params) {
        return mzSrvc.directRegistration(siMzFeeUrl, params);
    }

    public List<RxIndex> getRxIndex(IndexInquiry inquiry) {
        if (null == inquiry.getBegintime()) {
            inquiry.setBegintime(DateUtil.parse("2024-01-01", "yyyy-MM-dd"));
        }
        if (null == inquiry.getEndtime()) {
            inquiry.setEndtime(new Date());
        }
        List<RxIndex> list = rxDao.getRxIndex(inquiry);
        if (inquiry.getState() != RxState.ALL) {
            list.removeIf(item -> item.getState() != inquiry.getState());
        }
        return list;
    }

    public String getRxDetail(String hospRxno) {
        String rxFile = rxDao.getRxFile(hospRxno);
        if (StringUtil.notBlank(rxFile)) {
            return rxFile;
        }

        RxPreCheckRequest request = new RxPreCheckRequest();
        request.setHospRxno(hospRxno);
        request.setStaffId(TokenUtil.getInstance().getTokenUserId());
        ResultVo<String> pdfVo = mzSrvc.createRxPdf(siMzFeeUrl, makePreCheckRequest(request));
        if (!Objects.equals(pdfVo.getCode(), ExceptionEnum.SUCCESS.getCode())) {
            throw new BizException(ExceptionEnum.LOGICAL_ERROR, pdfVo.getMessage());
        }
        return pdfVo.getData();
    }

    public ResultVo<JSONObject> rxPreCheck(RxPreCheckRequest request) {
        makePreCheckRequest(request);
        if (StringUtil.isBlank(request.getRxMdtrtinfo().getMdtrtId())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "患者未做医保登记，无法进行预核验！");
        }

        return mzSrvc.rxPreCheck(siMzFeeUrl, request);
    }

    private RxPreCheckRequest makePreCheckRequest(RxPreCheckRequest request) {
        RxMdtrtInfo rxMdtrtInfo = rxDao.getRxMdtrtinfo(request.getHospRxno());

        RxPreCheck rxPreCheck = rxDao.getRxReceiptinfo(request.getHospRxno());
        fillMdtrtCertNo(request, rxPreCheck);
        rxPreCheck.setBizTypeCode("01");

        List<RxDrugDetail> rxDrugDetailList = rxDao.getRxDruginfo(request.getHospRxno());
        for (RxDrugDetail item : rxDrugDetailList) {
            String spec = item.getDrugSpec();
            String unt = String.valueOf(spec.charAt(spec.length() - 1));
            item.setDrugTotlcntEmp(unt);
        }
        List<RxDiseInfo> rxDiseInfoList = rxDao.getRxDiseinfo(request.getHospRxno());

        request.setRxPreCheck(rxPreCheck);
        request.setRxMdtrtinfo(rxMdtrtInfo);
        request.setRxDrugDetailList(rxDrugDetailList);
        request.setRxDiseInfoList(rxDiseInfoList);

        return request;
    }

    private void fillMdtrtCertNo(RxPreCheckRequest request, RxPreCheck rxPreCheck) {
        ReadCardType readCardType = request.getReadCardType();
        rxPreCheck.setMdtrtCertType(readCardType.getCode());
        if (readCardType == ReadCardType.SFZ) {
            return;
        }
        String readCardResult = request.getReadCardResult();
        if (StringUtil.isBlank(readCardResult)) {
            throw new BizException("没有获取到读卡信息，请稍后重试。");
        }
        if (readCardType == ReadCardType.DZPZ) {
            JSONObject qrinfo = JSONObject.parseObject(readCardResult);
            String ecToken = qrinfo.getString("ecToken");
            rxPreCheck.setMdtrtCertNo(ecToken);
            rxPreCheck.setEcToken(ecToken);
        } else if (readCardType == ReadCardType.SBK) {
            String[] out = readCardResult.split("\\|");
            rxPreCheck.setMdtrtCertNo(out[2]);
            rxPreCheck.setCardSn(out[3]);
        }
    }

    public ResultVo<JSONObject> rxSign(RxSignRequest request) {
        RxUpload pharInfo = rxDao.selectPharInfo(request.getStaffId());
        pharInfo.setHospRxno(request.getHospRxno());
        rxDao.updatePharInfo(pharInfo);
        RxUpload rxUpload = rxDao.selectRxUploadForSign(request.getHospRxno());
        RxSign rxSign = new RxSign();
        String j = JSONObject.toJSONStringWithDateFormat(rxUpload, "yyyy-MM-dd HH:mm:ss");
        rxSign.setOriginalValue(Base64.getEncoder().encodeToString(j.getBytes(StandardCharsets.UTF_8)));
        rxSign.setOriginalRxFile(rxDao.selectOriginRxFile(request.getHospRxno()));
        request.setRxSign(rxSign);
        return mzSrvc.rxSign(siMzFeeUrl, request);
    }

    public ResultVo<JSONObject> rxUpload(RxUploadRequest request) {
        RxUpload rxUpload = rxDao.selectFullRxUploadInfo(request.getHospRxno());
        request.setRxUpload(rxUpload);
        return mzSrvc.rxUpload(siMzFeeUrl, request);
    }

    public ResultVo<JSONObject> rxRevoke(RxRevokeRequest request) {
        RxRevoke rxRevoke = rxDao.selectRxRevoke(request);
        request.setRxRevoke(rxRevoke);
        return mzSrvc.rxRevoke(siMzFeeUrl, request);
    }

    public ResultVo<JSONObject> rxInfoQuery(RxInfoQueryRequest request) {
        RxInfoQuery rxInfoQuery = rxDao.selectRxInfoQuery(request.getHospRxno());
        request.setRxInfoQuery(rxInfoQuery);
        return mzSrvc.rxInfoQuery(siMzFeeUrl, request);
    }

    public ResultVo<JSONObject> rxAuditingQuery(RxAuditingQueryRequest request) {
        RxInfoQuery rxInfoQuery = rxDao.selectRxInfoQuery(request.getHospRxno());
        request.setRxAuditingQuery(rxInfoQuery);
        return mzSrvc.rxAuditingQuery(siMzFeeUrl, request);
    }

    public ResultVo<JSONObject> rxSetlQuery(RxSetlQueryRequest request) {
        RxInfoQuery rxInfoQuery = rxDao.selectRxInfoQuery(request.getHospRxno());
        request.setRxSetlQuery(rxInfoQuery);
        return mzSrvc.rxSetlQuery(siMzFeeUrl, request);
    }

    public ResultVo<String> regRevoke(RxRevokeRequest request) {
        MzPatientInfo patinfo = rxDao.getBriefPatInfo(request.getHospRxno());
        patinfo.setStaffId(request.getStaffId());
        return mzSrvc.revokeOutpatientRegistration(siMzFeeUrl, patinfo);
    }

    public ResultVo<JSONObject> medicineInquiry(MedicineInquiry inquiry) throws Exception {
        return mzSrvc.medicineInquiry(siMzFeeUrl, inquiry);
    }
}
