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

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

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

import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.core.domain.entity.SysDictData;
import com.core.common.enums.DeleteFlag;
import com.core.common.utils.*;
import com.core.common.utils.bean.BeanUtils;
import com.core.common.utils.poi.ExcelUtil;
import com.core.system.service.ISysDictTypeService;
import com.openhis.administration.domain.ChargeItemDefinition;
import com.openhis.administration.domain.Location;
import com.openhis.administration.domain.Supplier;
import com.openhis.administration.service.IChargeItemDefinitionService;
import com.openhis.administration.service.ILocationService;
import com.openhis.administration.service.ISupplierService;
import com.openhis.common.constant.CommonConstants;
import com.openhis.common.constant.PromptMsgConstant;
import com.openhis.common.enums.*;
import com.openhis.common.utils.CommonUtil;
import com.openhis.common.utils.EnumUtils;
import com.openhis.common.utils.HisQueryUtils;
import com.openhis.medication.domain.Medication;
import com.openhis.medication.domain.MedicationDefinition;
import com.openhis.medication.domain.MedicationDetail;
import com.openhis.medication.domain.MedicationRequest;
import com.openhis.medication.service.IMedicationDefinitionService;
import com.openhis.medication.service.IMedicationRequestService;
import com.openhis.medication.service.IMedicationService;
import com.openhis.sys.service.IOperationRecordService;
import com.openhis.web.datadictionary.appservice.IItemDefinitionService;
import com.openhis.web.datadictionary.appservice.IMedicationManageAppService;
import com.openhis.web.datadictionary.dto.*;
import com.openhis.web.datadictionary.mapper.MedicationManageSearchMapper;
import com.openhis.workflow.service.ISupplyRequestService;
import com.openhis.yb.service.YbManager;

/**
 * TODO:DTO已UI最小需要值返回 药品目录 impl
 *
 * @author
 * @date 2025-03-17
 */
@Service
public class MedicationManageAppServiceImpl implements IMedicationManageAppService {

    @Resource
    private IMedicationService medicationService;

    @Resource
    private IMedicationDefinitionService medicationDefinitionService;

    @Resource
    private IChargeItemDefinitionService chargeItemDefinitionService;

    @Resource
    private ILocationService locationService;

    @Resource
    private MedicationManageSearchMapper medicationManageSearchMapper;

    @Resource
    private ISupplierService supplierService;

    @Resource
    private ISysDictTypeService sysDictTypeService;

    @Resource
    private IItemDefinitionService itemDefinitionServic;

    @Resource
    private AssignSeqUtil assignSeqUtil;

    @Resource
    private YbManager ybService;

    @Resource
    private IOperationRecordService operationRecordService;

    @Resource
    private ISupplyRequestService supplyRequestService;

    @Resource
    private IMedicationRequestService medicationRequestService;

    /**
     * 药品目录初始化
     *
     * @return
     */
    @Override
    public R<?> getMedicationInit() {

        MedicationManageInitDto medicationManageInitDto = new MedicationManageInitDto();
        // 获取状态，从枚举里面取下拉值
        List<MedicationManageInitDto.statusEnumOption> statusEnumOptions = Stream.of(PublicationStatus.values())
            .map(status -> new MedicationManageInitDto.statusEnumOption(status.getValue(), status.getInfo()))
            .collect(Collectors.toList());
        // 获取适用范围
        List<MedicationManageInitDto.domainEnumOption> domainEnumOptions = Stream.of(ApplicableScope.values())
            .map(domain -> new MedicationManageInitDto.domainEnumOption(domain.getValue(), domain.getInfo()))
            .collect(Collectors.toList());
        // 查询供应商列表
        List<Supplier> supplierList = supplierService.getList();
        // 供应商信息
        List<MedicationManageInitDto.supplierListOption> supplierListOptions = supplierList.stream()
            .map(supplier -> new MedicationManageInitDto.supplierListOption(supplier.getId(), supplier.getName()))
            .collect(Collectors.toList());

        // 获取药品分类
        List<SysDictData> medicalList =
            sysDictTypeService.selectDictDataByType(CommonConstants.DictName.MED_CATEGORY_CODE);
        // 获取药品分类
        List<MedicationManageInitDto.dictCategoryCode> medicationCategories = medicalList.stream().map(
            category -> new MedicationManageInitDto.dictCategoryCode(category.getDictValue(), category.getDictLabel()))
            .collect(Collectors.toList());

        // 获取是/否 列表
        // 获取状态
        List<MedicationManageInitDto.statusEnumOption> statusWeatherOption = Stream.of(Whether.values())
            .map(status -> new MedicationManageInitDto.statusEnumOption(status.getValue(), status.getInfo()))
            .collect(Collectors.toList());

        // 权限限制
        List<MedicationManageInitDto.statusEnumOption> statusRestrictedOptions = Stream.of(PermissionLimit.values())
            .map(status -> new MedicationManageInitDto.statusEnumOption(status.getValue(), status.getInfo()))
            .collect(Collectors.toList());

        // 拆分属性
        List<MedicationManageInitDto.statusEnumOption> partAttributeEnumOptions = Stream.of(SplitPropertyCode.values())
            .map(status -> new MedicationManageInitDto.statusEnumOption(status.getValue(), status.getInfo()))
            .collect(Collectors.toList());

        // 住院临时医嘱拆分属性的枚举
        List<MedicationManageInitDto.statusEnumOption> tempOrderSplitPropertyOptions =
            Stream.of(TempOrderSplitPropertyCode.values())
                .map(status -> new MedicationManageInitDto.statusEnumOption(status.getValue(), status.getInfo()))
                .collect(Collectors.toList());

        // 医保等级List
        List<MedicationManageInitDto.statusEnumOption> chrgitmLvOptions = Stream.of(InsuranceLevel.values())
            .map(status -> new MedicationManageInitDto.statusEnumOption(status.getValue(), status.getInfo()))
            .collect(Collectors.toList());

        medicationManageInitDto.setStatusFlagOptions(statusEnumOptions);
        medicationManageInitDto.setDomainFlagOptions(domainEnumOptions);
        medicationManageInitDto.setSupplierListOptions(supplierListOptions);
        medicationManageInitDto.setMedicationCategoryCodeOptions(medicationCategories);
        medicationManageInitDto.setStatusWeatherOptions(statusWeatherOption);
        medicationManageInitDto.setStatusRestrictedOptions(statusRestrictedOptions);
        medicationManageInitDto.setPartAttributeEnumOptions(partAttributeEnumOptions);
        medicationManageInitDto.setTempOrderSplitPropertyEnumOptions(tempOrderSplitPropertyOptions);
        medicationManageInitDto.setChrgitmLvOptions(chrgitmLvOptions);

        return R.ok(medicationManageInitDto);
    }

    /**
     * 已评审 药品目录查询
     *
     * @param
     * @param searchKey 查询条件-模糊查询
     * @param pageNo 查询条件
     * @param pageSize 查询条件
     * @return 药品目录查询结果
     */
    @Override
    public R<?> getMedicationList(MedicationSearchParam medicationSearchParam,
        @RequestParam(value = "searchKey", defaultValue = "") String searchKey,
        @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
        @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest request) {

        // 构建查询条件
        QueryWrapper<MedicationManageDto> queryWrapper = HisQueryUtils.buildQueryWrapper(medicationSearchParam,
            searchKey, new HashSet<>(Arrays.asList("name", "name_en", "merchandise_name", "bus_no", "py_str", "wb_str",
                "merchandise_py_str", "merchandise_wb_str")),
            null);

        IPage<MedicationManageDto> medicationManageDtoPage =
            medicationManageSearchMapper.getPage(new Page<>(pageNo, pageSize), queryWrapper);

        // 枚举类回显赋值
        medicationManageDtoPage.getRecords().forEach(e -> {
            // 药品状态
            e.setStatusEnum_enumText(EnumUtils.getInfoByValue(PublicationStatus.class, e.getStatusEnum()));
            // 权限限制
            e.setRestrictedEnum_enumText(EnumUtils.getInfoByValue(PermissionLimit.class, e.getRestrictedEnum()));
            // 是否为活性
            e.setActiveFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getActiveFlag()));
            // 医保是否对码
            e.setYbMatchFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getYbMatchFlag()));
            // 是否皮试
            e.setSkinTestFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getSkinTestFlag()));;
            // 是否为注射药物
            e.setInjectFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getInjectFlag()));
            // 是否限制使用
            e.setRestrictedFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getRestrictedFlag()));
            // 儿童用药标志
            e.setChildrenFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getChildrenFlag()));
            // 适用范围
            e.setDomainEnum_enumText(EnumUtils.getInfoByValue(ApplicableScope.class, e.getDomainEnum()));

            // 是否自制
            e.setSelfFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getSelfFlag()));
            // 是否抗生素
            e.setAntibioticFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getAntibioticFlag()));
            // 基药标识
            e.setBasicFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getBasicFlag()));
            // 拆分分属性
            e.setPartAttributeEnum_enumText(
                EnumUtils.getInfoByValue(SplitPropertyCode.class, e.getPartAttributeEnum()));
            // 住院临时医嘱拆分属性
            e.setThoPartAttributeEnum_enumText(
                EnumUtils.getInfoByValue(TempOrderSplitPropertyCode.class, e.getThoPartAttributeEnum()));
            // // 活动标记
            // e.setActiveFlag_enumText(EnumUtils.getInfoByValue(AccountStatus.class, e.getActiveFlag()));

        });

        // 返回【药品录列表DTO】分页
        return R.ok(medicationManageDtoPage);
    }

    /**
     * 已评审 编辑药品目录信息
     *
     * @param medicationManageUpDto 药品目录信息
     */
    @Override
    public R<?> editMedication(@Validated @RequestBody MedicationManageUpDto medicationManageUpDto) {
        // Todo:用Medication和medicationDefinition的domainservice来创造新的实例，根据业务需求，使用构造函数；
        // 如果小于5哥变量，就用基本类型传递，如果大于5哥，在domain层定义构造方法的入参

        MedicationDefinition medicationDefinition = new MedicationDefinition();
        Medication medication = new Medication();
        BeanUtils.copyProperties(medicationManageUpDto, medication); // 子表信息
        BeanUtils.copyProperties(medicationManageUpDto, medicationDefinition);// 主表信息
        medicationDefinition.setId(medicationManageUpDto.getMedicationDefId());
        // 拼音码
        medicationDefinition.setPyStr(ChineseConvertUtils.toPinyinFirstLetter(medicationDefinition.getName()));
        medicationDefinition
            .setMerchandisePyStr(ChineseConvertUtils.toPinyinFirstLetter(medicationDefinition.getMerchandiseName()));
        // 五笔码
        medicationDefinition.setWbStr(ChineseConvertUtils.toWBFirstLetter(medicationDefinition.getName()));
        medicationDefinition
            .setMerchandiseWbStr(ChineseConvertUtils.toWBFirstLetter(medicationDefinition.getMerchandiseName()));

        ChargeItemDefinition chargeItemDefinition = new ChargeItemDefinition();
        chargeItemDefinition.setYbType(medicationManageUpDto.getYbType())
            .setTypeCode(medicationManageUpDto.getTypeCode())
            .setInstanceTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION)
            .setInstanceId(medicationManageUpDto.getMedicationDefId()).setPrice(medicationManageUpDto.getRetailPrice())
            .setChargeName(medicationManageUpDto.getName());

        // 更新子表药品信息
        if (medicationService.updateById(medication)) {
            // 更新主表药品信息
            boolean updateMedicationDefinition = medicationDefinitionService.updateById(medicationDefinition);
            if (updateMedicationDefinition) {
                // 调用医保目录对照接口
                String ybSwitch =
                    SecurityUtils.getLoginUser().getOptionJson().getString(CommonConstants.Option.YB_SWITCH); // 医保开关
                if (Whether.YES.getCode().equals(ybSwitch) && StringUtils.isNotEmpty(medicationDefinition.getYbNo())) {
                    R<?> r = ybService.directoryCheck(CommonConstants.TableName.MED_MEDICATION_DEFINITION,
                        medicationDefinition.getId());
                    if (200 != r.getCode()) {
                        throw new RuntimeException("医保目录对照接口异常");
                    }
                }
            }

            // 插入操作记录
            operationRecordService.addEntityOperationRecord(DbOpType.UPDATE.getCode(),
                CommonConstants.TableName.MED_MEDICATION_DEFINITION, medication);
            // Todo:封装一个价格初始话的方法给app层调用
            // 更新价格表
            boolean updateChargeItemDefinition = itemDefinitionServic.updateItem(chargeItemDefinition);
            // 更新子表,修改购入价,条件:采购
            boolean upItemDetail1 = itemDefinitionServic.updateItemDetail(chargeItemDefinition,
                medicationManageUpDto.getPurchasePrice(), ConditionCode.PURCHASE.getCode());
            // 更新子表,修改零售价,条件:单位
            boolean upItemDetail2 = itemDefinitionServic.updateItemDetail(chargeItemDefinition,
                medicationManageUpDto.getRetailPrice(), ConditionCode.UNIT.getCode());
            // 更新子表,修改最高零售价,条件:限制
            boolean upItemDetail3 = itemDefinitionServic.updateItemDetail(chargeItemDefinition,
                medicationManageUpDto.getMaximumRetailPrice(), ConditionCode.LIMIT.getCode());

            return (updateMedicationDefinition && updateChargeItemDefinition && upItemDetail1 && upItemDetail2
                && upItemDetail3)
                    ? R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[] {"药品目录"}))
                    : R.fail(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null));
        } else {
            return R.fail(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null));
        }
    }

    /**
     * 已评审 药品目录详细查询
     *
     * @param id 查询条件
     * @return 药品目录查询结果
     */
    @Override
    public R<?> getMedicationOne(@RequestParam Long id) {

        // 获取租户ID
        Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
        // 查询药品目录列表
        MedicationManageDto medicationManageDto = medicationManageSearchMapper.getOne(id, tenantId);
        // 返回【药品录列表DTO】列表
        return R.ok(medicationManageDto);
    }

    /**
     * 药品目录停用
     *
     * @param ids 药品目录ID列表
     * @return
     */
    @Override
    public R<?> editMedicationStop(List<Long> ids) {

        List<Medication> medicationList = new ArrayList<>();
        // 取得更新值
        for (Long detail : ids) {
            Medication medication = new Medication();
            medication.setId(detail);
            medication.setStatusEnum(PublicationStatus.RETIRED.getValue());
            medicationList.add(medication);
        }

        // TODO:别用三元，日志在业务代码以后记录
        // 插入操作记录
        operationRecordService.addIdsOperationRecord(DbOpType.STOP.getCode(),
            CommonConstants.TableName.MED_MEDICATION_DEFINITION, ids);
        // 更新药品信息
        return medicationService.updateBatchById(medicationList)
            ? R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[] {"药品目录"}))
            : R.fail(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null));
    }

    /**
     * TODO：业务代码写在Domain里 药品目录启用
     *
     * @param ids 药品目录ID列表
     * @return
     */
    @Override
    public R<?> editMedicationStart(List<Long> ids) {

        List<Medication> medicationList = new ArrayList<>();
        // 取得更新值
        for (Long detail : ids) {
            Medication medication = new Medication();
            medication.setId(detail);
            medication.setStatusEnum(PublicationStatus.ACTIVE.getValue());
            medicationList.add(medication);
        }
        // 插入操作记录
        operationRecordService.addIdsOperationRecord(DbOpType.START.getCode(),
            CommonConstants.TableName.MED_MEDICATION_DEFINITION, ids);
        // 更新药品信息
        return medicationService.updateBatchById(medicationList)
            ? R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[] {"药品目录"}))
            : R.fail(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null));
    }

    /**
     * 添加药品目录信息
     *
     * @param medicationManageUpDto 药品目录信息
     */
    @Override
    public R<?> addMedication(@Validated @RequestBody MedicationManageUpDto medicationManageUpDto) {

        MedicationDetail medicationDetail = new MedicationDetail();
        BeanUtils.copyProperties(medicationManageUpDto, medicationDetail);
        medicationDetail.setStatusEnum(PublicationStatus.ACTIVE.getValue());
        // 使用10位数基础采番
        String code = assignSeqUtil.getSeq(AssignSeqEnum.MEDICATION_NUM.getPrefix(), 10);
        medicationDetail.setBusNo(code);
        // 拼音码
        medicationDetail.setPyStr(ChineseConvertUtils.toPinyinFirstLetter(medicationDetail.getName()));
        medicationDetail
            .setMerchandisePyStr(ChineseConvertUtils.toPinyinFirstLetter(medicationDetail.getMerchandiseName()));
        // 五笔码
        medicationDetail.setWbStr(ChineseConvertUtils.toWBFirstLetter(medicationDetail.getName()));
        medicationDetail
            .setMerchandiseWbStr(ChineseConvertUtils.toWBFirstLetter(medicationDetail.getMerchandiseName()));

        // 新增主表外来药品目录
        if (medicationDefinitionService.addMedication(medicationDetail)) {
            // 调用医保目录对照接口
            String ybSwitch = SecurityUtils.getLoginUser().getOptionJson().getString(CommonConstants.Option.YB_SWITCH); // 医保开关
            if (Whether.YES.getCode().equals(ybSwitch) && StringUtils.isNotEmpty(medicationDetail.getYbNo())) {
                R<?> r = ybService.directoryCheck(CommonConstants.TableName.MED_MEDICATION_DEFINITION,
                    medicationDetail.getId());
                if (200 != r.getCode()) {
                    throw new RuntimeException("医保目录对照接口异常");
                }
            }
            // 插入操作记录
            operationRecordService.addEntityOperationRecord(DbOpType.INSERT.getCode(),
                CommonConstants.TableName.MED_MEDICATION_DEFINITION, medicationDetail);
            // 新增子表外来药品目录
            boolean insertMedicationSuccess = medicationService.addMedication(medicationDetail);
            ItemUpFromDirectoryDto itemUpFromDirectoryDto = new ItemUpFromDirectoryDto();
            BeanUtils.copyProperties(medicationManageUpDto, itemUpFromDirectoryDto);
            itemUpFromDirectoryDto.setInstanceId(medicationDetail.getMedicationDefId())
                .setStatusEnum(PublicationStatus.ACTIVE.getValue())
                .setInstanceTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION)
                .setEffectiveStart(DateUtils.getNowDate()).setOrgId(SecurityUtils.getLoginUser().getOrgId())
                .setConditionFlag(Whether.YES.getValue()).setChargeName(medicationDetail.getName())
                .setPrice(medicationManageUpDto.getRetailPrice());

            // 添加药品成功后，添加相应的条件价格表信息
            boolean insertItemDefinitionSuccess = itemDefinitionServic.addItem(itemUpFromDirectoryDto);

            return (insertMedicationSuccess && insertItemDefinitionSuccess)
                ? R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[] {"药品目录"}))
                : R.fail(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00008, null));
        } else {
            return R.fail(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00008, null));
        }
    }

    @Override
    public R<?> exportMedication(String searchKey, Integer ybMatchFlag, Integer statusEnum, String categoryCode,
        HttpServletResponse response) {
        // 获取租户ID
        Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
        List<MedicationManageDto> list =
            medicationManageSearchMapper.getList(searchKey, ybMatchFlag, statusEnum, categoryCode, tenantId);
        ExcelUtil<MedicationManageDto> util = new ExcelUtil<>(MedicationManageDto.class);
        util.exportExcel(response, list, "药品目录");
        return null;
    }

    /**
     * 导入药品目录
     *
     * @param file 文件
     * @return 结果
     */
    @Override
    public R<?> importData(MultipartFile file) {
        // 读取文件
        R<List<MedicationImportDto>> readResult = CommonUtil.readImportedExcelFile(file, MedicationImportDto.class);
        if (R.SUCCESS != readResult.getCode()) {
            return readResult;
        }
        List<MedicationImportDto> importDtoList = readResult.getData();
        // 导入信息校验
        R<?> validateResult = validateImportDtoList(importDtoList);
        if (R.SUCCESS != validateResult.getCode()) {
            return validateResult;
        }
        // 查询机构ID、位置信息供后续使用
        Long orgId = SecurityUtils.getLoginUser().getOrgId();
        List<Location> locationList = locationService.list(new LambdaQueryWrapper<Location>()
            .eq(Location::getDeleteFlag, DeleteFlag.NOT_DELETED.getCode()).orderByAsc(Location::getId));
        Long defaultLocationId = locationList.stream().findFirst().orElse(new Location()).getId();
        Map<String, List<Location>> locationNameMap =
            locationList.stream().collect(Collectors.groupingBy(Location::getName));
        // 创建表数据
        for (MedicationImportDto importDto : importDtoList) {
            // 创建药品定义
            MedicationDefinition medicationDefinition = createMedicationDefinitionEntity(importDto);
            medicationDefinitionService.save(medicationDefinition);
            // 创建药品
            Medication medication =
                createMedicationEntity(importDto, medicationDefinition.getId(), defaultLocationId, locationNameMap);
            medicationService.save(medication);
            // 创建费用定价和详情
            chargeItemDefinitionService.addChargeItemDefinitionAndDetail(importDto.getName(), importDto.getTypeCode(),
                importDto.getYbType(), importDto.getUnitCode(), importDto.getPurchasePrice(),
                importDto.getRetailPrice(), importDto.getMaximumRetailPrice(), orgId,
                CommonConstants.TableName.MED_MEDICATION_DEFINITION, medicationDefinition.getId());
        }
        return R.ok(null, "导入成功！");
    }

    /**
     * 获取导入模板
     *
     * @param response 响应
     */
    @Override
    public void importTemplate(HttpServletResponse response) {
        ExcelUtil<MedicationImportDto> util = new ExcelUtil<>(MedicationImportDto.class);
        util.importTemplateExcel(response, "药品目录数据");
    }

    /**
     * 校验药品是否可以编辑
     *
     * @param medicationId 药品ID
     * @return 校验结果
     */
    @Override
    public R<?> validateMedicationEdit(Long medicationId) {
        List<MedicationRequest> medicationRequestList =
            medicationRequestService.getMedRequestByMedicationId(medicationId);
        if (!medicationRequestList.isEmpty()) {
            if (medicationRequestList.stream()
                .allMatch(x -> x.getStatusEnum().equals(RequestStatus.COMPLETED.getValue()))) {
                return R.ok(1, "医生开过该药品，不可编辑");
            } else {
                // 校验是否可以编辑
                boolean result = supplyRequestService.verifyAbleEdit(medicationId);
                if (result) {
                    return R.ok(2, "该药品已经入库过，不可编辑");
                }
            }
        }
        return R.ok();
    }

    /**
     * 导入信息校验
     * 
     * @param importDtoList 药品目录导入数据列表
     */
    private R<?> validateImportDtoList(List<MedicationImportDto> importDtoList) {
        // 字段校验（必填及数值类型）
        List<String> fieldValidateMsgList = new ArrayList<>();
        for (int i = 0; i < importDtoList.size(); i++) {
            MedicationImportDto importDto = importDtoList.get(i);
            importDto.setLineNumber(i + 2);
            List<String> lineValidateMsgList = new ArrayList<>();
            if (StringUtils.isEmpty(importDto.getName())) {
                lineValidateMsgList.add("药品名称必填");
            }
            if (StringUtils.isEmpty(importDto.getCategoryCode())) {
                lineValidateMsgList.add("药品分类必填");
            }
            if (Whether.YES.getCode().equals(importDto.getYbMatchFlag())
                && !MedCategoryCode.TRADITIONAL_CHINESE_MEDICINE.getValue().equals(importDto.getCategoryCode())
                && !MedCategoryCode.WESTERN_MEDICINE.getValue().equals(importDto.getCategoryCode())
                && !MedCategoryCode.CHINESE_HERBAL_MEDICINE.getValue().equals(importDto.getCategoryCode())) {
                lineValidateMsgList.add("医保药的药品分类只能选择中成药、西药或中草药；");
            }
            if (StringUtils.isEmpty(importDto.getMerchandiseName())) {
                lineValidateMsgList.add("商品名称必填");
            }
            if (StringUtils.isEmpty(importDto.getPharmacologyCategoryCode())) {
                lineValidateMsgList.add("药品性质必填");
            }
            if (StringUtils.isEmpty(importDto.getUnitCode())) {
                lineValidateMsgList.add("药品单位必填");
            }
            if (StringUtils.isEmpty(importDto.getMinUnitCode())) {
                lineValidateMsgList.add("最小单位必填");
            }
            if (StringUtils.isEmpty(importDto.getPartPercentStr())) {
                lineValidateMsgList.add("拆零比必填");
            }
            BigDecimal partPercent;
            try {
                partPercent = new BigDecimal(importDto.getPartPercentStr());
                importDto.setPartPercent(partPercent);
            } catch (Exception e) {
                lineValidateMsgList.add("拆零比应为数值类型");
            }
            if (StringUtils.isEmpty(importDto.getDoseFrom())) {
                lineValidateMsgList.add("剂量形式必填");
            }
            if (StringUtils.isEmpty(importDto.getYbMatchFlag())) {
                lineValidateMsgList.add("医保是否对码必填");
            }
            if (Whether.YES.getCode().equals(importDto.getYbMatchFlag()) && StringUtils.isEmpty(importDto.getYbNo())) {
                lineValidateMsgList.add("医保对码时，医保编码必填");
            }
            if (StringUtils.isEmpty(importDto.getSkinTestFlag())) {
                lineValidateMsgList.add("是否皮试必填");
            }
            if (StringUtils.isEmpty(importDto.getInjectFlag())) {
                lineValidateMsgList.add("是否为注射药物必填");
            }
            if (StringUtils.isEmpty(importDto.getRestrictedFlag())) {
                lineValidateMsgList.add("是否限制使用必填");
            }
            if (Whether.YES.getCode().equals(importDto.getRestrictedFlag())
                && StringUtils.isEmpty(importDto.getRestrictedScope())) {
                lineValidateMsgList.add("限制使用时，限制使用范围必填");
            }
            if (StringUtils.isEmpty(importDto.getChildrenFlag())) {
                lineValidateMsgList.add("儿童用药标志必填");
            }
            if (StringUtils.isEmpty(importDto.getPartAttributeEnum())) {
                lineValidateMsgList.add("拆分属性必填");
            }
            if (StringUtils.isEmpty(importDto.getAntibioticFlag())) {
                lineValidateMsgList.add("是否抗生素必填");
            }
            if (Whether.YES.getCode().equals(importDto.getAntibioticFlag())
                && StringUtils.isEmpty(importDto.getAntibioticCode())) {
                lineValidateMsgList.add("为抗生素时，抗生素分类必填");
            }
            if (StringUtils.isEmpty(importDto.getSelfFlag())) {
                lineValidateMsgList.add("是否自制必填");
            }
            if (StringUtils.isEmpty(importDto.getBasicFlag())) {
                lineValidateMsgList.add("基药标识必填");
            }
            if (StringUtils.isEmpty(importDto.getManufacturerText())) {
                lineValidateMsgList.add("生产厂商文本必填");
            }
            if (StringUtils.isEmpty(importDto.getThoPartAttributeEnum())) {
                lineValidateMsgList.add("住院临时医嘱拆分属性必填");
            }
            if (StringUtils.isEmpty(importDto.getUnitConversionRatioStr())) {
                lineValidateMsgList.add("剂量单位换算比必填");
            }
            BigDecimal unitConversionRatio;
            try {
                unitConversionRatio = new BigDecimal(importDto.getUnitConversionRatioStr());
                importDto.setUnitConversionRatio(unitConversionRatio);
            } catch (Exception e) {
                lineValidateMsgList.add("剂量单位换算比应为数值类型");
            }
            if (StringUtils.isEmpty(importDto.getChrgitmLv())) {
                lineValidateMsgList.add("医保等级必填");
            }
            if (StringUtils.isEmpty(importDto.getRxFlag())) {
                lineValidateMsgList.add("处方标志必填");
            }
            if (StringUtils.isEmpty(importDto.getItemMinQuantityStr())) {
                lineValidateMsgList.add("最小库存警戒数量(常规单位)必填");
            }
            BigDecimal itemMinQuantity;
            try {
                itemMinQuantity = new BigDecimal(importDto.getItemMinQuantityStr());
                importDto.setItemMinQuantity(itemMinQuantity);
            } catch (Exception e) {
                lineValidateMsgList.add("最小库存警戒数量(常规单位)应为数值类型");
            }
            if (StringUtils.isEmpty(importDto.getItemMaxQuantityStr())) {
                lineValidateMsgList.add("最大库存警戒数量(常规单位)必填");
            }
            BigDecimal itemMaxQuantity;
            try {
                itemMaxQuantity = new BigDecimal(importDto.getItemMaxQuantityStr());
                importDto.setItemMaxQuantity(itemMaxQuantity);
            } catch (Exception e) {
                lineValidateMsgList.add("最大库存警戒数量(常规单位)应为数值类型");
            }
            if (StringUtils.isEmpty(importDto.getLocationName())) {
                lineValidateMsgList.add("所在位置名称必填");
            }
            if (StringUtils.isEmpty(importDto.getTotalVolume())) {
                lineValidateMsgList.add("规格必填");
            }
            if (StringUtils.isNotEmpty(importDto.getDoseStr())) {
                BigDecimal dose;
                try {
                    dose = new BigDecimal(importDto.getDoseStr());
                    importDto.setDose(dose);
                } catch (Exception e) {
                    lineValidateMsgList.add("单次剂量应为数值类型");
                }
            }
            if (StringUtils.isNotEmpty(importDto.getMaxUnitStr())) {
                BigDecimal maxUnit;
                try {
                    maxUnit = new BigDecimal(importDto.getMaxUnitStr());
                    importDto.setMaxUnit(maxUnit);
                } catch (Exception e) {
                    lineValidateMsgList.add("单次最大剂量应为数值类型");
                }
            }
            if (StringUtils.isEmpty(importDto.getTypeCode())) {
                lineValidateMsgList.add("财务类别必填");
            }
            if (StringUtils.isEmpty(importDto.getYbType())) {
                lineValidateMsgList.add("医保费用类别必填");
            }
            if (StringUtils.isEmpty(importDto.getPurchasePriceStr())) {
                lineValidateMsgList.add("购入价必填");
            }
            BigDecimal purchasePrice;
            try {
                purchasePrice = new BigDecimal(importDto.getPurchasePriceStr());
                importDto.setPurchasePrice(purchasePrice);
            } catch (Exception e) {
                lineValidateMsgList.add("购入价应为数值类型");
            }
            if (StringUtils.isEmpty(importDto.getRetailPriceStr())) {
                lineValidateMsgList.add("零售价必填");
            }
            BigDecimal retailPrice;
            try {
                retailPrice = new BigDecimal(importDto.getRetailPriceStr());
                importDto.setRetailPrice(retailPrice);
            } catch (Exception e) {
                lineValidateMsgList.add("零售价应为数值类型");
            }
            if (StringUtils.isEmpty(importDto.getMaximumRetailPriceStr())) {
                lineValidateMsgList.add("最高零售价必填");
            }
            BigDecimal maximumRetailPrice;
            try {
                maximumRetailPrice = new BigDecimal(importDto.getMaximumRetailPriceStr());
                importDto.setMaximumRetailPrice(maximumRetailPrice);
            } catch (Exception e) {
                lineValidateMsgList.add("最高零售价应为数值类型");
            }
            if (!lineValidateMsgList.isEmpty()) {
                fieldValidateMsgList
                    .add("■ 第" + importDto.getLineNumber() + "行：" + String.join("，", lineValidateMsgList) + "；");
            }
        }
        if (!fieldValidateMsgList.isEmpty()) {
            return R.fail("导入失败！药品信息填写有误：" + String.join(" ", fieldValidateMsgList) + " ■ ※如遇到模板中不存在的字段，请重新下载模板");
        }
        // 重复校验（文件行重复）
        List<String> lineRepeatedValidateMsgList = new ArrayList<>();
        List<List<MedicationImportDto>> importDtoGroupList = new ArrayList<>(importDtoList.stream()
            .collect(Collectors.groupingBy(e -> e.getName() + e.getManufacturerText() + e.getTotalVolume())).values());
        for (List<MedicationImportDto> importDtoGroup : importDtoGroupList) {
            if (importDtoGroup.size() > 1) {
                lineRepeatedValidateMsgList
                    .add(
                        "■ 第"
                            + importDtoGroup.stream().map(MedicationImportDto::getLineNumber).sorted()
                                .map(Object::toString).collect(Collectors.joining(","))
                            + "行的【" + importDtoGroup.get(0).getName() + "】重复；");
            }
        }
        if (!lineRepeatedValidateMsgList.isEmpty()) {
            return R.fail("导入失败！文件中存在重复药品：" + String.join(" ", lineRepeatedValidateMsgList));
        }
        // 重复校验（文件与数据库重复）
        List<String> dbRepeatedValidateMsgList = new ArrayList<>();
        for (MedicationImportDto importDto : importDtoList) {
            List<MedicationDefinition> medicationDefinitionList = medicationDefinitionService.list(
                new LambdaQueryWrapper<MedicationDefinition>().eq(MedicationDefinition::getName, importDto.getName())
                    .eq(MedicationDefinition::getManufacturerText, importDto.getManufacturerText()));
            if (!medicationDefinitionList.isEmpty()) {
                List<Medication> medicationList =
                    medicationService.list(new LambdaQueryWrapper<Medication>()
                        .in(Medication::getMedicationDefId,
                            medicationDefinitionList.stream().map(MedicationDefinition::getId)
                                .collect(Collectors.toList()))
                        .eq(Medication::getTotalVolume, importDto.getTotalVolume()));
                if (!medicationList.isEmpty()) {
                    dbRepeatedValidateMsgList
                        .add("■ 第" + importDto.getLineNumber() + "行的【" + importDto.getName() + "】在系统中已存在；");
                }
            }
        }
        if (!dbRepeatedValidateMsgList.isEmpty()) {
            return R.fail("导入失败！系统中存在重复药品：" + String.join(" ", dbRepeatedValidateMsgList));
        }
        return R.ok();
    }

    /**
     * 创建药品定义实体
     * 
     * @param importDto 药品目录导入Dto
     * @return 药品定义实体
     */
    private MedicationDefinition createMedicationDefinitionEntity(MedicationImportDto importDto) {
        MedicationDefinition medicationDefinition = new MedicationDefinition();
        medicationDefinition.setName(importDto.getName())
            .setBusNo(assignSeqUtil.getSeq(AssignSeqEnum.MEDICATION_NUM.getPrefix(), 10)).setDomainEnum(1)
            .setVersion(importDto.getVersion()).setNameEn(importDto.getNameEn())
            .setPyStr(ChineseConvertUtils.toPinyinFirstLetter(importDto.getName()))
            .setWbStr(ChineseConvertUtils.toWBFirstLetter(importDto.getName()))
            .setCategoryCode(importDto.getCategoryCode()).setMerchandiseName(importDto.getMerchandiseName())
            .setMerchandisePyStr(ChineseConvertUtils.toPinyinFirstLetter(importDto.getMerchandiseName()))
            .setMerchandiseWbStr(ChineseConvertUtils.toPinyinFirstLetter(importDto.getMerchandiseName()))
            .setUnitCode(importDto.getUnitCode()).setMinUnitCode(importDto.getMinUnitCode())
            .setPartPercent(importDto.getPartPercent()).setDoseFrom(CommonUtil.tryParseInt(importDto.getDoseFrom()))
            .setApprovalNumber(importDto.getApprovalNumber())
            .setYbMatchFlag(CommonUtil.tryParseInt(importDto.getYbMatchFlag())).setYbNo(importDto.getYbNo())
            .setPharmacologyCategoryCode(importDto.getPharmacologyCategoryCode())
            .setSkinTestFlag(CommonUtil.tryParseInt(importDto.getSkinTestFlag()))
            .setInjectFlag(CommonUtil.tryParseInt(importDto.getInjectFlag()))
            .setManufacturerText(importDto.getManufacturerText())
            .setRestrictedFlag(CommonUtil.tryParseInt(importDto.getRestrictedFlag()))
            .setRestrictedScope(importDto.getRestrictedScope()).setActiveFlag(Whether.YES.getValue())
            .setChildrenFlag(CommonUtil.tryParseInt(importDto.getChildrenFlag()))
            .setNationalDrugCode(importDto.getNationalDrugCode())
            .setPartAttributeEnum(CommonUtil.tryParseInt(importDto.getPartAttributeEnum()))
            .setAntibioticCode(importDto.getAntibioticCode())
            .setSelfFlag(CommonUtil.tryParseInt(importDto.getSelfFlag()))
            .setAntibioticFlag(CommonUtil.tryParseInt(importDto.getAntibioticFlag()))
            .setBasicFlag(CommonUtil.tryParseInt(importDto.getBasicFlag()))
            .setThoPartAttributeEnum(CommonUtil.tryParseInt(importDto.getThoPartAttributeEnum()))
            .setUnitConversionRatio(importDto.getUnitConversionRatio())
            .setChrgitmLv(CommonUtil.tryParseInt(importDto.getChrgitmLv()))
            .setRxFlag(CommonUtil.tryParseInt(importDto.getRxFlag())).setItemMinQuantity(importDto.getItemMinQuantity())
            .setItemMaxQuantity(importDto.getItemMaxQuantity());
        return medicationDefinition;
    }

    /**
     * 创建药品基本实体
     * 
     * @param importDto 药品目录导入Dto
     * @param medicationDefId 药品定义ID
     * @param defaultLocationId 默认位置ID
     * @param locationNameMap 位置名称匹配分组Map
     * @return 药品基本实体
     */
    private Medication createMedicationEntity(MedicationImportDto importDto, Long medicationDefId,
        Long defaultLocationId, Map<String, List<Location>> locationNameMap) {
        Medication medication = new Medication();
        // 根据输入的所在位置名称获取位置ID
        List<Location> mapLocationList = locationNameMap.get(importDto.getLocationName());
        if (mapLocationList == null || mapLocationList.isEmpty()) {
            medication.setLocationId(defaultLocationId);
        } else {
            medication.setLocationId(mapLocationList.get(0).getId());
        }
        medication.setMedicationDefId(medicationDefId).setStatusEnum(PublicationStatus.ACTIVE.getValue())
            .setDoseFormCode(importDto.getDoseFrom()).setTotalVolume(importDto.getTotalVolume())
            .setActiveFlag(Whether.YES.getValue()).setMethodCode(importDto.getMethodCode())
            .setRateCode(importDto.getRateCode()).setDose(importDto.getDose())
            .setDoseUnitCode(importDto.getDoseUnitCode()).setMaxUnit(importDto.getMaxUnit());
        return medication;
    }

}
