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

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

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

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

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.constant.HttpStatus;
import com.core.common.core.domain.R;
import com.core.common.exception.ServiceException;
import com.core.common.utils.*;
import com.openhis.common.constant.CommonConstants;
import com.openhis.common.constant.PromptMsgConstant;
import com.openhis.common.enums.*;
import com.openhis.common.enums.ybenums.YbDrordType;
import com.openhis.common.utils.EnumUtils;
import com.openhis.common.utils.HisQueryUtils;
import com.openhis.medication.service.IMedicationDispenseService;
import com.openhis.web.inhospitalnursestation.appservice.IMedicineSummaryAppService;
import com.openhis.web.inhospitalnursestation.dto.InpatientMedicineEncounterInfoDto;
import com.openhis.web.inhospitalnursestation.dto.InpatientMedicinePrescriptionInfoDto;
import com.openhis.web.inhospitalnursestation.dto.InpatientMedicineSearchParam;
import com.openhis.web.inhospitalnursestation.mapper.InpatientMedicineCollectionMapper;
import com.openhis.web.pharmacymanage.dto.InventoryDto;
import com.openhis.web.pharmacymanage.mapper.ReturnMedicineMapper;
import com.openhis.workflow.domain.InventoryItem;
import com.openhis.workflow.domain.SupplyDelivery;
import com.openhis.workflow.domain.SupplyRequest;
import com.openhis.workflow.service.IDeviceDispenseService;
import com.openhis.workflow.service.ISupplyDeliveryService;
import com.openhis.workflow.service.ISupplyRequestService;

/**
 * 住院领药 应用实现类
 *
 * @author yuxj
 * @date 2025/8/18
 */
@Service
public class MedicineSummaryAppServiceImpl implements IMedicineSummaryAppService {

    @Resource
    private AssignSeqUtil assignSeqUtil;

    @Autowired
    private IMedicationDispenseService medicationDispenseService;

    @Autowired
    private IDeviceDispenseService deviceDispenseService;

    @Autowired
    private InpatientMedicineCollectionMapper inpatientMedicineCollectionMapper;
    @Resource
    private ISupplyRequestService supplyRequestService;

    @Resource
    private ISupplyDeliveryService supplyDeliveryService;
    @Autowired
    private ReturnMedicineMapper returnMedicineMapper;

    /**
     * 分页查询在科病人列表
     *
     * @param searchParam 查询条件
     * @param searchKey 模糊查询关键字
     * @param pageNo 当前页码
     * @param pageSize 查询条数
     * @param request 请求数据
     * @return 发药病人列表
     */
    @Override
    public R<?> getEncounterInfoListPage(InpatientMedicineSearchParam searchParam, String searchKey, Integer pageNo,
        Integer pageSize, HttpServletRequest request) {
        // 参与者科室id
        Long orgId = SecurityUtils.getLoginUser().getOrgId();
        searchParam.setOrganizationId(orgId);

        // 构建查询条件
        QueryWrapper<InpatientMedicineSearchParam> queryWrapper =
            HisQueryUtils.buildQueryWrapper(searchParam, searchKey,
                new HashSet<>(
                    Arrays.asList(CommonConstants.FieldName.PatientWbStr, CommonConstants.FieldName.PatientPyStr,
                        CommonConstants.FieldName.PatientName, CommonConstants.FieldName.InpatientBed)),
                request);
        queryWrapper.orderByDesc(CommonConstants.FieldName.EncounterId);

        // 查询就诊病人列表
        Page<InpatientMedicineEncounterInfoDto> encounterInfoPageDto = inpatientMedicineCollectionMapper
            .selectEncounterInfoListPage(new Page<>(pageNo, pageSize), queryWrapper, EncounterClass.IMP.getValue());

        // 个别项目设定
        encounterInfoPageDto.getRecords().forEach(patientInfoDto -> {
            // 性别
            patientInfoDto.setGenderEnum_enumText(
                EnumUtils.getInfoByValue(AdministrativeGender.class, patientInfoDto.getGenderEnum()));
            // 年龄
            patientInfoDto.setAge(AgeCalculatorUtil.getAge(patientInfoDto.getBirthDate()));
        });

        return R.ok(encounterInfoPageDto);
    }

    /**
     * 查询医嘱列表
     *
     * @param searchParam 查询条件
     * @param searchKey 模糊查询关键字
     * @param pageNo 当前页码
     * @param pageSize 查询条数
     * @param request 请求数据
     * @return 处方单列表
     */
    @Override
    public R<?> getPrescriptionInfo(InpatientMedicineSearchParam searchParam, String searchKey, Integer pageNo,
        Integer pageSize, HttpServletRequest request) {

        // 就诊id
        List<Long> encounterIdList = searchParam.getEncounterIdList();
        searchParam.setEncounterIdList(null);

        // 构建查询条件
        QueryWrapper<InpatientMedicineSearchParam> queryWrapper =
            HisQueryUtils.buildQueryWrapper(searchParam, searchKey, null, request);
        queryWrapper.orderByDesc(CommonConstants.FieldName.BusNo);
        queryWrapper.le(CommonConstants.FieldName.PlannedDispenseTime, searchParam.getPlannedDispenseTime());
        // queryWrapper.in(CommonConstants.FieldName.encounterId,encounterIdList);
        searchParam.setPlannedDispenseTime(null);

        // 查询医嘱列表
        Page<InpatientMedicinePrescriptionInfoDto> prescriptionInfoPageDto =
            inpatientMedicineCollectionMapper.selectPrescriptionInfoListPage(new Page<>(pageNo, pageSize), queryWrapper,
                encounterIdList, DispenseStatus.IN_PROGRESS.getValue(),
                CommonConstants.TableName.MED_MEDICATION_DEFINITION, CommonConstants.TableName.ADM_DEVICE_DEFINITION);
        // 个别项目设定
        prescriptionInfoPageDto.getRecords().forEach(prescriptionInfo -> {
            // 治疗类型
            prescriptionInfo.setTherapyEnum_enumText(
                EnumUtils.getInfoByValue(YbDrordType.class, prescriptionInfo.getTherapyEnum()));
            // 状态
            prescriptionInfo.setStatusEnum_enumText(
                EnumUtils.getInfoByValue(DispenseStatus.class, prescriptionInfo.getStatusEnum()));
        });

        return R.ok(prescriptionInfoPageDto);
    }

    /**
     * 显示汇总发药单（生成之前的确认，此刻还没生成汇总单）
     *
     * @param searchParam 查询条件
     * @param pageNo 当前页码
     * @param pageSize 查询条数
     * @return 处理结果
     */
    @Override
    public R<?> showMedicineSummary(List<InpatientMedicineSearchParam> searchParam, Integer pageNo, Integer pageSize) {
        // 药品发放id
        List<Long> medDispenseId = searchParam.stream()
            .filter(param -> param != null
                && Objects.equals(param.getItemTable(), CommonConstants.TableName.MED_MEDICATION_DEFINITION))
            .map(InpatientMedicineSearchParam::getDispenseId).collect(Collectors.toList());
        // 耗材发放id
        List<Long> devDispenseId = searchParam.stream()
            .filter(param -> param != null
                && Objects.equals(param.getItemTable(), CommonConstants.TableName.ADM_DEVICE_DEFINITION))
            .map(InpatientMedicineSearchParam::getDispenseId).collect(Collectors.toList());

        // 构建查询条件
        QueryWrapper<InpatientMedicineSearchParam> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByAsc(CommonConstants.FieldName.itemId);

        // 查询汇总医嘱列表
        Page<InpatientMedicinePrescriptionInfoDto> prescriptionSummaryInfoPageDto =
            inpatientMedicineCollectionMapper.selectPrescriptionSummaryInfoListPage(new Page<>(pageNo, pageSize),
                queryWrapper, medDispenseId, devDispenseId, CommonConstants.TableName.MED_MEDICATION_DEFINITION,
                CommonConstants.TableName.ADM_DEVICE_DEFINITION);
        // 个别项目设定
        prescriptionSummaryInfoPageDto.getRecords().forEach(prescriptionInfo -> {
            // 地点类型
            prescriptionInfo.setLocationEnum_enumText(
                EnumUtils.getInfoByValue(LocationForm.class, prescriptionInfo.getLocationEnum()));
        });

        return R.ok(prescriptionSummaryInfoPageDto);
    }

    /**
     * 生成汇总发药单
     *
     * @param prescriptionInfo 汇总发药单
     * @return 处理结果
     */
    @Override
    public R<?> medicineSummary(List<InpatientMedicinePrescriptionInfoDto> prescriptionInfo) {
        // 药品发放id
        List<Long> medDispenseId = new ArrayList<>();
        // 耗材发放id
        List<Long> devDispenseId = new ArrayList<>();
        // 供应申请
        List<SupplyRequest> supplyRequestList = new ArrayList<>();
        SupplyRequest supplyRequest;
        // 供应发放
        List<SupplyDelivery> supplyDeliveryList = new ArrayList<>();
        SupplyDelivery supplyDelivery;
        Date now = DateUtils.getNowDate();

        // 校验库存
        R<?> checkInventoryReturn = this.checkInventoryItem(devDispenseId, medDispenseId);
        if (checkInventoryReturn.getCode() != HttpStatus.SUCCESS) {
            return checkInventoryReturn;
        }

        // 单据号
        String busNo = assignSeqUtil.getSeqByDay(AssignSeqEnum.DISPENSING_ORDER.getPrefix(), 4);
        if (prescriptionInfo.stream().map(InpatientMedicinePrescriptionInfoDto::getStatusEnum)
            .anyMatch(x -> x.equals(DispenseStatus.SUMMARIZED.getValue()))) {
            throw new ServiceException("药品已汇总，请勿重复汇总");
        } else {
            for (InpatientMedicinePrescriptionInfoDto item : prescriptionInfo) {
                // 供应申请
                supplyRequest = new SupplyRequest().setBusNo(busNo).setTypeEnum(SupplyType.DISPENSING_ORDER.getValue())
                    .setStatusEnum(SupplyStatus.SEND.getValue())
                    .setCategoryEnum(SupplyCategory.INPATIENT_PATIENT_SUMMARY_DISPENSING.getValue())
                    .setItemTable(item.getItemTable()).setItemId(item.getItemId()).setUnitCode(item.getUnitCode())
                    .setItemQuantity(new BigDecimal(item.getQuantity())).setLotNumber(item.getLotNumber())
                    .setSourceTypeEnum(item.getLocationEnum()).setSourceLocationId(item.getLocationId())
                    .setPurposeTypeEnum(LocationForm.DEPARTMENT.getValue())
                    .setPurposeLocationId(SecurityUtils.getLoginUser().getOrgId())
                    .setApplicantId(SecurityUtils.getLoginUser().getPractitionerId()).setApplyTime(now);
                supplyRequestList.add(supplyRequest);

                // 供应发放
                supplyDelivery = new SupplyDelivery().setRequestId(supplyRequest.getId())
                    .setStatusEnum(DispenseStatus.IN_PROGRESS.getValue()).setTypeEnum(supplyRequest.getTypeEnum())
                    .setItemTable(supplyRequest.getItemTable()).setItemId(supplyRequest.getItemId())
                    .setBasedOnIds(item.getDispenseIds()).setUnitCode(supplyRequest.getUnitCode())
                    .setQuantity(supplyRequest.getItemQuantity()).setLotNumber(supplyRequest.getLotNumber())
                    .setReceiverId(SecurityUtils.getLoginUser().getPractitionerId());
                if (item.getItemTable().equals(CommonConstants.TableName.MED_MEDICATION_DEFINITION)) {
                    // 设置供应发放信息
                    supplyDelivery.setBasedOnTable(CommonConstants.TableName.MED_MEDICATION_DISPENSE);
                    // 设置药品发放id
                    medDispenseId.addAll(Arrays.stream(item.getDispenseIds().split(",")).map(String::trim) // 去除每个ID前后的空格
                        .filter(s -> !s.isEmpty()) // 过滤空字符串
                        .map(Long::parseLong) // 转换为Long类型
                        .toList());
                } else {
                    // 设置供应发放信息
                    supplyDelivery.setBasedOnTable(CommonConstants.TableName.WOR_DEVICE_DISPENSE);
                    // 设置耗材发放id
                    devDispenseId.addAll(Arrays.stream(item.getDispenseIds().split(",")).map(String::trim) // 去除每个ID前后的空格
                        .filter(s -> !s.isEmpty()) // 过滤空字符串
                        .map(Long::parseLong) // 转换为Long类型
                        .toList());
                }
                supplyDeliveryList.add(supplyDelivery);
            }
            // 供应申请更新
            boolean requestFlg = supplyRequestService.saveBatch(supplyRequestList);
            if (!requestFlg) {
                return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00010, null));
            }
            // 供应发放更新
            boolean deliveryFlg = supplyDeliveryService.saveBatch(supplyDeliveryList);
            if (!deliveryFlg) {
                return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00010, null));
            }
            // 药品发放状态更新
            medicationDispenseService.updateDispenseStatusSummarized(medDispenseId);
            // 耗材发放状态更新
            deviceDispenseService.updateDispenseStatusSummarized(devDispenseId);
        }

        return R.ok(MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null));
    }

    /**
     * 校验库存
     *
     * @param devDispenseId 耗材发放id
     * @param medDispenseId 药品发放id
     * @return 处理结果
     */
    @Override
    public R<?> checkInventoryItem(List<Long> devDispenseId, List<Long> medDispenseId) {

        List<InventoryItem> inventoryItemList = new ArrayList<>();
        // 获取库存信息
        List<InventoryDto> inventoryList = returnMedicineMapper.selectInventoryInfoList(devDispenseId, medDispenseId,
            CommonConstants.TableName.MED_MEDICATION_DEFINITION, CommonConstants.TableName.ADM_DEVICE_DEFINITION);
        // 按每个药品分组
        Map<Long, List<InventoryDto>> groupedByItemId =
            inventoryList.stream().collect(Collectors.groupingBy(InventoryDto::getItemId));
        // 遍历每个分组校验库存状态
        for (Map.Entry<Long, List<InventoryDto>> entry : groupedByItemId.entrySet()) {
            List<InventoryDto> groupItems = entry.getValue();
            if (groupItems.stream().map(InventoryDto::getInventoryStatusEnum)
                .allMatch(x -> x.equals(PublicationStatus.RETIRED.getValue()))) {
                // 库存停供校验
                return R.fail(groupItems.get(0).getItemName() + "库存已停供");
            }
        }
        if (!inventoryList.isEmpty()) {
            for (InventoryDto inventoryDto : inventoryList) {
                if (PublicationStatus.ACTIVE.getValue().equals(inventoryDto.getInventoryStatusEnum())) {
                    InventoryItem inventoryItem = new InventoryItem();
                    // 库存数量判定
                    if (inventoryDto.getDispenseUnit().equals(inventoryDto.getInventoryUnitCode())) {
                        // 当前库存数量(拆零单位)=当前库存数量(拆零单位)-请求数量
                        BigDecimal quantity = inventoryDto.getInventoryQuantity().subtract(inventoryDto.getQuantity());
                        // 库存数量判定
                        if (quantity.compareTo(BigDecimal.ZERO) < 0) {
                            // 库存数量不足
                            return R.fail(inventoryDto.getItemName() + "当前库存数量不足");
                        } else {
                            inventoryItem.setId(inventoryDto.getInventoryId()).setQuantity(quantity);
                        }
                    } else {
                        // 当前库存数量(拆零单位)=当前库存数量(拆零单位)-拆零数量（拆零比×请求数量）
                        BigDecimal quantity = inventoryDto.getInventoryQuantity()
                            .subtract(inventoryDto.getPartPercent().multiply(inventoryDto.getQuantity()));
                        // 库存数量判定
                        if (quantity.compareTo(BigDecimal.ZERO) < 0) {
                            // 库存数量不足
                            return R.fail(inventoryDto.getItemName() + "当前库存数量不足");
                        } else {
                            inventoryItem.setId(inventoryDto.getInventoryId()).setQuantity(quantity);
                        }
                    }
                    inventoryItemList.add(inventoryItem);
                }
            }
        }
        return R.ok(inventoryItemList);
    }

}
