package com.openhis.financial.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.core.common.exception.ServiceException;
import com.core.common.utils.AssignSeqUtil;
import com.core.common.utils.SecurityUtils;
import com.core.common.utils.StringUtils;
import com.openhis.administration.domain.ChargeItemDefinition;
import com.openhis.administration.domain.DeviceDefinition;
import com.openhis.administration.domain.HealthcareService;
import com.openhis.administration.service.IChargeItemDefinitionService;
import com.openhis.administration.service.IChargeItemService;
import com.openhis.administration.service.IDeviceDefinitionService;
import com.openhis.administration.service.IHealthcareServiceService;
import com.openhis.administration.service.impl.PatientServiceImpl;
import com.openhis.administration.service.impl.PatientStudentServiceImpl;
import com.openhis.common.constant.CommonConstants;
import com.openhis.common.constant.YbCommonConstants;
import com.openhis.common.enums.DelFlag;
import com.openhis.common.enums.ItemType;
import com.openhis.common.enums.PaymentKind;
import com.openhis.common.enums.PaymentStatus;
import com.openhis.common.enums.ybenums.YbChrgitmLv;
import com.openhis.common.enums.ybenums.YbMdtrtCertType;
import com.openhis.common.enums.ybenums.YbMedChrgItmType;
import com.openhis.common.enums.ybenums.YbMedType;
import com.openhis.financial.domain.Contract;
import com.openhis.financial.domain.PaymentReconciliation;
import com.openhis.financial.mapper.PaymentReconciliationMapper;
import com.openhis.financial.model.*;
import com.openhis.financial.service.IContractService;
import com.openhis.financial.service.IPaymentReconciliationService;
import com.openhis.medication.domain.MedicationDefinition;
import com.openhis.medication.service.IMedicationDefinitionService;
import com.openhis.nenu.dto.GfTypeRatioDto;
import com.openhis.nenu.service.impl.GfRatioServiceImpl;
import com.openhis.workflow.domain.ActivityDefinition;
import com.openhis.workflow.service.IActivityDefinitionService;
import com.openhis.yb.dto.Clinic2206OrderOutput;
import com.openhis.yb.dto.ClinicReg2201Output;
import com.openhis.yb.dto.PaymentInpatientDto;
import com.openhis.yb.dto.Yb2304OutputSetlInfo;
import com.openhis.yb.model.Clinic2207OrderModel;
import com.openhis.yb.service.YbManager;

/**
 * 付款管理Service业务层处理
 *
 * @author system
 * @date 2025-02-20
 */
@Service
public class PaymentReconciliationServiceImpl extends ServiceImpl<PaymentReconciliationMapper, PaymentReconciliation>
    implements IPaymentReconciliationService {
    @Resource
    private AssignSeqUtil assignSeqUtil;
    @Autowired
    private IContractService iContractService;
    @Autowired
    private YbManager ybManager;
    @Autowired
    private GfRatioServiceImpl gfRatioService;
    @Autowired
    private PatientServiceImpl patientService;
    @Autowired
    private PatientStudentServiceImpl patientStudentService;
    @Autowired
    private IChargeItemService chargeItemService;
    @Autowired
    private IChargeItemDefinitionService chargeItemDefinitionService;
    @Autowired
    private IDeviceDefinitionService deviceDefinitionService;
    @Autowired
    private IActivityDefinitionService activityDefinitionService;
    @Autowired
    private IMedicationDefinitionService medicationDefinitionService;
    @Autowired
    private IHealthcareServiceService healthcareServiceService;

    /**
     * 根据支付id获取对应收费项目的id列表
     *
     * @param paymentIdList 支付id列表
     * @return 收费项目的id列表
     */
    @Override
    public List<Long> getChargeItemIdListByPayment(List<Long> paymentIdList) {

        // 根据支付id获取支付信息
        List<PaymentReconciliation> paymentReconciliationList =
            baseMapper.selectList(new LambdaQueryWrapper<PaymentReconciliation>()
                .select(PaymentReconciliation::getChargeItemIds).in(PaymentReconciliation::getId, paymentIdList));
        if (paymentReconciliationList.isEmpty()) {
            return null;
        }
        // 拆解所有的chargeItemId，拼装成一个集合
        List<String> chargeItemIdList = paymentReconciliationList.stream().map(PaymentReconciliation::getChargeItemIds)
            .collect(Collectors.toList());
        List<Long> chargeItemIds = new ArrayList<>();
        for (String chargeItemId : chargeItemIdList) {
            if (StringUtils.isNotEmpty(chargeItemId)) {
                chargeItemIds.addAll(Arrays
                    .stream(
                        chargeItemId.replaceAll("\\[", "").replaceAll("\\]", "").split(CommonConstants.Common.COMMA))
                    .map(Long::parseLong).collect(Collectors.toList()));
            }
        }
        // 将收费项目集合转换成列表
        return chargeItemIds;
    }

    /**
     * 更新付款状态：退款中
     *
     * @param paymentIdList 支付id列表
     */
    @Override
    public void updateRefundingStatus(List<Long> paymentIdList) {
        baseMapper.update(new PaymentReconciliation().setStatusEnum(PaymentStatus.REFUNDING.getValue()),
            new LambdaUpdateWrapper<PaymentReconciliation>().in(PaymentReconciliation::getId, paymentIdList));
    }

    /**
     * PS：对chargeItem分付款方式 2025/05/23 ChargeItem分完付款方式之后，医保支付的ChargeItem还要分特慢病和普通门诊，特慢病等支付与常规门诊支付传参不一样
     */
    /**
     * 【预结算】
     * 
     * @param ybMdtrtCertType 医保凭证类型
     * @param busiCardInfo 读卡获取的密钥
     * @param contractBusNo 合同编号
     * @param paymentedItemList 收费项
     * @return 预结算结果
     */
    @Override
    public PrePaymentResult preSettle(YbMdtrtCertType ybMdtrtCertType, String busiCardInfo, String contractBusNo,
        List<PaymentedItemModel> paymentedItemList) {

        PrePaymentResult prePaymentResult = null;
        String ybSwitchFlag = SecurityUtils.getLoginUser().getOptionJson().getString(CommonConstants.Option.YB_SWITCH);
        if (ybSwitchFlag.equals("0")) {
            contractBusNo = CommonConstants.BusinessName.DEFAULT_CONTRACT_NO;
        }

        Contract contract = iContractService.getContract(contractBusNo);

        switch (contractBusNo) {
            case CommonConstants.BusinessName.DEFAULT_CONTRACT_NO:
                prePaymentResult = new PrePaymentResult();
                BigDecimal sumAmount = BigDecimal.ZERO;
                for (PaymentedItemModel item : paymentedItemList) {
                    sumAmount = sumAmount.add(item.getTotalPrice());
                }
                prePaymentResult.setMedfeeSumamt(sumAmount);
                prePaymentResult.setFulamtOwnpayAmt(sumAmount);
                prePaymentResult.setPsnPartAmt(sumAmount);
                prePaymentResult.setPsnCashPay(sumAmount);
                prePaymentResult.setChrgBchno(CommonConstants.BusinessName.DEFAULT_CONTRACT_NO);
                break;
            case "229900":// 吉林省医保
            case "220199":// 长春市医保(农大)
            case "220100":// 长春市医保(长大)
                Map<String, List<PaymentedItemModel>> collect =
                    paymentedItemList.stream().collect(Collectors.groupingBy(PaymentedItemModel::getMedType));
                if (collect.entrySet().size() > 1) {
                    throw new ServiceException("医保只接受同种医疗类型结算（普通门诊与慢病等不可以同时结算）！");
                }
                PrePaymentResult result;
                for (Map.Entry<String, List<PaymentedItemModel>> medTypeKV : collect.entrySet()) {
                    Clinic2206OrderOutput clinic2206OrderOutput = null;
                    ClinicReg2201Output reg2201Output = null;
                    if (!medTypeKV.getKey().equals(YbMedType.GENERAL_OUTPATIENT.getValue()) && "1".equals(
                        SecurityUtils.getLoginUser().getOptionJson().getString(CommonConstants.Option.YB_SWITCH))) {
                        // 不是普通门诊就诊类型，补充挂号信息
                        reg2201Output = ybManager.createRegWithMedType(contract, ybMdtrtCertType, busiCardInfo,
                            medTypeKV.getValue().get(0).getEncounterId(),
                            YbMedType.getByValue(medTypeKV.getValue().get(0).getMedType()));
                        reg2201Output.setMedType(medTypeKV.getKey());// 2025/06/05慢病挂号后上传2206信息报错，2201返回值没有medType，此处更正赋值
                    } else {
                        // 从数据库里取reg2201
                        reg2201Output =
                            ybManager.getClinicRegByEncounterId(medTypeKV.getValue().get(0).getEncounterId());
                    }
                    // 调用预结算
                    clinic2206OrderOutput = ybManager.preSettle(contract, medTypeKV.getValue().get(0).getEncounterId(),
                        ybMdtrtCertType, busiCardInfo, reg2201Output, "01", medTypeKV.getValue(),
                        YbMedType.getByValue(medTypeKV.getKey()));
                    prePaymentResult = new PrePaymentResult();
                    BeanUtils.copyProperties(clinic2206OrderOutput, prePaymentResult);
                }
                break;
            case "STUDENT0000":
                prePaymentResult = this.studentSelfPay(paymentedItemList);
                break;
            case "STUDENT220100":
            case "STUDENT229900":
            case "STUDENT220199":
                prePaymentResult = this.studentYbPay(contract, ybMdtrtCertType, busiCardInfo, "01", paymentedItemList);
                break;
            default:
                break;
        }
        return prePaymentResult;
    }

    /**
     * 学生二次报销
     * 
     * @param contract 合同
     * @param ybMdtrtCertType 医疗类别
     * @param busiCardInfo 电子码
     * @param s 按项目收费还是按病种收费（该字段目前在系统里面没用上，默认都是01）
     * @param paymentedItemList 收费项
     * @return 预结算结果
     */
    private PrePaymentResult studentYbPay(Contract contract, YbMdtrtCertType ybMdtrtCertType, String busiCardInfo,
        String s, List<PaymentedItemModel> paymentedItemList) {

        // 查比例及分类信息(PaymentedItemModel在chargeItem表中不是一定存在的所以此处改用单独查询)
        List<StudentPaymentItemModel> allPaymentItemList = getStudentPaymentItemModelList(paymentedItemList);

        // 拟定使用公费医疗的情况下实收金额
        BigDecimal onceReceivedAmount = BigDecimal.ZERO;
        for (StudentPaymentItemModel studentPaymentItemModel : allPaymentItemList) {
            // 获取折扣比例
            BigDecimal ratio = studentPaymentItemModel.getTwiceRatio() == null ? studentPaymentItemModel.getSelfRatio()
                : studentPaymentItemModel.getTwiceRatio();

            // 计算金额
            onceReceivedAmount = onceReceivedAmount.add(studentPaymentItemModel.getTotalPrice()
                .multiply(ratio.divide(new BigDecimal("100"), 6, RoundingMode.HALF_UP)));
        }

        // 医保结算
        PrePaymentResult prePaymentResult =
            this.studentPreSettleYb(contract, ybMdtrtCertType, busiCardInfo, paymentedItemList);
        if (prePaymentResult == null) {
            throw new ServiceException("医生开具的收费项未分配对应的医疗类型！");
        }

        BigDecimal psnPartAmt = prePaymentResult.getPsnPartAmt();

        if (psnPartAmt.compareTo(onceReceivedAmount) > 0) {
            prePaymentResult.setGfRatio(psnPartAmt.subtract(onceReceivedAmount));
            prePaymentResult.setPsnCashPay(onceReceivedAmount);
        } else {
            prePaymentResult.setGfRatio(BigDecimal.ZERO);
        }

        return prePaymentResult;
    }

    /**
     * 学生一次报销
     * 
     * @param paymentedItemList 收费项
     * @return 预结算结果
     */
    private PrePaymentResult studentSelfPay(List<PaymentedItemModel> paymentedItemList) {

        List<StudentPaymentItemModel> allPaymentItemList = getStudentPaymentItemModelList(paymentedItemList);

        // 拟定使用公费医疗的情况下实收金额
        BigDecimal onceReceivedAmount = BigDecimal.ZERO;
        for (StudentPaymentItemModel studentPaymentItemModel : allPaymentItemList) {
            // 获取折扣比例
            BigDecimal ratio = studentPaymentItemModel.getTwiceRatio() == null ? studentPaymentItemModel.getSelfRatio()
                : studentPaymentItemModel.getTwiceRatio();

            // 计算金额
            onceReceivedAmount = onceReceivedAmount.add(studentPaymentItemModel.getTotalPrice().multiply(ratio));
        }

        PrePaymentResult prePaymentResult = new PrePaymentResult();
        BigDecimal sumAmount = BigDecimal.ZERO;
        for (PaymentedItemModel item : paymentedItemList) {
            sumAmount = sumAmount.add(item.getTotalPrice());
        }
        prePaymentResult.setMedfeeSumamt(sumAmount);
        prePaymentResult.setFulamtOwnpayAmt(sumAmount);
        prePaymentResult.setPsnPartAmt(sumAmount);
        prePaymentResult.setPsnCashPay(onceReceivedAmount.divide(new BigDecimal("100"), 6, RoundingMode.HALF_UP));
        prePaymentResult.setGfRatio(sumAmount.subtract(prePaymentResult.getPsnCashPay()));
        prePaymentResult.setChrgBchno(CommonConstants.BusinessName.DEFAULT_STUDENT_CONTRACT_NO);
        return prePaymentResult;
    }

    /**
     * 【门诊结算】
     * 
     * @param contract 合同
     * @param payTransNo 支付批次号
     * @param ybMdtrtCertType 凭证类型
     * @param busiCardInfo 读卡获取到的凭证
     * @param minpacuntDrugTracCnt 追溯码相关信息
     * @param mcsTracCnt 追溯码相关信息
     * @return 结算结果
     */
    @Override
    public PaymentResult settle(Contract contract, String payTransNo, YbMdtrtCertType ybMdtrtCertType,
        String busiCardInfo, Integer minpacuntDrugTracCnt, Integer mcsTracCnt) {
        PaymentResult paymentResult = null;
        if (!(CommonConstants.BusinessName.DEFAULT_CONTRACT_NO.equals(payTransNo)
            || CommonConstants.BusinessName.DEFAULT_STUDENT_CONTRACT_NO.equals(payTransNo))) {
            // 医保支付 todo：支付的详细信息在于结算中已经存好了，但是还没有存储卡余额
            Clinic2207OrderModel clinic2207OrderModel =
                ybManager.settle(contract, payTransNo, busiCardInfo, ybMdtrtCertType, minpacuntDrugTracCnt, mcsTracCnt);
            paymentResult = new PaymentResult();
            BeanUtils.copyProperties(clinic2207OrderModel, paymentResult);
        } else {
            // 自费返回new实体
            paymentResult = new PaymentResult();
        }
        return paymentResult;
    }

    /**
     * 【住院结算】
     *
     * @param contract 合同
     * @param paymentDto 收费参数
     * @return 结算结果
     */
    @Override
    public PaymentResult inpatientSettle(Contract contract, PaymentInpatientDto paymentDto) {
        PaymentResult paymentResult = null;
        if (!CommonConstants.BusinessName.DEFAULT_CONTRACT_NO.equals(contract.getBusNo())) {
            // 医保支付 todo：支付的详细信息在于结算中已经存好了，但是还没有存储卡余额
            Yb2304OutputSetlInfo yb2304OutputSetlInfo = ybManager.inpatientSettle(contract, paymentDto);
            paymentResult = new PaymentResult();
            BeanUtils.copyProperties(yb2304OutputSetlInfo, paymentResult);
        } else {
            // 自费返回new实体
            paymentResult = new PaymentResult();
        }
        return paymentResult;
    }

    /**
     * 更改付款状态
     *
     * @param id paymentId
     * @param success 付款状态
     */
    @Override
    public void updatePaymentStatusById(Long id, PaymentStatus success) {
        baseMapper.update(new PaymentReconciliation().setStatusEnum(success.getValue()),
            new LambdaQueryWrapper<PaymentReconciliation>().eq(PaymentReconciliation::getId, id));
    }

    /**
     * 更改payment状态以及医保支付结算id
     * 
     * @param id 主键id
     * @param success 状态
     * @param settleId 医保结算id
     */
    @Override
    public void updatePaymentStatusAndSettleIdsById(Long id, PaymentStatus success, Integer paymentOutcome,
        List<String> settleId) {
        if (settleId == null || settleId.isEmpty()) {
            baseMapper.update(
                new PaymentReconciliation().setStatusEnum(success.getValue()).setOutcomeEnum(paymentOutcome),
                new LambdaQueryWrapper<PaymentReconciliation>().eq(PaymentReconciliation::getId, id));
        } else {
            baseMapper.update(
                new PaymentReconciliation().setStatusEnum(success.getValue()).setYbSettleIds(String.join(",", settleId))
                    .setOutcomeEnum(paymentOutcome),
                new LambdaQueryWrapper<PaymentReconciliation>().eq(PaymentReconciliation::getId, id));
        }
    }

    /**
     * 查询付款实体
     * 
     * @param encounterId 就诊id
     * @return 付款实体
     */
    @Override
    public PaymentReconciliation getByEncounterId(Long encounterId, PaymentKind paymentKind) {
        return baseMapper.selectOne(new LambdaQueryWrapper<PaymentReconciliation>()
            .eq(PaymentReconciliation::getEncounterId, encounterId)
            .eq(PaymentReconciliation::getKindEnum, PaymentKind.HOSPITAL_DEPOSIT.getValue())
            .eq(PaymentReconciliation::getDeleteFlag, DelFlag.NO.getCode()).last(YbCommonConstants.sqlConst.LIMIT1));
    }

    /**
     * 查询已收费付款实体
     *
     * @param encounterId 就诊id
     * @return 付款实体
     */
    @Override
    public List<PaymentReconciliation> getListByEncounterId(Long encounterId, PaymentKind paymentKind) {
        return baseMapper.selectList(new LambdaQueryWrapper<PaymentReconciliation>()
                .eq(PaymentReconciliation::getEncounterId, encounterId)
                .in(PaymentReconciliation::getStatusEnum, PaymentStatus.SUCCESS.getValue(),PaymentStatus.REFUNDING.getValue())
                .eq(PaymentReconciliation::getKindEnum, PaymentKind.HOSPITAL_DEPOSIT.getValue())
                .eq(PaymentReconciliation::getDeleteFlag, DelFlag.NO.getCode()));
    }

    /**
     * 判断是否已退费
     *
     * @param paymentId 原单id
     * @return 结果
     */
    @Override
    public boolean isReturn(Long paymentId) {
        List<PaymentReconciliation> paymentReconciliations = baseMapper.selectList(
            new LambdaQueryWrapper<PaymentReconciliation>().eq(PaymentReconciliation::getRelationId, paymentId)
                .in(PaymentReconciliation::getStatusEnum, PaymentStatus.REFUNDING.getValue(),
                    PaymentStatus.REFUND_ALL.getValue(), PaymentStatus.REFUND_PART.getValue())
                .eq(PaymentReconciliation::getDeleteFlag, DelFlag.NO.getCode()));
        if (paymentReconciliations != null && paymentReconciliations.size() > 0) {
            return true;
        }
        return false;
    }

    /**
     * 查询实体集合
     *
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param entererId 款员id
     * @param contractNo 合同编号
     * @param success 状态
     * @param returnAll 状态
     * @param clinic 类型
     * @return 集合
     */
    @Override
    public List<PaymentReconciliationAccountDel> getPaymentAccountContract(String startTime, String endTime,
        Long entererId, String contractNo, Integer success, Integer returnAll, Integer clinic) {
        return baseMapper.getPaymentAccountContract(startTime, endTime, entererId, contractNo, success, returnAll,
            clinic);
    }

    /**
     * 查询自付比例等
     * 
     * @param paymentedItemList 收款明细
     * @return 学生付款实体
     */
    private List<StudentPaymentItemModel> getStudentPaymentItemModelList(List<PaymentedItemModel> paymentedItemList) {

        // 大项比例
        List<GfTypeRatioDto> typeRatioList = gfRatioService.getTypeRatioList();
        Map<String, Map<String, List<GfTypeRatioDto>>> result = typeRatioList.stream().collect(
            // 第一次分组：按 ybClass 分组（外层 key 为 ybClass）
            Collectors.groupingBy(GfTypeRatioDto::getYbClass,
                // 第二次分组：对每个分组的 List 再按 subType 分组（内层 key 为 subType）
                Collectors.groupingBy(GfTypeRatioDto::getYbLv)));

        List<StudentPaymentItemModel> allPaymentItemList = new ArrayList<>();

        Map<String, List<PaymentedItemModel>> paymentedItemListByServiceTableMap =
            paymentedItemList.stream().collect(Collectors.groupingBy(PaymentedItemModel::getServiceTable));

        for (Map.Entry<String, List<PaymentedItemModel>> stringListEntry : paymentedItemListByServiceTableMap
            .entrySet()) {

            String key = stringListEntry.getKey();
            ItemType itemType;
            if (CommonConstants.TableName.MED_MEDICATION_REQUEST.equals(key)) {
                itemType = ItemType.MEDICINE;
            } else if (CommonConstants.TableName.WOR_SERVICE_REQUEST.equals(key)) {
                itemType = ItemType.ACTIVITY;
            } else {
                throw new ServiceException("除药品和诊疗项目外不存在其他公费项目，请确认！");
            }
            List<PaymentedItemModel> value = stringListEntry.getValue();
            List<StudentPaymentItemModel> paymentItemList = gfRatioService.getGfRatioList(itemType, value);

            for (StudentPaymentItemModel studentPaymentItemModel : paymentItemList) {

                // 如果自付比例有值，就continue掉
                if (studentPaymentItemModel.getSelfRatio() != null && studentPaymentItemModel.getTwiceRatio() != null) {
                    continue;
                }
                // 查定价分类
                ChargeItemDefinition chargeItemDefinition =
                    chargeItemDefinitionService.getById(studentPaymentItemModel.getDefinitionId());

                // 查医保等级
                if (CommonConstants.TableName.ADM_DEVICE_DEFINITION.equals(studentPaymentItemModel.getProductTable())) {
                    DeviceDefinition deviceDefinition =
                        deviceDefinitionService.getById(studentPaymentItemModel.getProductId());
                    if (deviceDefinition != null && chargeItemDefinition != null) {
                        // 约定大项目的自付比例获取条件
                        YbMedChrgItmType medChrgItmType = YbMedChrgItmType.getByValue(chargeItemDefinition.getYbType());
                        if (medChrgItmType == null) {
                            throw new ServiceException(chargeItemDefinition.getChargeName() + "未配置正确的医保分类！请检查！！！");
                        }
                        YbChrgitmLv chrgitmLv = YbChrgitmLv.getByValue(deviceDefinition.getChrgitmLv());
                        if (chrgitmLv == null) {
                            throw new ServiceException(chargeItemDefinition.getChargeName() + "未配置正确的医保等级！请检查！！！");
                        }
                        List<GfTypeRatioDto> gfTypeRatioDtos =
                            result.get(chargeItemDefinition.getYbType()).get(chrgitmLv.getCode());
                        if (gfTypeRatioDtos == null || gfTypeRatioDtos.isEmpty()) {
                            throw new ServiceException(
                                "医保分类：" + medChrgItmType.getInfo() + "医保等级：" + chrgitmLv.getInfo() + "未配置自付比例！请检查！！！");
                        }

                        studentPaymentItemModel.setSelfRatio(gfTypeRatioDtos.get(0).getSelfRatio());
                        studentPaymentItemModel.setTwiceRatio(gfTypeRatioDtos.get(0).getSelfRatio());

                    }
                } else if (CommonConstants.TableName.WOR_ACTIVITY_DEFINITION
                    .equals(studentPaymentItemModel.getProductTable())) {
                    ActivityDefinition activityDefinition =
                        activityDefinitionService.getById(studentPaymentItemModel.getProductId());
                    if (activityDefinition != null && chargeItemDefinition != null) {
                        // 约定大项目的自付比例获取条件
                        YbMedChrgItmType medChrgItmType = YbMedChrgItmType.getByValue(chargeItemDefinition.getYbType());
                        if (medChrgItmType == null) {
                            throw new ServiceException(chargeItemDefinition.getChargeName() + "未配置正确的医保分类！请检查！！！");
                        }
                        YbChrgitmLv chrgitmLv = YbChrgitmLv.getByValue(activityDefinition.getChrgitmLv());
                        if (chrgitmLv == null) {
                            throw new ServiceException(chargeItemDefinition.getChargeName() + "未配置正确的医保等级！请检查！！！");
                        }
                        List<GfTypeRatioDto> gfTypeRatioDtos =
                            result.get(chargeItemDefinition.getYbType()).get(chrgitmLv.getCode());
                        if (gfTypeRatioDtos == null || gfTypeRatioDtos.isEmpty()) {
                            throw new ServiceException(
                                "医保分类：" + medChrgItmType.getInfo() + "医保等级：" + chrgitmLv.getInfo() + "未配置自付比例！请检查！！！");
                        }

                        studentPaymentItemModel.setSelfRatio(gfTypeRatioDtos.get(0).getSelfRatio());
                        studentPaymentItemModel.setTwiceRatio(gfTypeRatioDtos.get(0).getSelfRatio());
                    }
                } else if (CommonConstants.TableName.MED_MEDICATION_DEFINITION
                    .equals(studentPaymentItemModel.getProductTable())) {
                    MedicationDefinition medicationDefinition =
                        medicationDefinitionService.getById(studentPaymentItemModel.getProductId());
                    if (medicationDefinition != null && chargeItemDefinition != null) {
                        // 约定大项目的自付比例获取条件
                        YbMedChrgItmType medChrgItmType = YbMedChrgItmType.getByValue(chargeItemDefinition.getYbType());
                        if (medChrgItmType == null) {
                            throw new ServiceException(chargeItemDefinition.getChargeName() + "未配置正确的医保分类！请检查！！！");
                        }
                        YbChrgitmLv chrgitmLv = YbChrgitmLv.getByValue(medicationDefinition.getChrgitmLv());
                        if (chrgitmLv == null) {
                            throw new ServiceException(chargeItemDefinition.getChargeName() + "未配置正确的医保等级！请检查！！！");
                        }
                        List<GfTypeRatioDto> gfTypeRatioDtos =
                            result.get(chargeItemDefinition.getYbType()).get(chrgitmLv.getCode());
                        if (gfTypeRatioDtos == null || gfTypeRatioDtos.isEmpty()) {
                            throw new ServiceException(
                                "医保分类：" + medChrgItmType.getInfo() + "医保等级：" + chrgitmLv.getInfo() + "未配置自付比例！请检查！！！");
                        }

                        studentPaymentItemModel.setSelfRatio(gfTypeRatioDtos.get(0).getSelfRatio());
                        studentPaymentItemModel.setTwiceRatio(gfTypeRatioDtos.get(0).getSelfRatio());
                    }
                } else {
                    HealthcareService healthcareService =
                        healthcareServiceService.getById(studentPaymentItemModel.getServiceId());
                    if (healthcareService != null && chargeItemDefinition != null) {
                        // 约定大项目的自付比例获取条件 医疗服务没有定义医保等级，默认百分百还是直接抛异常？
                        studentPaymentItemModel.setSelfRatio(new BigDecimal("100"));
                        studentPaymentItemModel.setTwiceRatio(new BigDecimal("100"));
                    }
                }
                allPaymentItemList.addAll(paymentItemList);
            }
        }
        return allPaymentItemList;
    }

    /**
     * 医保预结算
     * 
     * @param contract 合同b
     * @param ybMdtrtCertType 证件类型
     * @param busiCardInfo 电子密钥
     * @param paymentedItemList 收款明细
     * @return 预结算参数
     */
    private PrePaymentResult studentPreSettleYb(Contract contract, YbMdtrtCertType ybMdtrtCertType, String busiCardInfo,
        List<PaymentedItemModel> paymentedItemList) {
        Map<String, List<PaymentedItemModel>> collect =
            paymentedItemList.stream().collect(Collectors.groupingBy(PaymentedItemModel::getMedType));
        // 一次医保结算只能支持一种医疗类型的结算
        for (Map.Entry<String, List<PaymentedItemModel>> medTypeKV : collect.entrySet()) {
            Clinic2206OrderOutput clinic2206OrderOutput = null;
            ClinicReg2201Output reg2201Output = null;
            if (!medTypeKV.getKey().equals(YbMedType.GENERAL_OUTPATIENT.getValue()) && "1"
                .equals(SecurityUtils.getLoginUser().getOptionJson().getString(CommonConstants.Option.YB_SWITCH))) {
                // 不是普通门诊就诊类型，补充挂号信息
                reg2201Output = ybManager.createRegWithMedType(contract, ybMdtrtCertType, busiCardInfo,
                    medTypeKV.getValue().get(0).getEncounterId(),
                    YbMedType.getByValue(medTypeKV.getValue().get(0).getMedType()));
                reg2201Output.setMedType(medTypeKV.getKey());// 2025/06/05慢病挂号后上传2206信息报错，2201返回值没有medType，此处更正赋值
            } else {
                // 从数据库里取reg2201
                reg2201Output = ybManager.getClinicRegByEncounterId(medTypeKV.getValue().get(0).getEncounterId());
            }
            if (reg2201Output == null) {
                throw new ServiceException("未查询到医保挂号信息");
            }
            // 调用预结算
            clinic2206OrderOutput =
                ybManager.preSettle(contract, medTypeKV.getValue().get(0).getEncounterId(), ybMdtrtCertType,
                    busiCardInfo, reg2201Output, "01", medTypeKV.getValue(), YbMedType.getByValue(medTypeKV.getKey()));
            PrePaymentResult prePaymentResult = new PrePaymentResult();
            BeanUtils.copyProperties(clinic2206OrderOutput, prePaymentResult);
            return prePaymentResult;
        }
        return null;
    }

}
