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.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.*;
import com.openhis.common.constant.CommonConstants;
import com.openhis.common.constant.PromptMsgConstant;
import com.openhis.common.enums.*;
import com.openhis.common.utils.EnumUtils;
import com.openhis.common.utils.HisQueryUtils;
import com.openhis.medication.domain.MedicationDefinition;
import com.openhis.medication.domain.MedicationDispense;
import com.openhis.medication.service.IMedicationDefinitionService;
import com.openhis.medication.service.IMedicationDispenseService;
import com.openhis.web.inhospitalnursestation.appservice.IMedicineSummaryAppService;
import com.openhis.web.inhospitalnursestation.dto.DispenseFormSearchParam;
import com.openhis.web.inhospitalnursestation.dto.MedicineDispenseFormDto;
import com.openhis.web.inhospitalnursestation.dto.MedicineSummaryFormDto;
import com.openhis.web.inhospitalnursestation.dto.MedicineSummaryParam;
import com.openhis.web.inhospitalnursestation.mapper.MedicineSummaryAppMapper;
import com.openhis.web.pharmacymanage.dto.UnDispenseInventoryDto;
import com.openhis.web.pharmacymanage.mapper.ReturnMedicineMapper;
import com.openhis.workflow.domain.InventoryItem;
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;

    @Resource
    private IMedicationDispenseService medicationDispenseService;

    @Resource
    private MedicineSummaryAppMapper medicineSummaryAppMapper;

    @Resource
    private ISupplyRequestService supplyRequestService;

    @Resource
    private ISupplyDeliveryService supplyDeliveryService;

    @Resource
    private IMedicationDefinitionService medicationDefinitionService;

    @Resource
    private ReturnMedicineMapper returnMedicineMapper;

    /**
     * 查询发药单信息
     *
     * @param dispenseFormSearchParam 查询条件
     * @param pageNo 当前页码
     * @param pageSize 查询条数
     * @param request 请求
     * @return 发药单信息
     */
    @Override
    public R<?> getMedicineDispenseFormPage(DispenseFormSearchParam dispenseFormSearchParam, Integer pageNo,
        Integer pageSize, HttpServletRequest request) {
        // 初始化查询参数
        String encounterIds = dispenseFormSearchParam.getEncounterIds();
        dispenseFormSearchParam.setEncounterIds(null);
        // 构建查询条件
        QueryWrapper<DispenseFormSearchParam> queryWrapper =
            HisQueryUtils.buildQueryWrapper(dispenseFormSearchParam, null, null, request);

        // 手动拼接住院患者id条件
        if (encounterIds != null && !encounterIds.isEmpty()) {
            List<Long> encounterIdList =
                Arrays.stream(encounterIds.split(CommonConstants.Common.COMMA)).map(Long::parseLong).toList();
            queryWrapper.in(CommonConstants.FieldName.EncounterId, encounterIdList);
        }
        // 领药信息列表
        Page<MedicineDispenseFormDto> medicineDispenseFormPage =
            medicineSummaryAppMapper.selectMedicineDispenseFormPage(new Page<>(pageNo, pageSize), queryWrapper,
                RequestStatus.COMPLETED.getValue(), EncounterActivityStatus.ACTIVE.getValue(),
                LocationForm.BED.getValue(), ParticipantType.ADMITTING_DOCTOR.getCode(),
                AccountType.PERSONAL_CASH_ACCOUNT.getCode(), ChargeItemStatus.BILLABLE.getValue(),
                ChargeItemStatus.BILLED.getValue(), ChargeItemStatus.REFUNDED.getValue(),
                DispenseStatus.SUMMARIZED.getValue());
        medicineDispenseFormPage.getRecords().forEach(e -> {
            // 是否皮试
            e.setSkinTestFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getSkinTestFlag()));
            // 是否为注射药物
            e.setInjectFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getInjectFlag()));
            // 医嘱类型
            e.setTherapyEnum_enumText(EnumUtils.getInfoByValue(TherapyTimeType.class, e.getTherapyEnum()));
            // 性别枚举
            e.setGenderEnum_enumText(EnumUtils.getInfoByValue(AdministrativeGender.class, e.getGenderEnum()));
            // 计算年龄
            if (e.getBirthDate() != null) {
                e.setAge(AgeCalculatorUtil.getAge(e.getBirthDate()));
            }
        });
        return R.ok(medicineDispenseFormPage);
    }

    /**
     * 查询药品汇总单
     *
     * @param dispenseFormSearchParam 查询条件
     * @param pageNo 当前页码
     * @param pageSize 查询条数
     * @param searchKey 模糊查询关键字
     * @param request 请求
     * @return 药品汇总单
     */
    @Override
    public R<?> getMedicineSummaryFormPage(DispenseFormSearchParam dispenseFormSearchParam, Integer pageNo,
        Integer pageSize, String searchKey, HttpServletRequest request) {
        // 构建查询条件
        QueryWrapper<DispenseFormSearchParam> queryWrapper = HisQueryUtils.buildQueryWrapper(dispenseFormSearchParam,
            searchKey, new HashSet<>(List.of(CommonConstants.FieldName.BusNo)), request);

        // 汇总单分页列表
        Page<MedicineSummaryFormDto> medicineSummaryFormPage = medicineSummaryAppMapper.selectMedicineSummaryFormPage(
            new Page<>(pageNo, pageSize), queryWrapper, DispenseStatus.COMPLETED.getValue(),
            DispenseStatus.IN_PROGRESS.getValue(), SupplyType.SUMMARY_DISPENSE.getValue());
        medicineSummaryFormPage.getRecords().forEach(e -> {
            // 发药状态
            e.setStatusEnum_enumText(EnumUtils.getInfoByValue(DispenseStatus.class, e.getStatusEnum()));
        });
        return R.ok(medicineSummaryFormPage);
    }

    /**
     * 查询药品汇总单详情
     *
     * @param summaryNo 汇总单号
     * @return 药品汇总单详情
     */
    @Override
    public R<?> getMedicineSummaryFormDetail(String summaryNo) {
        // 药品汇总单详情
        return R.ok(medicineSummaryAppMapper.selectMedicineSummaryFormDetail(summaryNo));
    }

    /**
     * 生成汇总发药单
     *
     * @param medicineSummaryParamList 汇总发药申请参数
     * @return 处理结果
     */
    @Override
    public R<?> medicineSummary(List<MedicineSummaryParam> medicineSummaryParamList) {
        // 领药人
        Long receiverId = medicineSummaryParamList.get(0).getReceiverId();
        // 申请时间
        Date now = DateUtils.getNowDate();
        // 申请人
        Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
        // 药品发放id
        List<Long> medDispenseIdList =
            medicineSummaryParamList.stream().map(MedicineSummaryParam::getDispenseId).toList();
        // 药品发放信息列表
        List<MedicationDispense> medicationDispenseList = medicationDispenseService.listByIds(medDispenseIdList);
        if (medicationDispenseList == null || medicationDispenseList.isEmpty()) {
            throw new ServiceException("未找到药品发放信息");
        }
        if (medicationDispenseList.stream().map(MedicationDispense::getStatusEnum)
            .anyMatch(x -> x.equals(DispenseStatus.SUMMARIZED.getValue()))) {
            throw new ServiceException("药品已汇总，请勿重复汇总");
        }
        // 查询药品信息
        List<MedicationDefinition> medicationDefinitions = medicationDefinitionService
            .listByIds(medicationDispenseList.stream().map(MedicationDispense::getMedicationId).toList());
        // 根据发放药房分组
        Map<Long, List<MedicationDispense>> medicationLocationMap =
            medicationDispenseList.stream().collect(Collectors.groupingBy(MedicationDispense::getLocationId));
        // 循环每个药房
        for (Map.Entry<Long, List<MedicationDispense>> entry : medicationLocationMap.entrySet()) {
            // 汇总单据号
            String busNo = assignSeqUtil.getSeqByDay(AssignSeqEnum.MEDICINE_SUMMARY_NO.getPrefix(), 4);

            List<MedicationDispense> medicationDispenses = entry.getValue();
            // 根据相同批号的同一药品进行汇总
            Map<String, List<MedicationDispense>> medicationSummaryInfoMap = medicationDispenses.stream().collect(
                Collectors.groupingBy(x -> x.getMedicationId() + CommonConstants.Common.DASH + x.getLotNumber()));
            for (Map.Entry<String, List<MedicationDispense>> medicationSummaryInfoList : medicationSummaryInfoMap
                .entrySet()) {
                List<MedicationDispense> medicationSummaryList = medicationSummaryInfoList.getValue();
                MedicationDispense medicationDispense = medicationSummaryList.get(0);
                Long medicationId = medicationDispense.getMedicationId();
                Long locationId = medicationDispense.getLocationId();
                String lotNumber = medicationDispense.getLotNumber();
                Long patientId = medicationDispense.getPatientId();
                // 拆零比例
                BigDecimal partPercent = BigDecimal.ONE;
                // 最小单位
                String minUnitCode = null;
                // 单位
                String unitCode = null;
                // 根据药品id获取对应的药品信息
                Optional<MedicationDefinition> medicationDefinition =
                    medicationDefinitions.stream().filter(x -> x.getId().equals(medicationId)).findFirst();
                if (medicationDefinition.isPresent()) {
                    partPercent = medicationDefinition.get().getPartPercent();
                    minUnitCode = medicationDefinition.get().getMinUnitCode();
                    unitCode = medicationDefinition.get().getUnitCode();
                }
                if (minUnitCode == null || unitCode == null || partPercent == null) {
                    throw new ServiceException("药品信息有误,请联系管理员");
                }
                // 最小单位数量
                BigDecimal minQuantity = BigDecimal.ZERO;
                for (MedicationDispense medicationSummaryInfo : medicationSummaryList) {
                    BigDecimal quantity = medicationSummaryInfo.getQuantity();
                    if (unitCode.equals(medicationDispense.getUnitCode())) {
                        // 转换为小单位进行累加
                        quantity = medicationSummaryInfo.getQuantity().multiply(partPercent);
                    }
                    minQuantity = minQuantity.add(quantity);
                }
                Long supplyRequestId = supplyRequestService.createSummarySupplyRequest(medicationId, locationId,
                    lotNumber, patientId, minQuantity, minUnitCode, practitionerId, now, busNo);
                supplyDeliveryService.createSummarySupplyDelivery(medicationId, lotNumber, patientId, minQuantity,
                    minUnitCode, receiverId, supplyRequestId);
            }
            // 药品发放状态更新
            medicationDispenseService.updateDispenseStatusSummarized(
                medicationDispenses.stream().map(MedicationDispense::getId).toList(), busNo);
        }
        return R.ok(MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[] {"汇总申请"}));
    }

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

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

    /**
     * 取消汇总
     *
     * @param summaryNo 汇总单号
     * @return 处理结果
     */
    @Override
    public R<?> cancelSummary(String summaryNo) {
        // 取消汇总申请（软删除）
        List<Long> requestIdList = supplyRequestService.cancelSummarySupplyRequest(List.of(summaryNo));
        if (requestIdList.isEmpty()) {
            return R.fail("取消汇总申请失败");
        }
        // 软删除汇总发放
        supplyDeliveryService.deleteSupplyDeliveryByReqId(requestIdList);
        // 取消药品汇总
        boolean result = medicationDispenseService.cancelMedicationSummary(List.of(summaryNo));
        if (!result) {
            return R.fail("取消汇总申请失败");
        }
        return R.ok(MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[] {"取消"}));
    }

}
