package com.openhis.web.regdoctorstation.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.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
import com.core.common.exception.ServiceException;
import com.core.common.utils.AgeCalculatorUtil;
import com.core.common.utils.AssignSeqUtil;
import com.core.common.utils.MessageUtils;
import com.core.common.utils.SecurityUtils;
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.dto.ActivityChildrenJsonParams;
import com.openhis.web.doctorstation.dto.AdviceSaveDto;
import com.openhis.web.doctorstation.utils.AdviceUtils;
import com.openhis.web.regdoctorstation.appservice.IAdviceManageAppService;
import com.openhis.web.regdoctorstation.dto.*;
import com.openhis.web.regdoctorstation.mapper.AdviceManageAppMapper;
import com.openhis.web.regdoctorstation.utils.RegPrescriptionUtils;
import com.openhis.workflow.domain.ActivityDefinition;
import com.openhis.workflow.domain.ServiceRequest;
import com.openhis.workflow.service.IActivityDefinitionService;
import com.openhis.workflow.service.IServiceRequestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

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

/**
 * 医嘱管理 应用实现类
 */
@Slf4j
@Service
public class AdviceManageAppServiceImpl implements IAdviceManageAppService {

    @Resource
    AdviceUtils adviceUtils;

    @Resource
    AssignSeqUtil assignSeqUtil;

    @Resource
    RegPrescriptionUtils regPrescriptionUtils;

    @Resource
    AdviceManageAppMapper adviceManageAppMapper;

    @Resource
    IChargeItemService iChargeItemService;

    @Resource
    IMedicationRequestService iMedicationRequestService;

    @Resource
    IMedicationDispenseService iMedicationDispenseService;

    @Resource
    IServiceRequestService iServiceRequestService;

    @Resource
    IActivityDefinitionService iActivityDefinitionService;

    /**
     * 查询住院患者信息
     *
     * @param regPatientMainInfoDto 住院患者信息 dto
     * @param searchKey             模糊查询关键字
     * @param pageNo                当前页
     * @param pageSize              每页多少条
     * @param request               请求
     * @return 住院患者信息
     */
    @Override
    public IPage<RegPatientMainInfoDto> getRegPatientMainInfo(RegPatientMainInfoDto regPatientMainInfoDto,
                                                              Integer status, String searchKey, Integer pageNo, Integer pageSize, HttpServletRequest request) {
        // 构建查询条件
        QueryWrapper<RegPatientMainInfoDto> queryWrapper =
                HisQueryUtils.buildQueryWrapper(regPatientMainInfoDto, searchKey,
                        new HashSet<>(Arrays.asList("bus_no", "patient_name", "inHospital_org_name", "house_name")), request);

        IPage<RegPatientMainInfoDto> regPatientMainInfo = adviceManageAppMapper.getRegPatientMainInfo(
                new Page<>(pageNo, pageSize), SecurityUtils.getLoginUser().getPractitionerId(),
                LocationForm.WARD.getValue(), LocationForm.HOUSE.getValue(), LocationForm.BED.getValue(),
                EncounterActivityStatus.ACTIVE.getValue(), EncounterClass.IMP.getValue(), status, Whether.YES.getValue(),
                AccountType.PERSONAL_CASH_ACCOUNT.getCode(), queryWrapper);
        regPatientMainInfo.getRecords().forEach(e -> {
            // 性别
            e.setGenderEnum_enumText(EnumUtils.getInfoByValue(AdministrativeGender.class, e.getGenderEnum()));
            // 计算年龄
            e.setAge(e.getBirthDate() != null ? AgeCalculatorUtil.getAge(e.getBirthDate()) : "");
        });
        return regPatientMainInfo;
    }

    /**
     * 住院保存医嘱
     *
     * @param regAdviceSaveParam 住院医嘱表单信息
     * @param adviceOpType       医嘱操作类型
     * @return 结果
     */
    @Override
    public R<?> saveRegAdvice(RegAdviceSaveParam regAdviceSaveParam, String adviceOpType) {
        // 当前时间
        Date curDate = new Date();
        // 医嘱开始时间
        Date startTime = regAdviceSaveParam.getStartTime();
        if (startTime == null) {
            startTime = curDate;
        }
        // 医嘱签发时间
        Date authoredTime = regAdviceSaveParam.getAuthoredTime();
        if (authoredTime == null) {
            authoredTime = curDate;
        }

        // 患者住院入科室id
        Long organizationId = regAdviceSaveParam.getOrganizationId();
        // 医嘱分类信息
        List<RegAdviceSaveDto> regAdviceSaveList = regAdviceSaveParam.getRegAdviceSaveList();
        // 药品
        List<RegAdviceSaveDto> medicineList = regAdviceSaveList.stream()
                .filter(e -> ItemType.MEDICINE.getValue().equals(e.getAdviceType())).collect(Collectors.toList());
        // 耗材
        // List<RegAdviceSaveDto> deviceList = regAdviceSaveList.stream()
        // .filter(e -> ItemType.DEVICE.getValue().equals(e.getAdviceType())).collect(Collectors.toList());
        // 诊疗活动
        List<RegAdviceSaveDto> activityList = regAdviceSaveList.stream()
                .filter(e -> ItemType.ACTIVITY.getValue().equals(e.getAdviceType())).collect(Collectors.toList());

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

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

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

        // 签发时,把草稿状态的账单更新为待收费
        if (AdviceOpType.SIGN_ADVICE.getCode().equals(adviceOpType) && !regAdviceSaveList.isEmpty()) {
            // 签发的医嘱id集合
            List<Long> requestIds = regAdviceSaveList.stream()
                    .filter(e -> !DbOpType.DELETE.getCode().equals(e.getDbOpType()) && e.getRequestId() != null)
                    .collect(Collectors.toList()).stream().map(AdviceSaveDto::getRequestId).collect(Collectors.toList());
            Long encounterId = regAdviceSaveList.get(0).getEncounterId();// 就诊id
            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<RegAdviceSaveDto> medicineList, Date startTime, Date authoredTime, 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);

        // 删除
        List<RegAdviceSaveDto> deleteList = medicineList.stream()
                .filter(e -> DbOpType.DELETE.getCode().equals(e.getDbOpType())).collect(Collectors.toList());
        for (RegAdviceSaveDto regAdviceSaveDto : deleteList) {
            iMedicationRequestService.removeById(regAdviceSaveDto.getRequestId());
            // 删除已经产生的药品发放信息
            iMedicationDispenseService.deleteMedicationDispense(regAdviceSaveDto.getRequestId());
            // 删除费用项
            iChargeItemService.deleteByServiceTableAndId(CommonConstants.TableName.MED_MEDICATION_REQUEST,
                    regAdviceSaveDto.getRequestId());
        }
        // 签发时统一处理组号 (排除删除操作,包括长期和临时)
        List<RegAdviceSaveDto> exceptDelList = medicineList.stream()
                .filter(e -> !DbOpType.DELETE.getCode().equals(e.getDbOpType())).collect(Collectors.toList());
        if (is_sign) {
            // 生成住院处方号
            regPrescriptionUtils.generatePrescriptionNumbers(exceptDelList);
        }

        // 声明长期医嘱药品请求
        MedicationRequest longMedicationRequest;
        // 新增 + 修改 (长期医嘱)
        List<RegAdviceSaveDto> longInsertOrUpdateList = medicineList.stream().filter(e -> TherapyTimeType.LONG_TERM
                        .getValue().equals(e.getTherapyEnum())
                        && (DbOpType.INSERT.getCode().equals(e.getDbOpType()) || DbOpType.UPDATE.getCode().equals(e.getDbOpType())))
                .collect(Collectors.toList());

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

        // 声明临时医嘱药品请求
        MedicationRequest tempMedicationRequest;
        // 声明临时医嘱费用项
        ChargeItem chargeItem;
        // 新增 + 修改 (临时医嘱)
        List<RegAdviceSaveDto> tempInsertOrUpdateList = medicineList.stream().filter(e -> TherapyTimeType.TEMPORARY
                        .getValue().equals(e.getTherapyEnum())
                        && (DbOpType.INSERT.getCode().equals(e.getDbOpType()) || DbOpType.UPDATE.getCode().equals(e.getDbOpType())))
                .collect(Collectors.toList());
        for (RegAdviceSaveDto regAdviceSaveDto : tempInsertOrUpdateList) {
            tempMedicationRequest = new MedicationRequest();
            tempMedicationRequest.setId(regAdviceSaveDto.getRequestId()); // 主键id
            tempMedicationRequest
                    .setStatusEnum(is_save ? RequestStatus.DRAFT.getValue() : RequestStatus.ACTIVE.getValue()); // 请求状态
            tempMedicationRequest.setPrescriptionNo(regAdviceSaveDto.getPrescriptionNo()); // 处方号
            tempMedicationRequest.setGroupId(regAdviceSaveDto.getGroupId()); // 组号
            if (is_sign) {
                tempMedicationRequest.setReqAuthoredTime(authoredTime); // 医嘱签发时间
                tempMedicationRequest.setSignCode(signCode);
            }
            // 保存时处理的字段属性
            if (is_save) {
                tempMedicationRequest.setEffectiveDoseStart(startTime); // 医嘱开始时间
                tempMedicationRequest
                        .setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.MEDICATION_RES_NO.getPrefix(), 4));
                tempMedicationRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
                tempMedicationRequest.setQuantity(regAdviceSaveDto.getQuantity()); // 请求数量
                tempMedicationRequest.setExecuteNum(regAdviceSaveDto.getExecuteNum()); // 执行次数
                tempMedicationRequest.setUnitCode(regAdviceSaveDto.getUnitCode()); // 请求单位编码
                tempMedicationRequest.setLotNumber(regAdviceSaveDto.getLotNumber()); // 产品批号
                tempMedicationRequest.setCategoryEnum(regAdviceSaveDto.getCategoryEnum()); // 请求类型
                tempMedicationRequest.setMedicationId(regAdviceSaveDto.getAdviceDefinitionId());// 医嘱定义id
                tempMedicationRequest.setPatientId(regAdviceSaveDto.getPatientId()); // 患者
                tempMedicationRequest.setPractitionerId(regAdviceSaveDto.getPractitionerId()); // 开方医生
                tempMedicationRequest.setOrgId(regAdviceSaveDto.getFounderOrgId()); // 开方人科室
                tempMedicationRequest.setPerformLocation(regAdviceSaveDto.getLocationId()); // 发放药房
                tempMedicationRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id
                tempMedicationRequest.setConditionId(regAdviceSaveDto.getConditionId()); // 诊断id
                tempMedicationRequest.setEncounterDiagnosisId(regAdviceSaveDto.getEncounterDiagnosisId()); // 就诊诊断id
                tempMedicationRequest.setTherapyEnum(regAdviceSaveDto.getTherapyEnum()); // 治疗类型,临时(需要前端传)
                tempMedicationRequest.setMethodCode(regAdviceSaveDto.getMethodCode()); // 用法
                tempMedicationRequest.setRateCode(regAdviceSaveDto.getRateCode()); // 用药频次
                tempMedicationRequest.setDose(regAdviceSaveDto.getDose()); // 单次剂量
                tempMedicationRequest.setDoseUnitCode(regAdviceSaveDto.getDoseUnitCode()); // 剂量单位
                tempMedicationRequest.setDispensePerDuration(regAdviceSaveDto.getDispensePerDuration()); // 每次发药供应天数
                tempMedicationRequest.setPackageId(regAdviceSaveDto.getPackageId()); // 组套id
                tempMedicationRequest.setContentJson(regAdviceSaveDto.getContentJson()); // 请求内容json
                tempMedicationRequest.setYbClassEnum(regAdviceSaveDto.getYbClassEnum());// 类别医保编码
                tempMedicationRequest.setSkinTestFlag(regAdviceSaveDto.getSkinTestFlag()); // 皮试标志
                tempMedicationRequest.setInfusionFlag(regAdviceSaveDto.getInjectFlag()); // 输液标志
                tempMedicationRequest.setSortNumber(regAdviceSaveDto.getSortNumber()); // 排序号
            }
            iMedicationRequestService.saveOrUpdate(tempMedicationRequest);
            if (is_save) {
                // 处理药品发放
                Long dispenseId = iMedicationDispenseService.handleMedicationDispense(tempMedicationRequest,
                        regAdviceSaveDto.getDbOpType());

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

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

                iChargeItemService.saveOrUpdate(chargeItem);
            }
        }
    }

    /**
     * 处理诊疗
     */
    private void handService(List<RegAdviceSaveDto> activityList, Date startTime, Date authoredTime, 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);

        // 删除
        List<AdviceSaveDto> deleteList = activityList.stream()
                .filter(e -> DbOpType.DELETE.getCode().equals(e.getDbOpType())).collect(Collectors.toList());
        for (AdviceSaveDto adviceSaveDto : deleteList) {
            iServiceRequestService.removeById(adviceSaveDto.getRequestId());
            // 删除费用项
            iChargeItemService.deleteByServiceTableAndId(CommonConstants.TableName.WOR_SERVICE_REQUEST,
                    adviceSaveDto.getRequestId());
        }

        // 声明长期医嘱诊疗请求
        ServiceRequest longServiceRequest;
        // 新增 + 修改 (长期医嘱)
        List<RegAdviceSaveDto> longInsertOrUpdateList = activityList.stream().filter(e -> TherapyTimeType.LONG_TERM
                        .getValue().equals(e.getTherapyEnum())
                        && (DbOpType.INSERT.getCode().equals(e.getDbOpType()) || DbOpType.UPDATE.getCode().equals(e.getDbOpType())))
                .collect(Collectors.toList());
        for (RegAdviceSaveDto regAdviceSaveDto : longInsertOrUpdateList) {
            longServiceRequest = new ServiceRequest();
            longServiceRequest.setId(regAdviceSaveDto.getRequestId()); // 主键id
            longServiceRequest
                    .setStatusEnum(is_save ? RequestStatus.DRAFT.getValue() : RequestStatus.ACTIVE.getValue());// 请求状态
            if (is_sign) {
                longServiceRequest.setAuthoredTime(authoredTime); // 医嘱签发时间
                longServiceRequest.setSignCode(signCode);
            }
            // 保存时处理的字段属性
            if (is_save) {
                longServiceRequest.setOccurrenceStartTime(startTime); // 医嘱开始时间
                longServiceRequest.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.SERVICE_RES_NO.getPrefix(), 4));
                longServiceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
                longServiceRequest.setQuantity(new BigDecimal("1")); // 请求数量 | 诊疗的长期医嘱数量都是1
                longServiceRequest.setUnitCode(regAdviceSaveDto.getUnitCode()); // 请求单位编码
                longServiceRequest.setRateCode(regAdviceSaveDto.getRateCode()); // 用药频次
                longServiceRequest.setCategoryEnum(regAdviceSaveDto.getCategoryEnum()); // 请求类型
                longServiceRequest.setTherapyEnum(regAdviceSaveDto.getTherapyEnum()); // 治疗类型,长期(需要前端传)
                longServiceRequest.setActivityId(regAdviceSaveDto.getAdviceDefinitionId());// 诊疗定义id
                longServiceRequest.setPatientId(regAdviceSaveDto.getPatientId()); // 患者
                longServiceRequest.setRequesterId(regAdviceSaveDto.getPractitionerId()); // 开方医生
                longServiceRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id
                longServiceRequest.setOrgId(regAdviceSaveDto.getPositionId()); // 执行科室
                longServiceRequest.setContentJson(regAdviceSaveDto.getContentJson()); // 请求内容json
                longServiceRequest.setYbClassEnum(regAdviceSaveDto.getYbClassEnum());// 类别医保编码
                longServiceRequest.setConditionId(regAdviceSaveDto.getConditionId()); // 诊断id
                longServiceRequest.setEncounterDiagnosisId(regAdviceSaveDto.getEncounterDiagnosisId()); // 就诊诊断id
            }
            iServiceRequestService.saveOrUpdate(longServiceRequest);
        }

        // 声明临时医嘱诊疗请求
        ServiceRequest tempServiceRequest;
        // 声明临时医嘱费用项
        ChargeItem chargeItem;
        // 新增 + 修改 (临时医嘱)
        List<RegAdviceSaveDto> tempInsertOrUpdateList = activityList.stream().filter(e -> TherapyTimeType.TEMPORARY

                        .getValue().equals(e.getTherapyEnum())
                        && (DbOpType.INSERT.getCode().equals(e.getDbOpType()) || DbOpType.UPDATE.getCode().equals(e.getDbOpType())))
                .collect(Collectors.toList());
        for (RegAdviceSaveDto regAdviceSaveDto : tempInsertOrUpdateList) {
            tempServiceRequest = new ServiceRequest();
            tempServiceRequest.setId(regAdviceSaveDto.getRequestId()); // 主键id
            tempServiceRequest
                    .setStatusEnum(is_save ? RequestStatus.DRAFT.getValue() : RequestStatus.ACTIVE.getValue());// 请求状态
            if (is_sign) {
                tempServiceRequest.setAuthoredTime(authoredTime); // 医嘱签发时间
                tempServiceRequest.setSignCode(signCode);
            }
            // 保存时处理的字段属性
            if (is_save) {
                tempServiceRequest.setOccurrenceStartTime(startTime); // 医嘱开始时间
                tempServiceRequest.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.SERVICE_RES_NO.getPrefix(), 4));
                tempServiceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
                tempServiceRequest.setQuantity(regAdviceSaveDto.getQuantity()); // 请求数量
                tempServiceRequest.setUnitCode(regAdviceSaveDto.getUnitCode()); // 请求单位编码
                tempServiceRequest.setCategoryEnum(regAdviceSaveDto.getCategoryEnum()); // 请求类型
                tempServiceRequest.setTherapyEnum(regAdviceSaveDto.getTherapyEnum()); // 治疗类型,临时(需要前端传)
                tempServiceRequest.setActivityId(regAdviceSaveDto.getAdviceDefinitionId());// 诊疗定义id
                tempServiceRequest.setPatientId(regAdviceSaveDto.getPatientId()); // 患者
                tempServiceRequest.setRequesterId(regAdviceSaveDto.getPractitionerId()); // 开方医生
                tempServiceRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id
                tempServiceRequest.setAuthoredTime(curDate); // 请求签发时间
                tempServiceRequest.setOrgId(regAdviceSaveDto.getPositionId()); // 执行科室
                tempServiceRequest.setContentJson(regAdviceSaveDto.getContentJson()); // 请求内容json
                tempServiceRequest.setYbClassEnum(regAdviceSaveDto.getYbClassEnum());// 类别医保编码
                tempServiceRequest.setConditionId(regAdviceSaveDto.getConditionId()); // 诊断id
                tempServiceRequest.setEncounterDiagnosisId(regAdviceSaveDto.getEncounterDiagnosisId()); // 就诊诊断id
            }
            iServiceRequestService.saveOrUpdate(tempServiceRequest);

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

                iChargeItemService.saveOrUpdate(chargeItem);

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

    }

    /**
     * 查询住院医嘱请求数据
     *
     * @param encounterId 就诊id
     * @return 住院医嘱请求数据
     */
    @Override
    public R<?> getRegRequestBaseInfo(Long encounterId) {
        // 当前账号的参与者id
        Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
        // 住院医嘱请求数据
        List<RegRequestBaseDto> regRequestBaseInfo = adviceManageAppMapper.getRegRequestBaseInfo(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());
        // 根据 requestId 过滤重复医嘱信息
        List<RegRequestBaseDto> distinctList = regRequestBaseInfo.stream()
                .collect(Collectors.toMap(RegRequestBaseDto::getRequestId, dto -> dto, (existing, replacement) -> existing // 如果key冲突，保留已存在的（第一条）
                )).values().stream().collect(Collectors.toList());

        for (RegRequestBaseDto regRequestBaseDto : distinctList) {
            // 请求状态
            regRequestBaseDto.setStatusEnum_enumText(
                    EnumUtils.getInfoByValue(RequestStatus.class, regRequestBaseDto.getStatusEnum()));
            // 是否皮试
            regRequestBaseDto
                    .setSkinTestFlag_enumText(EnumUtils.getInfoByValue(Whether.class, regRequestBaseDto.getSkinTestFlag()));
            // 是否为注射药物
            regRequestBaseDto
                    .setInjectFlag_enumText(EnumUtils.getInfoByValue(Whether.class, regRequestBaseDto.getInjectFlag()));
            // 收费状态
            regRequestBaseDto.setChargeStatus_enumText(
                    EnumUtils.getInfoByValue(ChargeItemStatus.class, regRequestBaseDto.getChargeStatus()));
            // 治疗类型
            regRequestBaseDto.setTherapyEnum_enumText(
                    EnumUtils.getInfoByValue(TherapyTimeType.class, regRequestBaseDto.getTherapyEnum()));
        }
        return R.ok(distinctList);
    }

    /**
     * 查询历史住院医嘱请求数据
     *
     * @param encounterId 就诊id
     * @param patientId   病人id
     * @return 历史住院医嘱请求数据
     */
    @Override
    public R<?> getRegRequestHistoryInfo(Long patientId, Long encounterId) {
        // 当前账号的参与者id
        Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
        // 住院医嘱请求数据
        List<RegRequestBaseDto> regRequestBaseInfo = adviceManageAppMapper.getRegRequestBaseInfo(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 (RegRequestBaseDto regRequestBaseDto : regRequestBaseInfo) {
            // 请求状态
            regRequestBaseDto.setStatusEnum_enumText(
                    EnumUtils.getInfoByValue(RequestStatus.class, regRequestBaseDto.getStatusEnum()));
            // 是否皮试
            regRequestBaseDto
                    .setSkinTestFlag_enumText(EnumUtils.getInfoByValue(Whether.class, regRequestBaseDto.getSkinTestFlag()));
            // 是否为注射药物
            regRequestBaseDto
                    .setInjectFlag_enumText(EnumUtils.getInfoByValue(Whether.class, regRequestBaseDto.getInjectFlag()));
            // 收费状态
            regRequestBaseDto.setChargeStatus_enumText(
                    EnumUtils.getInfoByValue(ChargeItemStatus.class, regRequestBaseDto.getChargeStatus()));
            // 治疗类型
            regRequestBaseDto.setTherapyEnum_enumText(
                    EnumUtils.getInfoByValue(TherapyTimeType.class, regRequestBaseDto.getTherapyEnum()));
        }
        return R.ok(regRequestBaseInfo);
    }

    /**
     * 住院医嘱签退
     *
     * @param paramList 签退参数
     * @return 结果
     */
    @Override
    public R<?> signOffRegAdvice(List<AdviceBatchOpParam> paramList) {
        // 药品
        List<AdviceBatchOpParam> medicineList = paramList.stream()
                .filter(e -> ItemType.MEDICINE.getValue().equals(e.getAdviceType())).collect(Collectors.toList());
        List<Long> medicineRequestIds =
                medicineList.stream().map(AdviceBatchOpParam::getRequestId).collect(Collectors.toList());
        // 诊疗
        List<AdviceBatchOpParam> activityList = paramList.stream()
                .filter(e -> ItemType.ACTIVITY.getValue().equals(e.getAdviceType())).collect(Collectors.toList());
        List<Long> activityRequestIds =
                activityList.stream().map(AdviceBatchOpParam::getRequestId).collect(Collectors.toList());
        // 查询已完成的药品请求
        List<MedicationRequest> medicineCompleteList = new ArrayList<>();
        if (!medicineRequestIds.isEmpty()) {
            medicineCompleteList = iMedicationRequestService.list(new LambdaQueryWrapper<MedicationRequest>()
                    .eq(MedicationRequest::getStatusEnum, RequestStatus.COMPLETED.getValue())
                    .in(MedicationRequest::getId, medicineRequestIds));
        }
        // 查询已完成的诊疗请求
        List<ServiceRequest> activityCompleteList = new ArrayList<>();
        if (!activityRequestIds.isEmpty()) {
            activityCompleteList = iServiceRequestService.list(new LambdaQueryWrapper<ServiceRequest>()
                    .eq(ServiceRequest::getStatusEnum, RequestStatus.COMPLETED.getValue())
                    .in(ServiceRequest::getId, activityRequestIds));
        }
        if (!medicineCompleteList.isEmpty() || !activityCompleteList.isEmpty()) {
            throw new ServiceException("存在已完成的医嘱，请重新选择");
        }
        if (!medicineRequestIds.isEmpty()) {
            // 根据请求id更新请求状态
            iMedicationRequestService.updateDraftStatusBatch(medicineRequestIds, null, null);
        }
        if (!activityRequestIds.isEmpty()) {
            // 根据请求id更新请求状态
            iServiceRequestService.updateDraftStatusBatch(activityRequestIds);
        }
        List<Long> requestIdList = new ArrayList<>();
        requestIdList.addAll(medicineRequestIds);
        requestIdList.addAll(activityRequestIds);
        // 根据请求编号列表查询收费项目信息
        List<ChargeItem> chargeItemList = iChargeItemService.getChargeItemInfoByReqId(requestIdList);
        List<Long> chargeItemIdList = chargeItemList.stream().map(ChargeItem::getId).collect(Collectors.toList());
        // 根据id更新收费项目状态 , 撤回后需要更新为草稿
        if (!chargeItemIdList.isEmpty()) {
            iChargeItemService.updatePaymentStatus(chargeItemIdList, ChargeItemStatus.DRAFT.getValue());
        }
        return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[]{"医嘱签退"}));
    }

    /**
     * 住院医嘱停止
     *
     * @param paramList 停嘱
     * @return 结果
     */
    @Override
    public R<?> stopRegAdvice(List<AdviceBatchOpParam> paramList) {
        // 当前时间
        Date date = new Date();
        // 药品
        List<AdviceBatchOpParam> medicineList = paramList.stream()
                .filter(e -> ItemType.MEDICINE.getValue().equals(e.getAdviceType())).collect(Collectors.toList());
        List<Long> medicineRequestIds =
                medicineList.stream().map(AdviceBatchOpParam::getRequestId).collect(Collectors.toList());
        // 诊疗
        List<AdviceBatchOpParam> activityList = paramList.stream()
                .filter(e -> ItemType.ACTIVITY.getValue().equals(e.getAdviceType())).collect(Collectors.toList());
        List<Long> activityRequestIds =
                activityList.stream().map(AdviceBatchOpParam::getRequestId).collect(Collectors.toList());
        if (!medicineRequestIds.isEmpty()) {
            iMedicationRequestService.update(new LambdaUpdateWrapper<MedicationRequest>()
                    .in(MedicationRequest::getId, medicineRequestIds).set(MedicationRequest::getEffectiveDoseEnd, date)
                    .set(MedicationRequest::getStatusEnum, RequestStatus.STOPPED.getValue()));
        }
        if (!activityRequestIds.isEmpty()) {
            iServiceRequestService.update(new LambdaUpdateWrapper<ServiceRequest>()
                    .in(ServiceRequest::getId, activityRequestIds).set(ServiceRequest::getOccurrenceEndTime, date)
                    .set(ServiceRequest::getStatusEnum, RequestStatus.STOPPED.getValue()));
        }
        return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[]{"医嘱停止"}));
    }

}
