/*
 * Copyright ©2023 CJB-CNIT Team. All rights reserved
 */
package com.openhis.web.inhospitalnursestation.appservice.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Service;

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.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
import com.core.common.utils.AgeCalculatorUtil;
import com.core.common.utils.MessageUtils;
import com.core.common.utils.SecurityUtils;
import com.core.common.utils.bean.BeanUtils;
import com.openhis.administration.domain.ChargeItem;
import com.openhis.administration.service.IChargeItemService;
import com.openhis.administration.service.IEncounterService;
import com.openhis.clinical.domain.Procedure;
import com.openhis.clinical.service.IProcedureService;
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.MedicationDefinition;
import com.openhis.medication.domain.MedicationDispense;
import com.openhis.medication.domain.MedicationRequest;
import com.openhis.medication.service.IMedicationDefinitionService;
import com.openhis.medication.service.IMedicationDispenseService;
import com.openhis.medication.service.IMedicationRequestService;
import com.openhis.web.common.dto.PerformInfoDto;
import com.openhis.web.common.dto.PerformRecordDto;
import com.openhis.web.doctorstation.appservice.IDoctorStationAdviceAppService;
import com.openhis.web.doctorstation.dto.AdviceBaseDto;
import com.openhis.web.doctorstation.dto.AdvicePriceDto;
import com.openhis.web.doctorstation.utils.AdviceUtils;
import com.openhis.web.inhospitalnursestation.appservice.IAdviceProcessAppService;
import com.openhis.web.inhospitalnursestation.dto.*;
import com.openhis.web.inhospitalnursestation.mapper.AdviceProcessAppMapper;
import com.openhis.web.outpatientmanage.mapper.OutpatientTreatmentAppMapper;
import com.openhis.workflow.domain.DeviceDispense;
import com.openhis.workflow.domain.ServiceRequest;
import com.openhis.workflow.service.IDeviceDispenseService;
import com.openhis.workflow.service.IServiceRequestService;

/**
 * 护士站医嘱处理实现类
 *
 * @author zwh
 * @date 2025-08-07
 */
@Service
public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {

    @Resource
    private AdviceProcessAppMapper adviceProcessAppMapper;

    @Resource
    private IProcedureService procedureService;

    @Resource
    private OutpatientTreatmentAppMapper outpatientTreatmentAppMapper;

    @Resource
    private IMedicationRequestService medicationRequestService;

    @Resource
    private IServiceRequestService serviceRequestService;

    @Resource
    private IMedicationDispenseService medicationDispenseService;

    @Resource
    private IDeviceDispenseService deviceDispenseService;

    @Resource
    private IEncounterService encounterService;

    @Resource
    private IMedicationDefinitionService medicationDefinitionService;

    @Resource
    private IChargeItemService chargeItemService;

    @Resource
    private AdviceUtils adviceUtils;

    @Resource
    private IDoctorStationAdviceAppService iDoctorStationAdviceAppService;

    /**
     * 住院患者分页列表
     *
     * @param admissionPageParam 查询条件
     * @param pageNo 当前页码
     * @param pageSize 查询条数
     * @param searchKey 模糊查询关键字
     * @param request 请求数据
     * @return 住院患者分页列表
     */
    @Override
    public R<?> getInpatientPage(AdmissionPageParam admissionPageParam, Integer pageNo, Integer pageSize,
        String searchKey, HttpServletRequest request) {
        // 构建查询条件
        QueryWrapper<AdmissionPageParam> queryWrapper = HisQueryUtils.buildQueryWrapper(admissionPageParam, searchKey,
            new HashSet<>(Arrays.asList(CommonConstants.FieldName.PatientWbStr, CommonConstants.FieldName.PatientPyStr,
                CommonConstants.FieldName.PatientName, CommonConstants.FieldName.BusNo)),
            request);
        // 入院患者分页列表
        Page<AdmissionPatientPageDto> admissionPatientPage =
            adviceProcessAppMapper.selectInpatientPage(new Page<>(pageNo, pageSize), queryWrapper,
                EncounterClass.IMP.getValue(), EncounterZyStatus.TO_BE_REGISTERED.getValue(),
                EncounterZyStatus.REGISTERED.getValue(), EncounterActivityStatus.ACTIVE.getValue(),
                LocationForm.WARD.getValue(), LocationForm.HOUSE.getValue(), LocationForm.BED.getValue());
        admissionPatientPage.getRecords().forEach(e -> {
            // 性别枚举
            e.setGenderEnum_enumText(EnumUtils.getInfoByValue(AdministrativeGender.class, e.getGenderEnum()));
            // 病情
            e.setPriorityEnum_enumText(EnumUtils.getInfoByValue(PriorityLevel.class, e.getPriorityEnum()));
            // 计算年龄
            if (e.getBirthDate() != null) {
                e.setAge(AgeCalculatorUtil.getAge(e.getBirthDate()));
            }
            // 住院状态
            e.setEncounterStatus_enumText(EnumUtils.getInfoByValue(EncounterZyStatus.class, e.getEncounterStatus()));
        });
        return R.ok(admissionPatientPage);
    }

    /**
     * 住院患者医嘱查询
     *
     * @param inpatientAdviceParam 查询条件
     * @param pageNo 当前页码
     * @param pageSize 查询条数
     * @return 住院患者医
     */
    @Override
    public R<?> getInpatientAdvicePage(InpatientAdviceParam inpatientAdviceParam, Integer pageNo, Integer pageSize) {
        // 初始化查询参数
        String encounterIds = inpatientAdviceParam.getEncounterIds();
        inpatientAdviceParam.setEncounterIds(null);
        Integer exeStatus = inpatientAdviceParam.getExeStatus();
        inpatientAdviceParam.setExeStatus(null);
        // 构建查询条件
        QueryWrapper<InpatientAdviceParam> queryWrapper = HisQueryUtils.buildQueryWrapper(inpatientAdviceParam, null,
            new HashSet<>(Arrays.asList(CommonConstants.FieldName.PatientWbStr, CommonConstants.FieldName.PatientPyStr,
                CommonConstants.FieldName.PatientName, CommonConstants.FieldName.BusNo)),
            null);

        // 手动拼接住院患者id条件
        if (encounterIds != null && !encounterIds.isEmpty()) {
            List<Long> encounterIdList =
                Arrays.stream(encounterIds.split(CommonConstants.Common.COMMA)).map(Long::parseLong).toList();
            queryWrapper.in(CommonConstants.FieldName.EncounterId, encounterIdList);
        }
        // 入院患者分页列表
        Page<InpatientAdviceDto> inpatientAdvicePage =
            adviceProcessAppMapper.selectInpatientAdvicePage(new Page<>(pageNo, pageSize), queryWrapper,
                CommonConstants.TableName.MED_MEDICATION_REQUEST, CommonConstants.TableName.WOR_SERVICE_REQUEST,
                RequestStatus.DRAFT.getValue(), EncounterActivityStatus.ACTIVE.getValue(), LocationForm.BED.getValue(),
                ParticipantType.ADMITTING_DOCTOR.getCode(), AccountType.PERSONAL_CASH_ACCOUNT.getCode(),
                ChargeItemStatus.BILLABLE.getValue(), ChargeItemStatus.BILLED.getValue(),
                ChargeItemStatus.REFUNDED.getValue(), EncounterClass.IMP.getValue());
        inpatientAdvicePage.getRecords().forEach(e -> {
            // 是否皮试
            e.setSkinTestFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getSkinTestFlag()));
            // 是否为注射药物
            e.setInjectFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getInjectFlag()));
            // 医嘱类型
            e.setTherapyEnum_enumText(EnumUtils.getInfoByValue(TherapyTimeType.class, e.getTherapyEnum()));
            // 请求状态
            e.setRequestStatus_enumText(EnumUtils.getInfoByValue(RequestStatus.class, e.getRequestStatus()));
            // 性别枚举
            e.setGenderEnum_enumText(EnumUtils.getInfoByValue(AdministrativeGender.class, e.getGenderEnum()));
            // 计算年龄
            if (e.getBirthDate() != null) {
                e.setAge(AgeCalculatorUtil.getAge(e.getBirthDate()));
            }
        });

        // 获取医嘱列表
        List<InpatientAdviceDto> inpatientAdviceList = inpatientAdvicePage.getRecords();
        // 获取请求ids
        List<Long> reqIds = inpatientAdviceList.stream().map(InpatientAdviceDto::getRequestId).toList();
        Map<Long, List<PerformRecordDto>> procedureRecordGroup = new HashMap<>();
        if (!reqIds.isEmpty()) {
            // 查询执行记录
            List<PerformRecordDto> performRecordList = outpatientTreatmentAppMapper.selectPerformRecordList(reqIds);
            if (performRecordList != null && !performRecordList.isEmpty()) {
                // 根据服务请求id分组
                procedureRecordGroup = performRecordList.stream()
                    .collect(Collectors.groupingBy(PerformRecordDto::getRequestId, Collectors.toList()));
            }
        }

        // 手动处理前端传来的执行条件
        if (exeStatus != null) {
            // 处理执行记录状态
            for (InpatientAdviceDto inpatientAdvice : inpatientAdviceList) {
                List<PerformRecordDto> performRecordList = procedureRecordGroup.get(inpatientAdvice.getRequestId());
                List<PerformRecordDto> exePerformRecordList = new ArrayList<>();
                List<PerformRecordDto> cancelPerformRecordList = new ArrayList<>();
                List<PerformRecordDto> stopPerformRecordList = new ArrayList<>();
                if (performRecordList != null && !performRecordList.isEmpty()) {
                    // 按时间分组，处理每个时间点的多条记录
                    Map<String, List<PerformRecordDto>> recordsByTime = performRecordList.stream()
                        .collect(Collectors.groupingBy(record -> record.getOccurrenceTime().toString()));
                    for (Map.Entry<String, List<PerformRecordDto>> entry : recordsByTime.entrySet()) {
                        List<PerformRecordDto> records = entry.getValue();
                        // 按操作顺序排序
                        records.sort(Comparator.comparing(PerformRecordDto::getCreateTime));
                        // 取最后一条记录,最终状态由最后一次操作决定
                        PerformRecordDto lastRecord = records.get(records.size() - 1);
                        if (EventStatus.COMPLETED.getValue().equals(lastRecord.getStatusEnum())) {
                            exePerformRecordList.add(lastRecord);
                        } else if (EventStatus.CANCEL.getValue().equals(lastRecord.getStatusEnum())) {
                            cancelPerformRecordList.add(lastRecord);
                        } else if (EventStatus.STOPPED.getValue().equals(lastRecord.getStatusEnum())) {
                            stopPerformRecordList.add(lastRecord);
                        }
                    }
                }
                inpatientAdvice.setExePerformRecordList(exePerformRecordList)
                    .setCancelPerformRecordList(cancelPerformRecordList)
                    .setStopPerformRecordList(stopPerformRecordList);
            }

            // 根据执行状态过滤医嘱列表
            List<InpatientAdviceDto> filteredList = new ArrayList<>();
            if (EventStatus.COMPLETED.getValue().equals(exeStatus)) {
                // 已执行 - 过滤出有执行记录的医嘱
                filteredList = inpatientAdviceList.stream().filter(
                    advice -> advice.getExePerformRecordList() != null && !advice.getExePerformRecordList().isEmpty())
                    .collect(Collectors.toList());
                // 更新分页数据
                inpatientAdvicePage.setRecords(filteredList);
                inpatientAdvicePage.setTotal(filteredList.size());
            } else if (EventStatus.CANCEL.getValue().equals(exeStatus)) {
                // 取消执行 - 过滤出有取消记录的医嘱
                filteredList = inpatientAdviceList.stream().filter(advice -> advice.getCancelPerformRecordList() != null
                    && !advice.getCancelPerformRecordList().isEmpty()).collect(Collectors.toList());
                // 更新分页数据
                inpatientAdvicePage.setRecords(filteredList);
                inpatientAdvicePage.setTotal(filteredList.size());
            } else if (EventStatus.STOPPED.getValue().equals(exeStatus)) {
                // 不执行 - 过滤出有停止记录的医嘱
                filteredList = inpatientAdviceList.stream().filter(
                    advice -> advice.getStopPerformRecordList() != null && !advice.getStopPerformRecordList().isEmpty())
                    .collect(Collectors.toList());
                // 更新分页数据
                inpatientAdvicePage.setRecords(filteredList);
                inpatientAdvicePage.setTotal(filteredList.size());
            }
        }
        return R.ok(inpatientAdvicePage);
    }

    /**
     * 医嘱校对通过
     *
     * @param performInfoList 医嘱信息集合
     * @return 操作结果
     */
    @Override
    public R<?> adviceVerify(List<PerformInfoDto> performInfoList) {
        // 分别创建两个列表来存储不同类型的请求
        List<PerformInfoDto> serviceRequestList = new ArrayList<>();
        List<PerformInfoDto> medRequestList = new ArrayList<>();
        for (PerformInfoDto item : performInfoList) {
            if (CommonConstants.TableName.WOR_SERVICE_REQUEST.equals(item.getRequestTable())) {
                serviceRequestList.add(item);
            } else if (CommonConstants.TableName.MED_MEDICATION_REQUEST.equals(item.getRequestTable())) {
                medRequestList.add(item);
            }
        }
        Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
        Date checkDate = new Date();
        if (!serviceRequestList.isEmpty()) {
            // 更新服务请求状态已完成
            serviceRequestService.updateCompleteRequestStatus(
                serviceRequestList.stream().map(PerformInfoDto::getRequestId).toList(), practitionerId, checkDate);
            List<ServiceRequest> serviceRequests = serviceRequestService
                .listByIds(serviceRequestList.stream().map(PerformInfoDto::getRequestId).collect(Collectors.toList()));
            for (ServiceRequest serviceRequest : serviceRequests) {
                // 判断医嘱类型
                if (ActivityDefCategory.TRANSFER.getValue().equals(serviceRequest.getCategoryEnum())) {
                    // 更新患者状态 待转科
                    encounterService.updateEncounterStatus(serviceRequest.getEncounterId(),
                        EncounterZyStatus.PENDING_TRANSFER.getValue());
                } else if (ActivityDefCategory.DISCHARGE.getValue().equals(serviceRequest.getCategoryEnum())) {
                    // 更新患者状态 待出院
                    encounterService.updateEncounterStatus(serviceRequest.getEncounterId(),
                        EncounterZyStatus.AWAITING_DISCHARGE.getValue());
                }
            }
        }
        if (!medRequestList.isEmpty()) {
            // 更新药品请求状态已完成
            medicationRequestService.updateCompletedStatusBatch(
                medRequestList.stream().map(PerformInfoDto::getRequestId).toList(), practitionerId, checkDate);
        }
        return R.ok(null, "校对成功");
    }

    /**
     * 医嘱退回
     *
     * @param performInfoList 医嘱信息集合
     * @return 操作结果
     */
    @Override
    public R<?> adviceReject(List<PerformInfoDto> performInfoList) {
        // 分别创建两个列表来存储不同类型的请求
        List<PerformInfoDto> serviceRequestList = new ArrayList<>();
        List<PerformInfoDto> medRequestList = new ArrayList<>();
        for (PerformInfoDto item : performInfoList) {
            if (CommonConstants.TableName.WOR_SERVICE_REQUEST.equals(item.getRequestTable())) {
                serviceRequestList.add(item);
            } else if (CommonConstants.TableName.MED_MEDICATION_REQUEST.equals(item.getRequestTable())) {
                medRequestList.add(item);
            }
        }
        Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
        Date checkDate = new Date();
        if (!serviceRequestList.isEmpty()) {
            // 更新服务请求状态待发送
            serviceRequestService.updateDraftStatus(
                serviceRequestList.stream().map(PerformInfoDto::getRequestId).toList(), practitionerId, checkDate);
        }
        if (!medRequestList.isEmpty()) {
            // 更新药品请求状态待发送
            medicationRequestService.updateDraftStatusBatch(
                medRequestList.stream().map(PerformInfoDto::getRequestId).toList(), practitionerId, checkDate);
        }
        return R.ok(null, "退回成功");
    }

    /**
     * 医嘱执行
     *
     * @param adviceExecuteParam 医嘱执行参数
     * @return 操作结果
     */
    @Override
    public R<?> adviceExecute(AdviceExecuteParam adviceExecuteParam) {
        // 医嘱集合
        List<AdviceExecuteDetailParam> adviceExecuteDetailList = adviceExecuteParam.getAdviceExecuteDetailList();
        // 药品
        List<AdviceExecuteDetailParam> medicineList = adviceExecuteDetailList.stream()
            .filter(e -> CommonConstants.TableName.MED_MEDICATION_REQUEST.equals(e.getAdviceTable())).toList();
        // 诊疗
        List<AdviceExecuteDetailParam> activityList = adviceExecuteDetailList.stream()
            .filter(e -> CommonConstants.TableName.WOR_SERVICE_REQUEST.equals(e.getAdviceTable())).toList();
        // -------------------------------------------药品
        if (!medicineList.isEmpty()) {
            // 组装药品请求用于执行的数据结构
            List<MedicationRequestUseExe> medUseExeList = this.assemblyMedication(medicineList);
            // 校验药品库存
            if (!medUseExeList.isEmpty()) {
                String tipRes = adviceUtils.checkExeMedInventory(medUseExeList);
                if (tipRes != null) {
                    return R.fail(null, tipRes);
                }
            }
            // 处理药品执行
            this.exeMedication(medUseExeList);
        }
        // -------------------------------------------诊疗
        if (!activityList.isEmpty()) {
            // 组装诊疗请求用于执行的数据结构
            List<ServiceRequestUseExe> actUseExeList = this.assemblyActivity(activityList);
            // 处理诊疗执行
            this.exeActivity(actUseExeList);
        }

        return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[] {"医嘱执行"}));
    }

    /**
     * 医嘱取消执行
     *
     * @param adviceExecuteParam 取消执行参数
     * @return 操作结果
     */
    @Override
    public R<?> adviceCancel(AdviceExecuteParam adviceExecuteParam) {

        // 长期医嘱执行id
        List<Long> longProcIdList = adviceExecuteParam.getAdviceExecuteDetailList().stream()
            .filter(x -> x.getTherapyEnum().equals(TherapyTimeType.LONG_TERM.getValue()))
            .map(AdviceExecuteDetailParam::getProcedureId).distinct().toList();
        // 药品临时医嘱执行id
        List<Long> tempProcIdList = adviceExecuteParam.getAdviceExecuteDetailList().stream()
            .filter(x -> x.getTherapyEnum().equals(TherapyTimeType.TEMPORARY.getValue()))
            .map(AdviceExecuteDetailParam::getProcedureId).distinct().toList();

        // 分别处理长期和临时的医嘱
        // 长期已发放药品
        List<MedicationDispense> longMedDispensedList = new ArrayList<>();
        // 长期未发放药品
        List<MedicationDispense> longMedUndispenseList = new ArrayList<>();
        // 长期已发放耗材
        List<DeviceDispense> longDevDispensedList = new ArrayList<>();
        // 长期未发放耗材
        List<DeviceDispense> longDevUndispenseList = new ArrayList<>();
        // 处理长期医嘱
        if (!longProcIdList.isEmpty()) {
            // 长期药品
            List<MedicationDispense> longMedDispenseList =
                medicationDispenseService.getMedDispenseByProcedureId(longProcIdList);
            // 长期耗材
            List<DeviceDispense> longDevDispenseList =
                deviceDispenseService.getDevDispenseByProcedureId(longProcIdList);
            // 分离已发药发药单和未发药发药单
            for (MedicationDispense medicationDispense : longMedDispenseList) {
                if (DispenseStatus.COMPLETED.getValue().equals(medicationDispense.getDispenseEnum())) {
                    longMedDispensedList.add(medicationDispense);
                } else if (DispenseStatus.PREPARATION.getValue().equals(medicationDispense.getDispenseEnum())) {
                    longMedUndispenseList.add(medicationDispense);
                }
            }
            // 分离已发耗材单和未发耗材单
            for (DeviceDispense deviceDispense : longDevDispenseList) {
                if (DispenseStatus.COMPLETED.getValue().equals(deviceDispense.getStatusEnum())) {
                    longDevDispensedList.add(deviceDispense);
                } else if (DispenseStatus.PREPARATION.getValue().equals(deviceDispense.getStatusEnum())) {
                    longDevUndispenseList.add(deviceDispense);
                }
            }
            // 查询账单
            List<ChargeItem> chargeItemList = chargeItemService.getChargeItemByProcedureId(longProcIdList);
            if (chargeItemList != null && !chargeItemList.isEmpty()) {
                for (ChargeItem chargeItem : chargeItemList) {
                    // 因执行医嘱时创建了账单，取消执行时需要软删除账单
                    chargeItemService.removeById(chargeItem);
                }
            }
        }

        // 临时已发放药品
        List<MedicationDispense> tempMedDispensedList = new ArrayList<>();
        // 临时未发放药品
        List<MedicationDispense> tempMedUndispenseList = new ArrayList<>();
        // 临时已发放耗材
        List<DeviceDispense> tempDevDispensedList = new ArrayList<>();
        // 临时未发放耗材
        List<DeviceDispense> tempDevUndispenseList = new ArrayList<>();
        // 处理临时医嘱
        if (!tempProcIdList.isEmpty()) {
            // 长期药品
            List<MedicationDispense> tempMedDispenseList =
                medicationDispenseService.getMedDispenseByProcedureId(tempProcIdList);
            // 长期耗材
            List<DeviceDispense> tempDevDispenseList =
                deviceDispenseService.getDevDispenseByProcedureId(tempProcIdList);
            // 分离已发药发药单和未发药发药单
            for (MedicationDispense medicationDispense : tempMedDispenseList) {
                if (DispenseStatus.COMPLETED.getValue().equals(medicationDispense.getDispenseEnum())) {
                    tempMedDispensedList.add(medicationDispense);
                } else if (DispenseStatus.PREPARATION.getValue().equals(medicationDispense.getDispenseEnum())) {
                    tempMedUndispenseList.add(medicationDispense);
                }
            }
            // 分离已发耗材单和未发耗材单
            for (DeviceDispense deviceDispense : tempDevDispenseList) {
                if (DispenseStatus.COMPLETED.getValue().equals(deviceDispense.getStatusEnum())) {
                    tempDevDispensedList.add(deviceDispense);
                } else if (DispenseStatus.PREPARATION.getValue().equals(deviceDispense.getStatusEnum())) {
                    tempDevUndispenseList.add(deviceDispense);
                }
            }
            // 查询账单
            List<ChargeItem> chargeItemList = chargeItemService.getChargeItemByProcedureId(tempProcIdList);
            if (chargeItemList != null && !chargeItemList.isEmpty()) {
                // 临时医嘱取消执行时，将临时医嘱的收费项目状态改为待收费
                chargeItemService
                    .updatePlannedChargeStatus(chargeItemList.stream().map(ChargeItem::getProcedureId).toList());
            }
        }
        // 统一处理已发放药品或耗材
        List<MedicationDispense> medDispensedList = new ArrayList<>(tempMedDispensedList);
        medDispensedList.addAll(longMedDispensedList);
        // 统一处理已发放药品或耗材
        List<DeviceDispense> devDispensedList = new ArrayList<>(tempDevDispensedList);
        devDispensedList.addAll(longDevDispensedList);
        // 合并长期和临时的执行记录
        List<Long> procedureIdList = new ArrayList<>(longProcIdList);
        procedureIdList.addAll(tempProcIdList);
        // 查询执行记录
        List<Procedure> procedureList = procedureService.listByIds(procedureIdList);
        if (procedureList != null && !procedureList.isEmpty()) {
            for (Procedure procedure : procedureList) {
                // 根据执行记录新增取消执行记录
                procedureService.addProcedureRecord(procedure.getEncounterId(), procedure.getPatientId(),
                    procedure.getRequestId(), procedure.getRequestTable(), EventStatus.CANCEL,
                    ProcedureCategory.INPATIENT_ADVICE, null, procedure.getOccurrenceTime(), procedure.getGroupId(),
                    procedure.getId());
            }
        }
        return R.ok("取消执行成功");
    }

    /**
     * 医嘱不执行
     *
     * @param adviceExecuteParam 不执行参数
     * @return 操作结果
     */
    @Override
    public R<?> adviceVoid(AdviceExecuteParam adviceExecuteParam) {
        // 长期临时都可以不执行，长期不执行的是某一时间点，也可以不执行这一整个医嘱（更新serviceRequest状态为7）
        // 已执行的时间点不能不执行，需要先取消
        // 增加不执行记录
        // 不执行的医嘱还可以再执行（暂时不做限制）
        return null;
    }

    /**
     * 执行药品医嘱
     *
     * @param medUseExeList 药品医嘱
     */
    private void exeMedication(List<MedicationRequestUseExe> medUseExeList) {
        // 长期医嘱
        List<MedicationRequestUseExe> longMedication = medUseExeList.stream()
            .filter(e -> TherapyTimeType.LONG_TERM.getValue().equals(e.getTherapyEnum())).collect(Collectors.toList());
        // 临时医嘱
        List<MedicationRequestUseExe> tempMedication = medUseExeList.stream()
            .filter(e -> TherapyTimeType.TEMPORARY.getValue().equals(e.getTherapyEnum())).collect(Collectors.toList());
        // 药品定义id集合
        List<Long> medicationDefinitionIdList =
            medUseExeList.stream().map(MedicationRequestUseExe::getMedicationId).collect(Collectors.toList());
        // 医嘱详细信息
        List<AdviceBaseDto> medicationInfos = iDoctorStationAdviceAppService.getAdviceBaseInfo(null, null, null,
            medicationDefinitionIdList, 0L, 1, 500, Whether.NO.getValue(), List.of(1)).getRecords();

        // 当前时间
        Date curDate = new Date();
        // 参与者id
        Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
        // 当前登录账号的科室id
        Long orgId = SecurityUtils.getLoginUser().getOrgId();

        // 长期
        MedicationRequest longMedicationRequest;
        ChargeItem chargeItem;
        for (MedicationRequestUseExe medicationRequestUseExe : longMedication) {
            for (String executeTime : medicationRequestUseExe.getExecuteTimes()) {
                longMedicationRequest = new MedicationRequest();
                BeanUtils.copyProperties(medicationRequestUseExe, longMedicationRequest);

                // 生成执行记录
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                // 转换为 LocalDateTime
                LocalDateTime localDateTime = LocalDateTime.parse(executeTime, formatter);
                // 转换为 Date
                Date exeDate = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
                // 执行记录id
                Long procedureId = procedureService.addProcedureRecord(longMedicationRequest.getEncounterId(),
                    longMedicationRequest.getPatientId(), longMedicationRequest.getId(),
                    CommonConstants.TableName.MED_MEDICATION_REQUEST, EventStatus.COMPLETED,
                    ProcedureCategory.INPATIENT_ADVICE, null, exeDate, longMedicationRequest.getGroupId(), null);

                // 生成药品发放
                medicationDispenseService.generateMedicationDispense(longMedicationRequest, procedureId);

                // 生成账单
                chargeItem = new ChargeItem();
                chargeItem.setStatusEnum(ChargeItemStatus.BILLABLE.getValue()); // 收费状态
                chargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(longMedicationRequest.getBusNo()));
                chargeItem.setPrescriptionNo(longMedicationRequest.getPrescriptionNo()); // 处方号
                chargeItem.setPatientId(longMedicationRequest.getPatientId()); // 患者
                chargeItem.setContextEnum(ChargeItemContext.MEDICATION.getValue()); // 类型
                chargeItem.setEncounterId(longMedicationRequest.getEncounterId()); // 就诊id
                chargeItem.setEntererId(practitionerId);// 开立人ID
                chargeItem.setRequestingOrgId(orgId); // 开立科室
                chargeItem.setEnteredDate(curDate); // 开立时间
                chargeItem.setServiceTable(CommonConstants.TableName.MED_MEDICATION_REQUEST);// 医疗服务类型
                chargeItem.setServiceId(longMedicationRequest.getId()); // 医疗服务ID
                chargeItem.setProductTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION);// 产品所在表
                chargeItem.setProductId(longMedicationRequest.getMedicationId());// 收费项id
                chargeItem.setAccountId(medicationRequestUseExe.getAccountId());// 关联账户ID
                chargeItem.setConditionId(longMedicationRequest.getConditionId()); // 诊断id
                chargeItem.setEncounterDiagnosisId(longMedicationRequest.getEncounterDiagnosisId()); // 就诊诊断id
                chargeItem.setProcedureId(procedureId);
                // ------------------------------ 匹配定价信息
                // 根据 medicationId 查找对应的医嘱信息
                MedicationRequest finalLongMedicationRequest = longMedicationRequest;
                Optional<AdviceBaseDto> matchedAdvice = medicationInfos.stream()
                    .filter(
                        advice -> finalLongMedicationRequest.getMedicationId().equals(advice.getAdviceDefinitionId()))
                    .findFirst();
                if (!matchedAdvice.isPresent()) {
                    throw new RuntimeException(
                        "未找到对应的医嘱信息，medicationId: " + finalLongMedicationRequest.getMedicationId());
                }
                AdviceBaseDto advice = matchedAdvice.get();
                // 获取拆零比
                BigDecimal partPercent = advice.getPartPercent();

                // 在 priceList 中查找匹配的定价信息
                Optional<AdvicePriceDto> matchedPrice = advice.getPriceList().stream()
                    .filter(price -> finalLongMedicationRequest.getLotNumber().equals(price.getConditionValue()))
                    .findFirst();
                if (!matchedPrice.isPresent()) {
                    throw new RuntimeException("未找到匹配的定价信息，lotNumber: " + finalLongMedicationRequest.getLotNumber());
                }
                AdvicePriceDto priceDto = matchedPrice.get();
                // 计算价格
                BigDecimal price;
                if (finalLongMedicationRequest.getUnitCode().equals(priceDto.getUnitCode())) {
                    // unitCode 匹配，直接取 price
                    price = priceDto.getPrice();
                } else {
                    // unitCode 不匹配，计算 price / partPercent
                    price = priceDto.getPrice().divide(partPercent, RoundingMode.HALF_UP);
                }
                chargeItem.setDefinitionId(priceDto.getDefinitionId()); // 费用定价ID
                chargeItem.setDefDetailId(priceDto.getDefinitionDetailId()); // 定价子表主键
                chargeItem.setQuantityValue(longMedicationRequest.getQuantity()); // 数量
                chargeItem.setQuantityUnit(longMedicationRequest.getUnitCode()); // 单位
                chargeItem.setUnitPrice(price); // 单价
                chargeItem.setTotalPrice(
                    longMedicationRequest.getQuantity().multiply(price).setScale(4, RoundingMode.HALF_UP)); // 总价

                chargeItemService.saveOrUpdate(chargeItem);
            }
        }

        // 临时
        MedicationRequest tempMedicationRequest;
        for (MedicationRequestUseExe medicationRequestUseExe : tempMedication) {
            for (String executeTime : medicationRequestUseExe.getExecuteTimes()) {
                tempMedicationRequest = new MedicationRequest();
                BeanUtils.copyProperties(medicationRequestUseExe, tempMedicationRequest);

                // 生成执行记录
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                // 转换为 LocalDateTime
                LocalDateTime localDateTime = LocalDateTime.parse(executeTime, formatter);
                // 转换为 Date
                Date exeDate = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
                // 执行记录id
                Long procedureId = procedureService.addProcedureRecord(tempMedicationRequest.getEncounterId(),
                    tempMedicationRequest.getPatientId(), tempMedicationRequest.getId(),
                    CommonConstants.TableName.MED_MEDICATION_REQUEST, EventStatus.COMPLETED,
                    ProcedureCategory.INPATIENT_ADVICE, null, exeDate, tempMedicationRequest.getGroupId(), null);

                // 更新药品放发状态
                medicationDispenseService.update(new LambdaUpdateWrapper<MedicationDispense>()
                    .eq(MedicationDispense::getMedReqId, tempMedicationRequest.getId())
                    .set(MedicationDispense::getStatusEnum, DispenseStatus.PREPARATION.getValue()));

                // 更新账单状态
                chargeItemService.update(
                    new LambdaUpdateWrapper<ChargeItem>().eq(ChargeItem::getServiceId, tempMedicationRequest.getId())
                        .set(ChargeItem::getProcedureId, procedureId)
                        .set(ChargeItem::getStatusEnum, ChargeItemStatus.BILLABLE.getValue()));
            }
        }

    }

    /**
     * 执行诊疗医嘱
     *
     * @param actUseExeList 诊疗医嘱
     */
    private void exeActivity(List<ServiceRequestUseExe> actUseExeList) {
        // 长期医嘱
        List<ServiceRequestUseExe> longActivity = actUseExeList.stream()
            .filter(e -> TherapyTimeType.LONG_TERM.getValue().equals(e.getTherapyEnum())).collect(Collectors.toList());
        // 临时医嘱
        List<ServiceRequestUseExe> tempActivity = actUseExeList.stream()
            .filter(e -> TherapyTimeType.TEMPORARY.getValue().equals(e.getTherapyEnum())).collect(Collectors.toList());
        // 诊疗定义id集合
        List<Long> activityDefinitionIdList =
            actUseExeList.stream().map(ServiceRequestUseExe::getActivityId).collect(Collectors.toList());
        // 医嘱详细信息
        List<AdviceBaseDto> activityInfos = iDoctorStationAdviceAppService.getAdviceBaseInfo(null, null, null,
            activityDefinitionIdList, 0L, 1, 500, Whether.NO.getValue(), List.of(3)).getRecords();

        // 当前时间
        Date curDate = new Date();
        // 参与者id
        Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
        // 当前登录账号的科室id
        Long orgId = SecurityUtils.getLoginUser().getOrgId();

        // 长期
        ServiceRequest longServiceRequest;
        ChargeItem chargeItem;
        for (ServiceRequestUseExe serviceRequestUseExe : longActivity) {
            for (String executeTime : serviceRequestUseExe.getExecuteTimes()) {
                longServiceRequest = new ServiceRequest();
                BeanUtils.copyProperties(serviceRequestUseExe, longServiceRequest);

                // 生成执行记录
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                // 转换为 LocalDateTime
                LocalDateTime localDateTime = LocalDateTime.parse(executeTime, formatter);
                // 转换为 Date
                Date exeDate = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
                // 执行记录id
                Long procedureId = procedureService.addProcedureRecord(longServiceRequest.getEncounterId(),
                    longServiceRequest.getPatientId(), longServiceRequest.getId(),
                    CommonConstants.TableName.WOR_SERVICE_REQUEST, EventStatus.COMPLETED,
                    ProcedureCategory.INPATIENT_ADVICE, null, exeDate, null, null);

                // 生成账单
                chargeItem = new ChargeItem();
                chargeItem.setStatusEnum(ChargeItemStatus.BILLABLE.getValue()); // 收费状态
                chargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(longServiceRequest.getBusNo()));
                chargeItem.setPatientId(longServiceRequest.getPatientId()); // 患者
                chargeItem.setContextEnum(ChargeItemContext.ACTIVITY.getValue()); // 类型
                chargeItem.setEncounterId(longServiceRequest.getEncounterId()); // 就诊id
                chargeItem.setEntererId(practitionerId);// 开立人ID
                chargeItem.setRequestingOrgId(orgId); // 开立科室
                chargeItem.setEnteredDate(curDate); // 开立时间
                chargeItem.setServiceTable(CommonConstants.TableName.WOR_SERVICE_REQUEST);// 医疗服务类型
                chargeItem.setServiceId(longServiceRequest.getId()); // 医疗服务ID
                chargeItem.setProductTable(CommonConstants.TableName.WOR_ACTIVITY_DEFINITION);// 产品所在表
                chargeItem.setProductId(longServiceRequest.getActivityId());// 收费项id
                chargeItem.setAccountId(serviceRequestUseExe.getAccountId());// 关联账户ID
                chargeItem.setConditionId(longServiceRequest.getConditionId()); // 诊断id
                chargeItem.setEncounterDiagnosisId(longServiceRequest.getEncounterDiagnosisId()); // 就诊诊断id
                chargeItem.setProcedureId(procedureId);
                // ------------------------------ 匹配定价信息
                // 根据 activityId 查找对应的医嘱信息
                ServiceRequest finalLongServiceRequest = longServiceRequest;
                Optional<AdviceBaseDto> matchedAdvice = activityInfos.stream()
                    .filter(advice -> finalLongServiceRequest.getActivityId().equals(advice.getAdviceDefinitionId()))
                    .findFirst();
                if (!matchedAdvice.isPresent()) {
                    throw new RuntimeException("未找到对应的医嘱信息，activityId: " + finalLongServiceRequest.getActivityId());
                }
                // 医嘱信息
                AdviceBaseDto advice = matchedAdvice.get();
                // 定价信息
                AdvicePriceDto priceDto = advice.getPriceList().get(0);
                // 计算价格
                BigDecimal price = priceDto.getPrice();

                chargeItem.setDefinitionId(priceDto.getDefinitionId()); // 费用定价ID
                chargeItem.setQuantityValue(longServiceRequest.getQuantity()); // 数量
                chargeItem.setQuantityUnit(longServiceRequest.getUnitCode()); // 单位
                chargeItem.setUnitPrice(price); // 单价
                chargeItem
                    .setTotalPrice(longServiceRequest.getQuantity().multiply(price).setScale(4, RoundingMode.HALF_UP)); // 总价
                chargeItemService.saveOrUpdate(chargeItem);
            }
        }

        // 临时
        ServiceRequest tempServiceRequest;
        for (ServiceRequestUseExe serviceRequestUseExe : tempActivity) {
            for (String executeTime : serviceRequestUseExe.getExecuteTimes()) {
                tempServiceRequest = new ServiceRequest();
                BeanUtils.copyProperties(serviceRequestUseExe, tempServiceRequest);

                // 生成执行记录
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                // 转换为 LocalDateTime
                LocalDateTime localDateTime = LocalDateTime.parse(executeTime, formatter);
                // 转换为 Date
                Date exeDate = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
                // 执行记录id
                Long procedureId = procedureService.addProcedureRecord(tempServiceRequest.getEncounterId(),
                    tempServiceRequest.getPatientId(), tempServiceRequest.getId(),
                    CommonConstants.TableName.WOR_SERVICE_REQUEST, EventStatus.COMPLETED,
                    ProcedureCategory.INPATIENT_ADVICE, null, exeDate, null, null);

                // 更新账单状态
                chargeItemService.update(
                    new LambdaUpdateWrapper<ChargeItem>().eq(ChargeItem::getServiceId, tempServiceRequest.getId())
                        .set(ChargeItem::getProcedureId, procedureId)
                        .set(ChargeItem::getStatusEnum, ChargeItemStatus.BILLABLE.getValue()));
            }
        }

    }

    /**
     * 组装药品请求用于执行的数据结构
     *
     * @param medicineList 药品执行参数
     * @return 用于执行的药品请求
     */
    private List<MedicationRequestUseExe> assemblyMedication(List<AdviceExecuteDetailParam> medicineList) {
        // 药品请求id集合
        List<Long> medicineRequestIdList =
            medicineList.stream().map(AdviceExecuteDetailParam::getRequestId).collect(Collectors.toList());
        // 药品请求集合
        List<MedicationRequest> medicationRequestList = medicationRequestService
            .list(new LambdaQueryWrapper<MedicationRequest>().in(MedicationRequest::getId, medicineRequestIdList));
        // 药品定义id集合
        List<Long> medicationDefinitionIdList =
            medicationRequestList.stream().map(MedicationRequest::getMedicationId).collect(Collectors.toList());
        // 药品定义集合
        List<MedicationDefinition> medicationDefinitionList = medicationDefinitionService.list(
            new LambdaQueryWrapper<MedicationDefinition>().in(MedicationDefinition::getId, medicationDefinitionIdList));
        // 组装MedicationRequestUseExe数据结构
        List<MedicationRequestUseExe> medUseExeList = medicationRequestList.stream().map(medicationRequest -> {
            // 创建 MedicationRequestUseExe 对象，并复制 MedicationRequest 的属性
            MedicationRequestUseExe useExe = new MedicationRequestUseExe();
            // 账号id赋值
            AdviceExecuteDetailParam adviceExecuteDetailParam = medicineList.stream()
                .filter(param -> medicationRequest.getId().equals(param.getRequestId())).findFirst().orElse(null);
            if (adviceExecuteDetailParam != null) {
                useExe.setAccountId(adviceExecuteDetailParam.getAccountId());
            }
            BeanUtils.copyProperties(medicationRequest, useExe);
            // 匹配 executeTimes：根据 medicationRequest 的 id 在 medicineList 中查找匹配的 executeTimes
            List<String> matchedExecuteTimes =
                medicineList.stream().filter(medicine -> medicine.getRequestId().equals(medicationRequest.getId()))
                    .findFirst().map(AdviceExecuteDetailParam::getExecuteTimes).orElse(null);
            useExe.setExecuteTimes(matchedExecuteTimes);
            // 计算 executeTimesNum：executeTimes 的集合大小，转换为 BigDecimal
            if (matchedExecuteTimes != null) {
                useExe.setExecuteTimesNum(BigDecimal.valueOf(matchedExecuteTimes.size()));
            } else {
                useExe.setExecuteTimesNum(BigDecimal.ZERO);
            }
            // 匹配 minUnitQuantity：根据 medicationId 在 medicationDefinitionList 中查找匹配的药品定义
            MedicationDefinition matchedDefinition = medicationDefinitionList.stream()
                .filter(definition -> definition.getId().equals(medicationRequest.getMedicationId())).findFirst()
                .orElse(null);
            if (matchedDefinition != null) {
                // 判断 minUnitCode 是否等于 unitCode
                if (matchedDefinition.getMinUnitCode().equals(medicationRequest.getUnitCode())) {
                    useExe.setMinUnitQuantity(medicationRequest.getQuantity());
                } else {
                    // 若不相等，则计算 quantity * partPercent
                    BigDecimal partPercent = matchedDefinition.getPartPercent();
                    if (partPercent == null) {
                        partPercent = BigDecimal.ONE; // 避免空指针，默认设为1
                    }
                    useExe.setMinUnitQuantity(medicationRequest.getQuantity().multiply(partPercent));
                }
            } else {
                // 若未找到匹配的药品定义，设为 null 或默认值
                useExe.setMinUnitQuantity(null);
            }
            return useExe;
        }).toList();
        return medUseExeList;
    }

    /**
     * 组装诊疗请求用于执行的数据结构
     *
     * @param activityList 诊疗执行参数
     * @return 用于执行的诊疗请求
     */
    private List<ServiceRequestUseExe> assemblyActivity(List<AdviceExecuteDetailParam> activityList) {
        // 诊疗请求id集合
        List<Long> activityRequestIdList =
            activityList.stream().map(AdviceExecuteDetailParam::getRequestId).collect(Collectors.toList());
        // 诊疗请求集合
        List<ServiceRequest> activityRequestList = serviceRequestService
            .list(new LambdaQueryWrapper<ServiceRequest>().in(ServiceRequest::getId, activityRequestIdList));
        // 组装ServiceRequestUseExe数据结构
        List<ServiceRequestUseExe> actUseExeList = activityRequestList.stream().map(serviceRequest -> {
            // 创建 ServiceRequestUseExe 对象，并复制 ServiceRequest 的属性
            ServiceRequestUseExe useExe = new ServiceRequestUseExe();
            // 账号id赋值
            AdviceExecuteDetailParam adviceExecuteDetailParam = activityList.stream()
                .filter(param -> serviceRequest.getId().equals(param.getRequestId())).findFirst().orElse(null);
            if (adviceExecuteDetailParam != null) {
                useExe.setAccountId(adviceExecuteDetailParam.getAccountId());
            }
            BeanUtils.copyProperties(serviceRequest, useExe);
            // 匹配 executeTimes：根据 serviceRequest 的 id 在 activityList 中查找匹配的 executeTimes
            List<String> matchedExecuteTimes =
                activityList.stream().filter(activity -> activity.getRequestId().equals(serviceRequest.getId()))
                    .findFirst().map(AdviceExecuteDetailParam::getExecuteTimes).orElse(null);
            useExe.setExecuteTimes(matchedExecuteTimes);
            // 计算 executeTimesNum：executeTimes 的集合大小，转换为 BigDecimal
            if (matchedExecuteTimes != null) {
                useExe.setExecuteTimesNum(BigDecimal.valueOf(matchedExecuteTimes.size()));
            } else {
                useExe.setExecuteTimesNum(BigDecimal.ZERO);
            }
            return useExe;
        }).toList();
        return actUseExeList;
    }

}
