package com.openhis.web.doctorstation.appservice.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
import com.core.common.enums.TenantOptionDict;
import com.core.common.exception.ServiceException;
import com.core.common.utils.AssignSeqUtil;
import com.core.common.utils.MessageUtils;
import com.core.common.utils.SecurityUtils;
import com.core.common.utils.StringUtils;
import com.core.web.util.TenantOptionUtil;
import com.openhis.administration.domain.ChargeItem;
import com.openhis.administration.service.IChargeItemService;
import com.openhis.common.constant.CommonConstants;
import com.openhis.common.constant.PromptMsgConstant;
import com.openhis.common.enums.*;
import com.openhis.common.utils.EnumUtils;
import com.openhis.common.utils.HisQueryUtils;
import com.openhis.medication.domain.MedicationRequest;
import com.openhis.medication.service.IMedicationDispenseService;
import com.openhis.medication.service.IMedicationRequestService;
import com.openhis.web.doctorstation.appservice.IDoctorStationAdviceAppService;
import com.openhis.web.doctorstation.dto.*;
import com.openhis.web.doctorstation.mapper.DoctorStationAdviceAppMapper;
import com.openhis.web.doctorstation.utils.AdviceUtils;
import com.openhis.web.doctorstation.utils.DoctorStationSendApplyUtil;
import com.openhis.web.doctorstation.utils.PrescriptionUtils;
import com.openhis.workflow.domain.ActivityDefinition;
import com.openhis.workflow.domain.DeviceRequest;
import com.openhis.workflow.domain.ServiceRequest;
import com.openhis.workflow.service.IActivityDefinitionService;
import com.openhis.workflow.service.IDeviceDispenseService;
import com.openhis.workflow.service.IDeviceRequestService;
import com.openhis.workflow.service.IServiceRequestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 医生站-医嘱/处方 应用实现类
 */
@Slf4j
@Service
public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAppService {

    @Resource
    AssignSeqUtil assignSeqUtil;

    @Resource
    DoctorStationAdviceAppMapper doctorStationAdviceAppMapper;

    @Resource
    IMedicationRequestService iMedicationRequestService;

    @Resource
    IDeviceRequestService iDeviceRequestService;

    @Resource
    IServiceRequestService iServiceRequestService;

    @Resource
    IChargeItemService iChargeItemService;

    // @Resource
    // IOrganizationLocationService iOrganizationLocationService;

    @Resource
    IMedicationDispenseService iMedicationDispenseService;

    @Resource
    IDeviceDispenseService iDeviceDispenseService;

    @Resource
    PrescriptionUtils prescriptionUtils;

    @Resource
    AdviceUtils adviceUtils;

    @Resource
    IActivityDefinitionService iActivityDefinitionService;

    // @Resource
    // OutpatientRegistrationAppMapper outpatientRegistrationAppMapper;

    @Resource
    DoctorStationSendApplyUtil doctorStationSendApplyUtil;

    /**
     * 查询医嘱信息
     *
     * @param adviceBaseDto               查询条件
     * @param searchKey                   模糊查询关键字
     * @param locationId                  药房id
     * @param adviceDefinitionIdParamList 医嘱定义id参数集合
     * @param organizationId              患者挂号对应的科室id
     * @param pageNo                      当前页
     * @param pageSize                    每页多少条
     * @param pricingFlag                 划价标记
     * @param adviceTypes                 医嘱类型参数集合
     * @return 医嘱信息
     */
    @Override
    public IPage<AdviceBaseDto> getAdviceBaseInfo(AdviceBaseDto adviceBaseDto, String searchKey, Long locationId,
                                                  List<Long> adviceDefinitionIdParamList, Long organizationId, Integer pageNo, Integer pageSize,
                                                  Integer pricingFlag, List<Integer> adviceTypes) {
        // 医嘱定价来源
        String orderPricingSource = TenantOptionUtil.getOptionContent(TenantOptionDict.ORDER_PRICING_SOURCE);
        if (StringUtils.isEmpty(orderPricingSource)) {
            throw new ServiceException("租户配置项【医嘱定价来源】未配置");
        }
        // 构建查询条件
        QueryWrapper<AdviceBaseDto> queryWrapper = HisQueryUtils.buildQueryWrapper(adviceBaseDto, searchKey,
                new HashSet<>(Arrays.asList("advice_name", "py_str", "wb_str")), null);
        IPage<AdviceBaseDto> adviceBaseInfo = doctorStationAdviceAppMapper.getAdviceBaseInfo(
                new Page<>(pageNo, pageSize), PublicationStatus.ACTIVE.getValue(), organizationId,
                CommonConstants.TableName.MED_MEDICATION_DEFINITION, CommonConstants.TableName.ADM_DEVICE_DEFINITION,
                CommonConstants.TableName.WOR_ACTIVITY_DEFINITION, pricingFlag, adviceDefinitionIdParamList, adviceTypes,
                queryWrapper);
        List<AdviceBaseDto> adviceBaseDtoList = adviceBaseInfo.getRecords();
        // 医嘱定义ID集合
        List<Long> adviceDefinitionIdList =
                adviceBaseDtoList.stream().map(AdviceBaseDto::getAdviceDefinitionId).collect(Collectors.toList());
        // 费用定价主表ID集合
        List<Long> chargeItemDefinitionIdList =
                adviceBaseDtoList.stream().map(AdviceBaseDto::getChargeItemDefinitionId).collect(Collectors.toList());
        // 医嘱库存集合
        List<AdviceInventoryDto> adviceInventoryList =
                doctorStationAdviceAppMapper.getAdviceInventory(locationId, adviceDefinitionIdList,
                        CommonConstants.SqlCondition.ABOUT_INVENTORY_TABLE_STR, PublicationStatus.ACTIVE.getValue());
        // 待发放个数信息
        List<AdviceInventoryDto> adviceDraftInventoryList = doctorStationAdviceAppMapper.getAdviceDraftInventory(
                CommonConstants.TableName.MED_MEDICATION_DEFINITION, CommonConstants.TableName.ADM_DEVICE_DEFINITION,
                DispenseStatus.DRAFT.getValue(), DispenseStatus.PREPARATION.getValue());
        // 预减库存
        List<AdviceInventoryDto> adviceInventory =
                adviceUtils.subtractInventory(adviceInventoryList, adviceDraftInventoryList);
        // 查询取药科室配置
        List<AdviceInventoryDto> medLocationConfig = doctorStationAdviceAppMapper.getMedLocationConfig(organizationId);
        // 将配置转为 {categoryCode -> 允许的locationId集合}
        Map<String, Set<Long>> allowedLocByCategory = new HashMap<>();
        if (medLocationConfig != null && !medLocationConfig.isEmpty()) {
            for (AdviceInventoryDto cfg : medLocationConfig) {
                if (cfg.getCategoryCode() == null || cfg.getLocationId() == null) {
                    continue;
                }
                allowedLocByCategory.computeIfAbsent(String.valueOf(cfg.getCategoryCode()), k -> new HashSet<>())
                    .add(cfg.getLocationId());
            }
        }
        // 费用定价子表信息
        List<AdvicePriceDto> childCharge = doctorStationAdviceAppMapper
                .getChildCharge(ConditionCode.LOT_NUMBER_PRICE.getCode(), chargeItemDefinitionIdList);
        // 费用定价主表信息
        List<AdvicePriceDto> mainCharge =
                doctorStationAdviceAppMapper.getMainCharge(chargeItemDefinitionIdList, PublicationStatus.ACTIVE.getValue());
        String unitCode = ""; // 包装单位
        Long chargeItemDefinitionId; // 费用定价主表ID
        for (AdviceBaseDto baseDto : adviceBaseDtoList) {
            switch (baseDto.getAdviceTableName()) {
                case CommonConstants.TableName.MED_MEDICATION_DEFINITION: // 药品
                    // 是否皮试
                    baseDto
                            .setSkinTestFlag_enumText(EnumUtils.getInfoByValue(Whether.class, baseDto.getSkinTestFlag()));
                    // 是否为注射药物
                    baseDto.setInjectFlag_enumText(EnumUtils.getInfoByValue(Whether.class, baseDto.getInjectFlag()));
                case CommonConstants.TableName.ADM_DEVICE_DEFINITION: // 耗材
                    // 每一条医嘱的库存集合信息 , 包装单位库存前端计算
                    List<
                            AdviceInventoryDto> inventoryList =
                            adviceInventory.stream()
                                    .filter(e -> baseDto.getAdviceDefinitionId().equals(e.getItemId())
                                            && baseDto.getAdviceTableName().equals(e.getItemTable()))
                                    .collect(Collectors.toList());
                    // 库存信息
                    baseDto.setInventoryList(inventoryList);
                    // 设置默认产品批号
                    if (!inventoryList.isEmpty()) {
                        // 库存大于0
                        List<AdviceInventoryDto> hasInventoryList = inventoryList.stream()
                                .filter(e -> e.getQuantity().compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toList());
                        if (!hasInventoryList.isEmpty()) {
                            baseDto.setDefaultLotNumber(hasInventoryList.get(0).getLotNumber());
                        }
                    }
                    if (!inventoryList.isEmpty() && !medLocationConfig.isEmpty()) {
                        // 第一步：在medLocationConfig中匹配categoryCode
                        AdviceInventoryDto result1 = medLocationConfig.stream()
                                .filter(dto -> baseDto.getCategoryCode().equals(dto.getCategoryCode())).findFirst()
                                .orElse(null);
                        if (result1 != null) {
                            // 第二步：在inventoryList中匹配locationId
                            AdviceInventoryDto result2 = inventoryList.stream()
                                    .filter(dto -> result1.getLocationId().equals(dto.getLocationId())).findFirst()
                                    .orElse(null);
                            if (result2 != null && result2.getLotNumber() != null) {
                                baseDto.setDefaultLotNumber(result2.getLotNumber());
                            }
                        }
                    }
                    unitCode = baseDto.getUnitCode();
                    chargeItemDefinitionId = baseDto.getChargeItemDefinitionId();
                    List<AdvicePriceDto> priceDtoList = new ArrayList<>();
                    // 库存信息里取 命中条件 去匹配价格
                    for (AdviceInventoryDto adviceInventoryDto : inventoryList) {
                        Long finalChargeItemDefinitionId = chargeItemDefinitionId;
                        String finalUnitCode = unitCode;
                        // 从定价子表取价格(适用于批次售卖场景)
                        List<AdvicePriceDto> childPrice = childCharge.stream()
                                .filter(e -> e.getDefinitionId().equals(finalChargeItemDefinitionId)
                                        && e.getConditionValue().equals(adviceInventoryDto.getLotNumber()))
                                .peek(e -> e.setUnitCode(finalUnitCode)) // 设置 unitCode
                                .collect(Collectors.toList());
                        // 从定价主表取价格(适用于统一零售价场景)
                        List<AdvicePriceDto> mainPrice = mainCharge.stream()
                                .filter(e -> baseDto.getChargeItemDefinitionId().equals(e.getDefinitionId()))
                                .collect(Collectors.toList());
                        // 按批次售价
                        if (OrderPricingSource.BATCH_SELLING_PRICE.getCode().equals(orderPricingSource)) {
                            priceDtoList.addAll(childPrice);
                        } else {
                            priceDtoList.addAll(mainPrice);
                        }
                    }
                    // 价格信息
                    baseDto.setPriceList(priceDtoList);
                    break;
                case CommonConstants.TableName.WOR_ACTIVITY_DEFINITION: // 诊疗
                    List<AdvicePriceDto> priceList =
                            mainCharge.stream().filter(e -> baseDto.getChargeItemDefinitionId().equals(e.getDefinitionId()))
                                    .collect(Collectors.toList());
                    // 价格信息
                    baseDto.setPriceList(priceList);
                    // 活动类型
                    baseDto.setActivityType_enumText(
                            EnumUtils.getInfoByValue(ActivityType.class, baseDto.getActivityType()));
                    break;
                default:
                    break;
            }
        }
        return adviceBaseInfo;
    }

    /**
     * 查询医嘱绑定信息
     *
     * @param typeCode 1:用法绑东西 2:诊疗绑东西
     * @param itemNo   用法的code 或者 诊疗定义id
     * @return 医嘱绑定信息
     */
    @Override
    public List<OrderBindInfoDto> getOrderBindInfo(String typeCode, String itemNo) {
        return doctorStationAdviceAppMapper.getOrderBindInfo(typeCode, PublicationStatus.ACTIVE.getValue(), itemNo);
    }

    /**
     * 门诊保存/签发医嘱
     *
     * @param adviceSaveParam 医嘱表单信息
     * @param adviceOpType    医嘱操作类型
     * @return 结果
     */
    @Override
    public R<?> saveAdvice(AdviceSaveParam adviceSaveParam, String adviceOpType) {
        // 患者挂号对应的科室id
        Long organizationId = adviceSaveParam.getOrganizationId();
        // 医嘱分类信息
        List<AdviceSaveDto> adviceSaveList = adviceSaveParam.getAdviceSaveList();
        // 药品
        List<AdviceSaveDto> medicineList = adviceSaveList.stream()
                .filter(e -> ItemType.MEDICINE.getValue().equals(e.getAdviceType())).collect(Collectors.toList());
        // 耗材
        List<AdviceSaveDto> deviceList = adviceSaveList.stream()
                .filter(e -> ItemType.DEVICE.getValue().equals(e.getAdviceType())).collect(Collectors.toList());
        // 诊疗活动
        List<AdviceSaveDto> activityList = adviceSaveList.stream()
                .filter(e -> ItemType.ACTIVITY.getValue().equals(e.getAdviceType())).collect(Collectors.toList());

        /**
         * 保存时,校验库存
         */
        if (AdviceOpType.SAVE_ADVICE.getCode().equals(adviceOpType)) {
            List<AdviceSaveDto> needCheckList =
                    adviceSaveList.stream().filter(e -> !DbOpType.DELETE.getCode().equals(e.getDbOpType())
                            && !ItemType.ACTIVITY.getValue().equals(e.getAdviceType())).collect(Collectors.toList());
            // 校验库存
            String tipRes = adviceUtils.checkInventory(needCheckList);
            if (tipRes != null) {
                return R.fail(null, tipRes);
            }
        }
        // 当前时间
        Date curDate = new Date();
        // 医嘱签发编码
        String signCode = assignSeqUtil.getSeq(AssignSeqEnum.ADVICE_SIGN.getPrefix(), 10);

        /**
         * 处理药品请求
         */
        this.handMedication(medicineList, curDate, adviceOpType, organizationId, signCode);

        /**
         * 处理诊疗项目请求
         */
        this.handService(activityList, curDate, adviceOpType, organizationId, signCode);

        /**
         * 处理耗材请求
         */
        this.handDevice(deviceList, curDate, adviceOpType);

        // 签发时,把草稿状态的账单更新为待收费
        if (AdviceOpType.SIGN_ADVICE.getCode().equals(adviceOpType) && !adviceSaveList.isEmpty()) {
            // 签发的医嘱id集合
            List<Long> requestIds = adviceSaveList.stream()
                    .filter(e -> !DbOpType.DELETE.getCode().equals(e.getDbOpType()) && e.getRequestId() != null)
                    .collect(Collectors.toList()).stream().map(AdviceSaveDto::getRequestId).collect(Collectors.toList());
            // 就诊id
            Long encounterId = adviceSaveList.get(0).getEncounterId();
            iChargeItemService.update(new LambdaUpdateWrapper<ChargeItem>()
                    .set(ChargeItem::getStatusEnum, ChargeItemStatus.PLANNED.getValue())
                    .eq(ChargeItem::getEncounterId, encounterId)
                    .eq(ChargeItem::getStatusEnum, ChargeItemStatus.DRAFT.getValue())
                    .in(ChargeItem::getServiceId, requestIds));
        }

        return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"门诊医嘱"}));
    }

    /**
     * 处理药品
     */
    private void handMedication(List<AdviceSaveDto> medicineList, Date curDate, String adviceOpType,
                                Long organizationId, String signCode) {
        // 当前登录账号的科室id
        Long orgId = SecurityUtils.getLoginUser().getOrgId();
        // 保存操作
        boolean is_save = AdviceOpType.SAVE_ADVICE.getCode().equals(adviceOpType);
        // 签发操作
        boolean is_sign = AdviceOpType.SIGN_ADVICE.getCode().equals(adviceOpType);
        // 保存药品请求
        MedicationRequest medicationRequest;
        // 声明费用项
        ChargeItem chargeItem;
        // 新增 + 修改
        List<AdviceSaveDto> insertOrUpdateList =
                medicineList.stream().filter(e -> (DbOpType.INSERT.getCode().equals(e.getDbOpType())
                        || DbOpType.UPDATE.getCode().equals(e.getDbOpType()))).collect(Collectors.toList());
        // 删除
        List<AdviceSaveDto> deleteList = medicineList.stream()
                .filter(e -> DbOpType.DELETE.getCode().equals(e.getDbOpType())).collect(Collectors.toList());
        // 校验删除的医嘱是否已经收费
        List<Long> delRequestIdList = deleteList.stream().map(AdviceSaveDto::getRequestId).collect(Collectors.toList());
        if (!delRequestIdList.isEmpty()) {
            List<ChargeItem> chargeItemList = iChargeItemService.getChargeItemInfoByReqId(delRequestIdList);
            if (chargeItemList != null && !chargeItemList.isEmpty()) {
                for (ChargeItem ci : chargeItemList) {
                    if (ChargeItemStatus.BILLED.getValue().equals(ci.getStatusEnum())) {
                        throw new ServiceException("已收费的项目无法删除，请刷新页面后重试");
                    }
                }
            }
        }
        for (AdviceSaveDto adviceSaveDto : deleteList) {
            iMedicationRequestService.removeById(adviceSaveDto.getRequestId());
            // 删除已经产生的药品发放信息
            iMedicationDispenseService.deleteMedicationDispense(adviceSaveDto.getRequestId());
            // 删除费用项
            iChargeItemService.deleteByServiceTableAndId(CommonConstants.TableName.MED_MEDICATION_REQUEST,
                    adviceSaveDto.getRequestId());
            // 删除基于这个药品生成的需要执行的诊疗请求
            iServiceRequestService.remove(
                    new LambdaQueryWrapper<ServiceRequest>().eq(ServiceRequest::getBasedOnId, adviceSaveDto.getRequestId())
                            .isNotNull(ServiceRequest::getBasedOnTable)
                            .eq(ServiceRequest::getStatusEnum, RequestStatus.COMPLETED.getValue()));
        }
        // 签发时
        if (is_sign) {
            // 生成处方号
            prescriptionUtils.generatePrescriptionNumbers(insertOrUpdateList);
        }

        for (AdviceSaveDto adviceSaveDto : insertOrUpdateList) {
            medicationRequest = new MedicationRequest();
            medicationRequest.setId(adviceSaveDto.getRequestId()); // 主键id
            medicationRequest.setStatusEnum(is_save ? RequestStatus.DRAFT.getValue() : RequestStatus.ACTIVE.getValue()); // 请求状态
            medicationRequest.setPrescriptionNo(adviceSaveDto.getPrescriptionNo()); // 处方号
            medicationRequest.setGroupId(adviceSaveDto.getGroupId()); // 组号
            if (is_sign) {
                medicationRequest.setSignCode(signCode);
            }
            // 保存时,处理数据(请求,发放,账单)
            if (is_save) {
                medicationRequest.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.MEDICATION_RES_NO.getPrefix(), 4));
                medicationRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
                medicationRequest.setQuantity(adviceSaveDto.getQuantity()); // 请求数量
                medicationRequest.setExecuteNum(adviceSaveDto.getExecuteNum()); // 执行次数
                medicationRequest.setUnitCode(adviceSaveDto.getUnitCode()); // 请求单位编码
                medicationRequest.setLotNumber(adviceSaveDto.getLotNumber()); // 产品批号
                medicationRequest.setCategoryEnum(adviceSaveDto.getCategoryEnum()); // 请求类型
                medicationRequest.setMedicationId(adviceSaveDto.getAdviceDefinitionId());// 医嘱定义id
                medicationRequest.setPatientId(adviceSaveDto.getPatientId()); // 患者
                medicationRequest.setPractitionerId(adviceSaveDto.getPractitionerId()); // 开方医生
                medicationRequest.setOrgId(adviceSaveDto.getFounderOrgId()); // 开方人科室
                medicationRequest.setReqAuthoredTime(curDate); // 请求开始时间
                // 发放药房
                medicationRequest.setPerformLocation(adviceSaveDto.getLocationId());
                medicationRequest.setEncounterId(adviceSaveDto.getEncounterId()); // 就诊id
                medicationRequest.setConditionId(adviceSaveDto.getConditionId()); // 诊断id
                medicationRequest.setEncounterDiagnosisId(adviceSaveDto.getEncounterDiagnosisId()); // 就诊诊断id
                medicationRequest.setTherapyEnum(adviceSaveDto.getTherapyEnum()); // 治疗类型,默认-临时
                medicationRequest.setMethodCode(adviceSaveDto.getMethodCode()); // 用法
                medicationRequest.setRateCode(adviceSaveDto.getRateCode()); // 用药频次
                medicationRequest.setDose(adviceSaveDto.getDose()); // 单次剂量
                medicationRequest.setDoseUnitCode(adviceSaveDto.getDoseUnitCode()); // 剂量单位
                medicationRequest.setDispensePerDuration(adviceSaveDto.getDispensePerDuration()); // 每次发药供应天数
                medicationRequest.setPackageId(adviceSaveDto.getPackageId()); // 组套id
                medicationRequest.setContentJson(adviceSaveDto.getContentJson()); // 请求内容json
                medicationRequest.setYbClassEnum(adviceSaveDto.getYbClassEnum());// 类别医保编码
                medicationRequest.setSkinTestFlag(adviceSaveDto.getSkinTestFlag()); // 皮试标志
                medicationRequest.setInfusionFlag(adviceSaveDto.getInjectFlag()); // 输液标志
                medicationRequest.setSortNumber(adviceSaveDto.getSortNumber()); // 排序号
            }
            iMedicationRequestService.saveOrUpdate(medicationRequest);

            if (is_save) {
                // 处理药品发放
                Long dispenseId =
                        iMedicationDispenseService.handleMedicationDispense(medicationRequest, adviceSaveDto.getDbOpType());

                // 保存药品费用项
                chargeItem = new ChargeItem();
                chargeItem.setId(adviceSaveDto.getChargeItemId()); // 费用项id
                chargeItem.setStatusEnum(ChargeItemStatus.DRAFT.getValue()); // 收费状态
                chargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(medicationRequest.getBusNo()));
                chargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
                chargeItem.setPrescriptionNo(adviceSaveDto.getPrescriptionNo()); // 处方号
                chargeItem.setPatientId(adviceSaveDto.getPatientId()); // 患者
                chargeItem.setContextEnum(adviceSaveDto.getAdviceType()); // 类型
                chargeItem.setEncounterId(adviceSaveDto.getEncounterId()); // 就诊id
                chargeItem.setDefinitionId(adviceSaveDto.getDefinitionId()); // 费用定价ID
                chargeItem.setDefDetailId(adviceSaveDto.getDefinitionDetailId()); // 定价子表主键
                chargeItem.setEntererId(adviceSaveDto.getPractitionerId());// 开立人ID
                chargeItem.setRequestingOrgId(orgId); // 开立科室
                chargeItem.setEnteredDate(curDate); // 开立时间
                chargeItem.setServiceTable(CommonConstants.TableName.MED_MEDICATION_REQUEST);// 医疗服务类型
                chargeItem.setServiceId(medicationRequest.getId()); // 医疗服务ID
                chargeItem.setProductTable(adviceSaveDto.getAdviceTableName());// 产品所在表
                chargeItem.setProductId(adviceSaveDto.getAdviceDefinitionId());// 收费项id
                chargeItem.setAccountId(adviceSaveDto.getAccountId());// 关联账户ID
                chargeItem.setConditionId(adviceSaveDto.getConditionId()); // 诊断id
                chargeItem.setEncounterDiagnosisId(adviceSaveDto.getEncounterDiagnosisId()); // 就诊诊断id
                chargeItem.setDispenseId(dispenseId); // 发放ID

                chargeItem.setQuantityValue(adviceSaveDto.getQuantity()); // 数量
                chargeItem.setQuantityUnit(adviceSaveDto.getUnitCode()); // 单位
                chargeItem.setUnitPrice(adviceSaveDto.getUnitPrice()); // 单价
                chargeItem.setTotalPrice(adviceSaveDto.getTotalPrice()); // 总价

                iChargeItemService.saveOrUpdate(chargeItem);

            }
        }
    }

    /**
     * 处理耗材
     */
    private void handDevice(List<AdviceSaveDto> deviceList, Date curDate, String adviceOpType) {
        // 当前登录账号的科室id
        Long orgId = SecurityUtils.getLoginUser().getOrgId();
        // 保存操作
        boolean is_save = AdviceOpType.SAVE_ADVICE.getCode().equals(adviceOpType);
        // 签发操作
        // boolean is_sign = AdviceOpType.SIGN_ADVICE.getCode().equals(adviceOpType);
        DeviceRequest deviceRequest;
        // 声明费用项
        ChargeItem chargeItem;
        // 新增 + 修改
        List<AdviceSaveDto> insertOrUpdateList =
                deviceList.stream().filter(e -> (DbOpType.INSERT.getCode().equals(e.getDbOpType())
                        || DbOpType.UPDATE.getCode().equals(e.getDbOpType()))).collect(Collectors.toList());
        // 删除
        List<AdviceSaveDto> deleteList = deviceList.stream()
                .filter(e -> DbOpType.DELETE.getCode().equals(e.getDbOpType())).collect(Collectors.toList());
        // 校验删除的医嘱是否已经收费
        List<Long> delRequestIdList = deleteList.stream().map(AdviceSaveDto::getRequestId).collect(Collectors.toList());
        if (!delRequestIdList.isEmpty()) {
            List<ChargeItem> chargeItemList = iChargeItemService.getChargeItemInfoByReqId(delRequestIdList);
            if (chargeItemList != null && !chargeItemList.isEmpty()) {
                for (ChargeItem ci : chargeItemList) {
                    if (ChargeItemStatus.BILLED.getValue().equals(ci.getStatusEnum())) {
                        throw new ServiceException("已收费的项目无法删除，请刷新页面后重试");
                    }
                }
            }
        }
        for (AdviceSaveDto adviceSaveDto : deleteList) {
            iDeviceRequestService.removeById(adviceSaveDto.getRequestId());
            // 删除已经产生的耗材发放信息
            iDeviceDispenseService.deleteDeviceDispense(adviceSaveDto.getRequestId());
            // 删除费用项
            iChargeItemService.deleteByServiceTableAndId(CommonConstants.TableName.WOR_DEVICE_REQUEST,
                    adviceSaveDto.getRequestId());
        }

        for (AdviceSaveDto adviceSaveDto : insertOrUpdateList) {
            deviceRequest = new DeviceRequest();
            deviceRequest.setId(adviceSaveDto.getRequestId()); // 主键id
            deviceRequest.setStatusEnum(is_save ? RequestStatus.DRAFT.getValue() : RequestStatus.ACTIVE.getValue()); // 请求状态

            // 保存时,处理数据(请求,发放,账单)
            if (is_save) {
                deviceRequest.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.DEVICE_RES_NO.getPrefix(), 4));
                deviceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
                deviceRequest.setQuantity(adviceSaveDto.getQuantity()); // 请求数量
                deviceRequest.setUnitCode(adviceSaveDto.getUnitCode()); // 请求单位编码
                deviceRequest.setLotNumber(adviceSaveDto.getLotNumber());// 产品批号

                deviceRequest.setCategoryEnum(adviceSaveDto.getCategoryEnum()); // 请求类型
                deviceRequest.setDeviceDefId(adviceSaveDto.getAdviceDefinitionId());// 耗材定义id
                deviceRequest.setPatientId(adviceSaveDto.getPatientId()); // 患者
                deviceRequest.setRequesterId(adviceSaveDto.getPractitionerId()); // 开方医生
                deviceRequest.setOrgId(adviceSaveDto.getFounderOrgId());// 开方人科室
                deviceRequest.setReqAuthoredTime(curDate); // 请求开始时间
                // 发放耗材房
                deviceRequest.setPerformLocation(adviceSaveDto.getLocationId());
                deviceRequest.setEncounterId(adviceSaveDto.getEncounterId()); // 就诊id
                deviceRequest.setPackageId(adviceSaveDto.getPackageId()); // 组套id
                // deviceRequest.setActivityId(adviceSaveDto.getActivityId());
                deviceRequest.setContentJson(adviceSaveDto.getContentJson()); // 请求内容json
                deviceRequest.setYbClassEnum(adviceSaveDto.getYbClassEnum());// 类别医保编码
                deviceRequest.setConditionId(adviceSaveDto.getConditionId()); // 诊断id
                deviceRequest.setEncounterDiagnosisId(adviceSaveDto.getEncounterDiagnosisId()); // 就诊诊断id

            }
            iDeviceRequestService.saveOrUpdate(deviceRequest);
            if (is_save) {
                // 处理耗材发放
                Long dispenseId =
                        iDeviceDispenseService.handleDeviceDispense(deviceRequest, adviceSaveDto.getDbOpType());

                // 保存耗材费用项
                chargeItem = new ChargeItem();
                chargeItem.setId(adviceSaveDto.getChargeItemId()); // 费用项id
                chargeItem.setStatusEnum(ChargeItemStatus.DRAFT.getValue()); // 收费状态
                chargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(deviceRequest.getBusNo()));
                chargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
                chargeItem.setPatientId(adviceSaveDto.getPatientId()); // 患者
                chargeItem.setContextEnum(adviceSaveDto.getAdviceType()); // 类型
                chargeItem.setEncounterId(adviceSaveDto.getEncounterId()); // 就诊id
                chargeItem.setDefinitionId(adviceSaveDto.getDefinitionId()); // 费用定价ID
                chargeItem.setDefDetailId(adviceSaveDto.getDefinitionDetailId()); // 定价子表主键
                chargeItem.setEntererId(adviceSaveDto.getPractitionerId());// 开立人ID
                chargeItem.setRequestingOrgId(orgId); // 开立科室
                chargeItem.setEnteredDate(curDate); // 开立时间
                chargeItem.setServiceTable(CommonConstants.TableName.WOR_DEVICE_REQUEST);// 医疗服务类型
                chargeItem.setServiceId(deviceRequest.getId()); // 医疗服务ID
                chargeItem.setProductTable(adviceSaveDto.getAdviceTableName());// 产品所在表
                chargeItem.setProductId(adviceSaveDto.getAdviceDefinitionId());// 收费项id
                chargeItem.setAccountId(adviceSaveDto.getAccountId());// 关联账户ID
                chargeItem.setConditionId(adviceSaveDto.getConditionId()); // 诊断id
                chargeItem.setEncounterDiagnosisId(adviceSaveDto.getEncounterDiagnosisId()); // 就诊诊断id
                chargeItem.setDispenseId(dispenseId); // 发放ID

                chargeItem.setQuantityValue(adviceSaveDto.getQuantity()); // 数量
                chargeItem.setQuantityUnit(adviceSaveDto.getUnitCode()); // 单位
                chargeItem.setUnitPrice(adviceSaveDto.getUnitPrice()); // 单价
                chargeItem.setTotalPrice(adviceSaveDto.getTotalPrice()); // 总价

                iChargeItemService.saveOrUpdate(chargeItem);
            }
        }
    }

    /**
     * 处理诊疗
     */
    private void handService(List<AdviceSaveDto> activityList, Date curDate, String adviceOpType, Long organizationId,
                             String signCode) {
        // 当前登录账号的科室id
        Long orgId = SecurityUtils.getLoginUser().getOrgId();
        // 保存操作
        boolean is_save = AdviceOpType.SAVE_ADVICE.getCode().equals(adviceOpType);
        // 签发操作
        boolean is_sign = AdviceOpType.SIGN_ADVICE.getCode().equals(adviceOpType);
        ServiceRequest serviceRequest;
        // 声明费用项
        ChargeItem chargeItem;
        // 新增 + 修改
        List<AdviceSaveDto> insertOrUpdateList =
                activityList.stream().filter(e -> (DbOpType.INSERT.getCode().equals(e.getDbOpType())
                        || DbOpType.UPDATE.getCode().equals(e.getDbOpType()))).collect(Collectors.toList());
        // 删除
        List<AdviceSaveDto> deleteList = activityList.stream()
                .filter(e -> DbOpType.DELETE.getCode().equals(e.getDbOpType())).collect(Collectors.toList());
        // 校验删除的医嘱是否已经收费
        List<Long> delRequestIdList = deleteList.stream().map(AdviceSaveDto::getRequestId).collect(Collectors.toList());
        if (!delRequestIdList.isEmpty()) {
            List<ChargeItem> chargeItemList = iChargeItemService.getChargeItemInfoByReqId(delRequestIdList);
            if (chargeItemList != null && !chargeItemList.isEmpty()) {
                for (ChargeItem ci : chargeItemList) {
                    if (ChargeItemStatus.BILLED.getValue().equals(ci.getStatusEnum())) {
                        throw new ServiceException("已收费的项目无法删除，请刷新页面后重试");
                    }
                }
            }
        }
        for (AdviceSaveDto adviceSaveDto : deleteList) {
            iServiceRequestService.removeById(adviceSaveDto.getRequestId());// 删除诊疗
            iServiceRequestService.remove(
                    new LambdaQueryWrapper<ServiceRequest>().eq(ServiceRequest::getParentId, adviceSaveDto.getRequestId()));// 删除诊疗套餐对应的子项
            // 删除费用项
            iChargeItemService.deleteByServiceTableAndId(CommonConstants.TableName.WOR_SERVICE_REQUEST,
                    adviceSaveDto.getRequestId());
        }

        for (AdviceSaveDto adviceSaveDto : insertOrUpdateList) {
            serviceRequest = new ServiceRequest();
            serviceRequest.setId(adviceSaveDto.getRequestId()); // 主键id
            serviceRequest.setStatusEnum(is_save ? RequestStatus.DRAFT.getValue() : RequestStatus.ACTIVE.getValue());// 请求状态
            if (is_sign) {
                serviceRequest.setSignCode(signCode);
            }
            // 只有保存时才处理的字段属性
            if (is_save) {
                serviceRequest.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.SERVICE_RES_NO.getPrefix(), 4));
                serviceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
                serviceRequest.setQuantity(adviceSaveDto.getQuantity()); // 请求数量
                serviceRequest.setUnitCode(adviceSaveDto.getUnitCode()); // 请求单位编码

                serviceRequest.setCategoryEnum(adviceSaveDto.getCategoryEnum()); // 请求类型
                serviceRequest.setActivityId(adviceSaveDto.getAdviceDefinitionId());// 诊疗定义id
                serviceRequest.setPatientId(adviceSaveDto.getPatientId()); // 患者
                serviceRequest.setRequesterId(adviceSaveDto.getPractitionerId()); // 开方医生
                serviceRequest.setEncounterId(adviceSaveDto.getEncounterId()); // 就诊id
                serviceRequest.setAuthoredTime(curDate); // 请求签发时间
                // 执行科室
                serviceRequest.setOrgId(adviceSaveDto.getPositionId());
                serviceRequest.setContentJson(adviceSaveDto.getContentJson()); // 请求内容json
                serviceRequest.setYbClassEnum(adviceSaveDto.getYbClassEnum());// 类别医保编码
                serviceRequest.setConditionId(adviceSaveDto.getConditionId()); // 诊断id
                serviceRequest.setEncounterDiagnosisId(adviceSaveDto.getEncounterDiagnosisId()); // 就诊诊断id
            }

            iServiceRequestService.saveOrUpdate(serviceRequest);

            // 保存时保存诊疗费用项
            if (is_save) {
                chargeItem = new ChargeItem();
                chargeItem.setId(adviceSaveDto.getChargeItemId()); // 费用项id
                chargeItem.setStatusEnum(ChargeItemStatus.DRAFT.getValue()); // 收费状态
                chargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(serviceRequest.getBusNo()));
                chargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
                chargeItem.setPatientId(adviceSaveDto.getPatientId()); // 患者
                chargeItem.setContextEnum(adviceSaveDto.getAdviceType()); // 类型
                chargeItem.setEncounterId(adviceSaveDto.getEncounterId()); // 就诊id
                chargeItem.setDefinitionId(adviceSaveDto.getDefinitionId()); // 费用定价ID
                chargeItem.setDefDetailId(adviceSaveDto.getDefinitionDetailId()); // 定价子表主键
                chargeItem.setEntererId(adviceSaveDto.getPractitionerId());// 开立人ID
                chargeItem.setEnteredDate(curDate); // 开立时间
                chargeItem.setServiceTable(CommonConstants.TableName.WOR_SERVICE_REQUEST);// 医疗服务类型
                chargeItem.setServiceId(serviceRequest.getId()); // 医疗服务ID
                chargeItem.setProductTable(adviceSaveDto.getAdviceTableName());// 产品所在表
                chargeItem.setProductId(adviceSaveDto.getAdviceDefinitionId());// 收费项id
                chargeItem.setAccountId(adviceSaveDto.getAccountId());// 关联账户ID
                chargeItem.setRequestingOrgId(orgId); // 开立科室
                chargeItem.setConditionId(adviceSaveDto.getConditionId()); // 诊断id
                chargeItem.setEncounterDiagnosisId(adviceSaveDto.getEncounterDiagnosisId()); // 就诊诊断id
                chargeItem.setQuantityValue(adviceSaveDto.getQuantity()); // 数量
                chargeItem.setQuantityUnit(adviceSaveDto.getUnitCode()); // 单位
                chargeItem.setUnitPrice(adviceSaveDto.getUnitPrice()); // 单价
                chargeItem.setTotalPrice(adviceSaveDto.getTotalPrice()); // 总价

                iChargeItemService.saveOrUpdate(chargeItem);

                // 第一次保存时,处理诊疗套餐的子项信息
                if (adviceSaveDto.getRequestId() == null) {
                    ActivityDefinition activityDefinition =
                            iActivityDefinitionService.getById(adviceSaveDto.getAdviceDefinitionId());
                    String childrenJson = activityDefinition.getChildrenJson();
                    if (childrenJson != null) {
                        // 诊疗子项参数类
                        ActivityChildrenJsonParams activityChildrenJsonParams = new ActivityChildrenJsonParams();
                        activityChildrenJsonParams.setTherapyEnum(TherapyTimeType.TEMPORARY.getValue()); // 治疗类型
                        activityChildrenJsonParams.setPatientId(serviceRequest.getPatientId()); // 患者
                        activityChildrenJsonParams.setEncounterId(serviceRequest.getEncounterId()); // 就诊id
                        activityChildrenJsonParams.setAccountId(chargeItem.getAccountId()); // 账户id
                        activityChildrenJsonParams.setChargeItemId(chargeItem.getId()); // 费用项id
                        activityChildrenJsonParams.setParentId(serviceRequest.getId());// 子项诊疗的父id
                        adviceUtils.handleActivityChild(childrenJson, organizationId, activityChildrenJsonParams);
                    }
                }
            }

            // 只有在签发时
            if (is_sign) {
                // 发送跨系统申请
                adviceSaveDto.setRequestId(serviceRequest.getId());
                try {
                    // 查询诊疗定义
                    ActivityDefinition activityDefinition =
                            iActivityDefinitionService.getById(adviceSaveDto.getAdviceDefinitionId());
                    if (activityDefinition != null) {
                        // 检验 或 检查
                        if (ActivityType.PROOF.getValue().equals(activityDefinition.getTypeEnum())
                                || ActivityType.TEST.getValue().equals(activityDefinition.getTypeEnum())) {
                            doctorStationSendApplyUtil.sendCrossSystemApply(adviceSaveDto, organizationId, curDate);
                        }
                    }
                } catch (Exception e) {
                    if (!Whether.YES.getCode()
                            .equals(TenantOptionUtil.getOptionContent(TenantOptionDict.LIS_PACS_ERROR_IGNORE))) {
                        throw e;
                    }
                    log.error(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * 查询医嘱请求数据
     *
     * @param encounterId 就诊id
     * @return 医嘱请求数据
     */
    @Override
    public R<?> getRequestBaseInfo(Long encounterId) {
        // 当前账号的参与者id
        Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
        // 医嘱请求数据
        List<RequestBaseDto> requestBaseInfo = doctorStationAdviceAppMapper.getRequestBaseInfo(encounterId, null,
                CommonConstants.TableName.MED_MEDICATION_REQUEST, CommonConstants.TableName.WOR_DEVICE_REQUEST,
                CommonConstants.TableName.WOR_SERVICE_REQUEST, practitionerId, Whether.NO.getCode(),
                GenerateSource.DOCTOR_PRESCRIPTION.getValue());
        for (RequestBaseDto requestBaseDto : requestBaseInfo) {
            // 请求状态
            requestBaseDto
                    .setStatusEnum_enumText(EnumUtils.getInfoByValue(RequestStatus.class, requestBaseDto.getStatusEnum()));
            // 是否皮试
            requestBaseDto
                    .setSkinTestFlag_enumText(EnumUtils.getInfoByValue(Whether.class, requestBaseDto.getSkinTestFlag()));
            // 是否为注射药物
            requestBaseDto
                    .setInjectFlag_enumText(EnumUtils.getInfoByValue(Whether.class, requestBaseDto.getInjectFlag()));
            // 收费状态
            requestBaseDto.setChargeStatus_enumText(
                    EnumUtils.getInfoByValue(ChargeItemStatus.class, requestBaseDto.getChargeStatus()));
        }
        return R.ok(requestBaseInfo);
    }

    /**
     * 门诊签退医嘱
     *
     * @param requestIdList 请求id列表
     * @return 结果
     */
    @Override
    public R<?> signOffAdvice(List<Long> requestIdList) {
        // 根据请求编号列表查询收费项目信息
        List<ChargeItem> chargeItemList = iChargeItemService.getChargeItemInfoByReqId(requestIdList);

        if (chargeItemList != null && !chargeItemList.isEmpty()) {
            for (ChargeItem chargeItem : chargeItemList) {
                if (ChargeItemStatus.BILLED.getValue().equals(chargeItem.getStatusEnum())) {
                    throw new ServiceException("已收费的项目无法签退，请刷新页面后重试");
                }
            }
            // 分别获取各个请求id列表
            List<Long> medReqIdList = new ArrayList<>();
            List<Long> devReqIdList = new ArrayList<>();
            List<Long> serReqIdList = new ArrayList<>();

            chargeItemList.forEach(item -> {
                switch (item.getServiceTable()) {
                    case CommonConstants.TableName.MED_MEDICATION_REQUEST -> medReqIdList.add(item.getServiceId());
                    case CommonConstants.TableName.WOR_DEVICE_REQUEST -> devReqIdList.add(item.getServiceId());
                    case CommonConstants.TableName.WOR_SERVICE_REQUEST -> serReqIdList.add(item.getServiceId());
                }
            });
            List<Long> chargeItemIdList = chargeItemList.stream().map(ChargeItem::getId).collect(Collectors.toList());
            // 根据id更新收费项目状态
            iChargeItemService.updatePaymentStatus(chargeItemIdList, ChargeItemStatus.DRAFT.getValue());// 撤回后需要更新为草稿
            if (!medReqIdList.isEmpty()) {
                // 根据请求id更新请求状态
                iMedicationRequestService.updateDraftStatusBatch(medReqIdList, null, null);
            }
            if (!devReqIdList.isEmpty()) {
                // 根据请求id更新请求状态
                iDeviceRequestService.updateDraftStatusBatch(devReqIdList);
            }
            if (!serReqIdList.isEmpty()) {
                // 根据请求id更新请求状态
                iServiceRequestService.updateDraftStatusBatch(serReqIdList);
            }
        } else {
            return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00006, null));
        }
        return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null));
    }

    /**
     * 查询历史医嘱请求数据
     *
     * @param patientId   病人id
     * @param encounterId 就诊id
     * @return 历史医嘱请求数据
     */
    @Override
    public R<?> getRequestHistoryInfo(Long patientId, Long encounterId) {
        // 当前账号的参与者id
        Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
        // 医嘱请求数据
        List<RequestBaseDto> requestBaseInfo = doctorStationAdviceAppMapper.getRequestBaseInfo(encounterId, patientId,
                CommonConstants.TableName.MED_MEDICATION_REQUEST, CommonConstants.TableName.WOR_DEVICE_REQUEST,
                CommonConstants.TableName.WOR_SERVICE_REQUEST, practitionerId, Whether.YES.getCode(),
                GenerateSource.DOCTOR_PRESCRIPTION.getValue());
        for (RequestBaseDto requestBaseDto : requestBaseInfo) {
            // 请求状态
            requestBaseDto
                    .setStatusEnum_enumText(EnumUtils.getInfoByValue(RequestStatus.class, requestBaseDto.getStatusEnum()));
            // 是否皮试
            requestBaseDto
                    .setSkinTestFlag_enumText(EnumUtils.getInfoByValue(Whether.class, requestBaseDto.getSkinTestFlag()));
            // 是否为注射药物
            requestBaseDto
                    .setInjectFlag_enumText(EnumUtils.getInfoByValue(Whether.class, requestBaseDto.getInjectFlag()));
            // 收费状态
            requestBaseDto.setChargeStatus_enumText(
                    EnumUtils.getInfoByValue(ChargeItemStatus.class, requestBaseDto.getChargeStatus()));
        }
        return R.ok(requestBaseInfo);
    }

    /**
     * 更新组号
     *
     * @param updateGroupIdParam 更新组号参数
     * @return 结果
     */
    @Override
    public void updateGroupId(UpdateGroupIdParam updateGroupIdParam) {
        List<UpdateGroupDto> groupList = updateGroupIdParam.getGroupList();
        List<Long> idsToSetNull = groupList.stream().filter(dto -> dto.getGroupId() == null)
                .map(UpdateGroupDto::getRequestId).collect(Collectors.toList());

        if (!idsToSetNull.isEmpty()) {
            // 创建更新条件
            UpdateWrapper<MedicationRequest> updateWrapper = new UpdateWrapper<>();
            updateWrapper.set("group_id", null).in("id", idsToSetNull);

            // 执行更新
            iMedicationRequestService.update(updateWrapper);
        }

        // 处理非null的情况
        List<MedicationRequest> medicationRequestList = groupList.stream().filter(dto -> dto.getGroupId() != null)
                .map(dto -> new MedicationRequest().setId(dto.getRequestId()).setGroupId(dto.getGroupId()))
                .collect(Collectors.toList());

        if (!medicationRequestList.isEmpty()) {
            iMedicationRequestService.saveOrUpdateBatch(medicationRequestList);
        }
    }

    /**
     * 查询就诊费用性质
     *
     * @param encounterId 就诊id
     * @return 就诊费用性质
     */
    @Override
    public R<?> getEncounterContract(Long encounterId) {
        return R.ok(doctorStationAdviceAppMapper.getEncounterContract(encounterId));
    }

}
