package com.ruoyi.inventory.service.impl;

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

import com.ruoyi.common.annotation.SerialExecution;
import com.ruoyi.common.config.WarehouseConfig;
import com.ruoyi.common.core.domain.entity.Materials;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.inventory.domain.*;
import com.ruoyi.inventory.domain.vo.OutboundTemplateVO;
import com.ruoyi.inventory.mapper.InventoryMapper;
import com.ruoyi.inventory.mapper.OutboundOrderItemsMapper;
import com.ruoyi.inventory.mapper.OutboundOrderLogMapper;
import org.apache.commons.lang3.SystemUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ruoyi.common.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.inventory.mapper.OutboundOrdersMapper;
import com.ruoyi.inventory.service.IOutboundOrdersService;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.CollectionUtils;

/**
 * 出库单主Service业务层处理
 * 核心修正：
 * 1. 库存匹配Key统一为 仓库ID_物料ID_库位ID_库存类型
 * 2. 确保inventoryType完整参与匹配
 * 3. 库存扣减后≤0时强制设置inventory_status=0
 *
 * @author ruoyi
 * @date 2025-12-03
 */
@Service
public class OutboundOrdersServiceImpl implements IOutboundOrdersService
{
    @Autowired
    private OutboundOrdersMapper outboundOrdersMapper;

    @Autowired
    private OutboundOrderItemsMapper outboundOrderItemsMapper;
    @Autowired
    private OutboundOrderLogMapper outboundOrderLogMapper;

    @Autowired
    private OwnersServiceImpl ownersService;

    @Autowired
    private WarehousesServiceImpl warehousesService;
    @Autowired
    private InventoryServiceImpl inventoryService;
    @Autowired
    private MaterialsServiceImpl materialsService;
    @Autowired
    private StorageLocationsServiceImpl storageLocationsService;

    @Autowired
    private InventoryMapper inventoryMapper;

    /**
     * 查询出库单主
     *
     * @param id 出库单主主键
     * @return 出库单主
     */
    @Override
    public OutboundOrders selectOutboundOrdersById(String id)
    {
        return outboundOrdersMapper.selectOutboundOrdersById(id);
    }

    /**
     * 查询出库单主列表
     *
     * @param outboundOrders 出库单主
     * @return 出库单主
     */
    @Override
    public List<OutboundOrders> selectOutboundOrdersList(OutboundOrders outboundOrders)
    {
        List<OutboundOrders> outboundOrders1 = outboundOrdersMapper.selectOutboundOrdersList(outboundOrders);
        return outboundOrders1;
    }

    /**
     * 新增出库单主
     *
     * @param outboundOrders 出库单主
     * @return 结果
     */
    @Transactional
    @Override
    public int insertOutboundOrders(OutboundOrders outboundOrders)
    {
        outboundOrders.setCreateTime(DateUtils.getNowDate());
        outboundOrders.setCreateUserCode(SystemUtils.getUserName());
        outboundOrders.setId(UUID.randomUUID().toString());

        int rows = outboundOrdersMapper.insertOutboundOrders(outboundOrders);
        insertOutboundOrderItems(outboundOrders);
        return rows;
    }

    /**
     * 修改出库单主
     *
     * @param outboundOrders 出库单主
     * @return 结果
     */
    @Transactional
    @Override
    public int updateOutboundOrders(OutboundOrders outboundOrders)
    {
        outboundOrdersMapper.deleteOutboundOrderItemsByOrderId(outboundOrders.getId());
        outboundOrderLogMapper.deleteOutboundOrderLogByOrdersId(outboundOrders.getId());

        outboundOrders.setUpdateUserCode(SystemUtils.getUserName());
        outboundOrders.setUpdateTime(DateUtils.getNowDate());
        insertOutboundOrderItems(outboundOrders);
        return outboundOrdersMapper.updateOutboundOrders(outboundOrders);
    }

    /**
     * 批量删除出库单主
     *
     * @param ids 需要删除的出库单主主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteOutboundOrdersByIds(String[] ids)
    {
        outboundOrdersMapper.deleteOutboundOrderItemsByOrderIds(ids);
        outboundOrderLogMapper.deleteOutboundOrderLogByOrdersIds(ids);
        return outboundOrdersMapper.deleteOutboundOrdersByIds(ids);
    }

    /**
     * 删除出库单主信息
     *
     * @param id 出库单主主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteOutboundOrdersById(String id)
    {
        outboundOrdersMapper.deleteOutboundOrderItemsByOrderId(id);
        return outboundOrdersMapper.deleteOutboundOrdersById(id);
    }

    @SerialExecution(group = "inventoryRefresh", fair = true)
    @Override
    public int ship(OutboundOrders outboundOrders) {
        // 1. 查询当前出库单的所有明细
        OutboundOrderItems query = new OutboundOrderItems();
        query.setOutboundOrderId(outboundOrders.getId());
        query.setDivisor(null);
        List<OutboundOrderItems> outboundOrderItems = outboundOrderItemsMapper.selectOutboundOrderItemsList(query);

        // 2. 更新明细和订单状态
        OutboundOrderLog outboundOrderLog = new OutboundOrderLog();
        String updateUser = SystemUtils.getUserName();
        Date updateTime = DateUtils.getNowDate();
        for (OutboundOrderItems item : outboundOrderItems) {
            item.setItemStatus(3L);
            item.setUpdateBy(updateUser);
            item.setUpdateTime(updateTime);
            outboundOrderItemsMapper.updateOutboundOrderItems(item);

            outboundOrderLog.setId(item.getId());
            outboundOrderLog.setItemStatus(item.getItemStatus());
            outboundOrderLogMapper.updateOutboundOrderLog(outboundOrderLog);
        }

        outboundOrders.setOrderStatus(2L);
        outboundOrders.setUpdateTime(updateTime);
        outboundOrders.setUpdateUserCode(updateUser);
        outboundOrdersMapper.updateOutboundOrders(outboundOrders);

        // 3. 执行库存扣减（包含inventoryType匹配 + 0值状态更新）
        this.deductInventory(outboundOrderItems, updateUser, updateTime);

        return 1;
    }

    /**
     * 核心库存扣减逻辑
     * 1. 按 仓库ID_物料ID_库位ID_库存类型 匹配库存
     * 2. 扣减后数量≤0时设置inventory_status=0
     * @param outboundOrderItems 出库明细
     * @param updateUser 操作人
     * @param updateTime 操作时间
     */
    private void deductInventory(List<OutboundOrderItems> outboundOrderItems, String updateUser, Date updateTime) {
        if (CollectionUtils.isEmpty(outboundOrderItems)) {
            return;
        }

        // 1. 预加载库存映射：Key=仓库ID_物料ID_库位ID_库存类型  Value=库存对象
        Map<String, Inventory> inventoryMap = this.loadInventoryMap();
        // 2. 构建扣减数量Map：Key=仓库ID_物料ID_库位ID_库存类型  Value=总扣减数量
        Map<String, Long> deductQtyMap = this.buildDeductQtyMap(outboundOrderItems);

        // 3. 遍历扣减Map，执行扣减+状态更新
        List<Inventory> needUpdateList = new ArrayList<>();
        for (Map.Entry<String, Long> entry : deductQtyMap.entrySet()) {
            String key = entry.getKey();
            Long deductQty = entry.getValue();

            // 匹配库存
            Inventory inventory = inventoryMap.get(key);
            if (inventory == null) {
                String[] keyParts = key.split("_");
                String warehouseId = keyParts.length > 0 ? keyParts[0] : "";
                String materialId = keyParts.length > 1 ? keyParts[1] : "";
                String locationId = keyParts.length > 2 ? keyParts[2] : "";
                String inventoryType = keyParts.length > 3 ? keyParts[3] : "";
                throw new ServiceException(String.format(
                        "仓库[%s]物料[%s]库位[%s]库存类型[%s]的库存不存在，无法扣减",
                        warehouseId, materialId, locationId, inventoryType));
            }

            // 执行数量扣减
            Long currentQty = Optional.ofNullable(inventory.getQuantity()).orElse(0L);
            Long newQty = currentQty - deductQty;
            inventory.setQuantity(newQty);

            // 核心规则：扣减后数量≤0 → 状态置0
            if (newQty <= 0) {
                inventory.setInventoryStatus(0L);
            }

            // 补充审计字段
            inventory.setUpdateBy(updateUser);
            inventory.setUpdateTime(updateTime);

            needUpdateList.add(inventory);
        }

        // 4. 批量更新库存
        if (!needUpdateList.isEmpty()) {
            inventoryMapper.batchUpdateInventory(needUpdateList);
            // 刷新库存缓存
            List<String> inventoryIds = needUpdateList.stream()
                    .map(Inventory::getId)
                    .distinct()
                    .collect(Collectors.toList());
            inventoryService.RefreshInventory(inventoryIds);
        }
    }

    /**
     * 预加载库存Map
     * Key规则：仓库ID_物料ID_库位ID_库存类型
     */
    private Map<String, Inventory> loadInventoryMap() {
        Inventory query = new Inventory();
        query.setInventoryStatus(1L);
        query.setIsUsed(1L);
        List<Inventory> inventoryList = inventoryService.selectInventoryList(query);

        if (CollectionUtils.isEmpty(inventoryList)) {
            return Collections.emptyMap();
        }

        Map<String, Inventory> inventoryMap = new HashMap<>();
        for (Inventory inv : inventoryList) {
            String key = String.join("_",
                    Optional.ofNullable(inv.getWarehousesId()).orElse(""),
                    Optional.ofNullable(inv.getMaterialId()).orElse(""),
                    Optional.ofNullable(inv.getLocationId()).orElse(""),
                    Optional.ofNullable(inv.getInventoryType()).map(String::valueOf).orElse("")
            );
            // 重复key保留第一个（避免覆盖）
            if (!inventoryMap.containsKey(key)) {
                inventoryMap.put(key, inv);
            }
        }
        return inventoryMap;
    }

    /**
     * 构建扣减数量Map
     * Key规则：仓库ID_物料ID_库位ID_库存类型（和库存Map完全对齐）
     */
    private Map<String, Long> buildDeductQtyMap(List<OutboundOrderItems> items) {
        Map<String, Long> deductQtyMap = new HashMap<>();
        for (OutboundOrderItems item : items) {
            String key = String.join("_",
                    Optional.ofNullable(item.getWarehouseId()).orElse(""),
                    Optional.ofNullable(item.getMaterialId()).orElse(""),
                    Optional.ofNullable(item.getLocationId()).orElse(""),
                    Optional.ofNullable(item.getInventoryType()).map(String::valueOf).orElse("")
            );
            // 累加扣减数量
            Long qty = Optional.ofNullable(item.getActualQuantity()).orElse(0L);
            deductQtyMap.put(key, deductQtyMap.getOrDefault(key, 0L) + qty);
        }
        return deductQtyMap;
    }

    @Override
    public List<Map<String,String>> outboundOrdersTopTenByQuantity() {
        return outboundOrdersMapper.SelectOutboundOrdersMaterialsTopTenByQuantity();
    }

    @Override
    public List<Map<String, String>> outboundOrdersTopTenByAmount() {
        return outboundOrdersMapper.SelectOutboundOrdersMaterialsTopTenByAmount();
    }

    @Override
    public String outboundOrdersCount() {
        return outboundOrdersMapper.outboundOrdersCount();
    }

    /**
     * 新增出库单明细信息
     *
     * @param outboundOrders 出库单主对象
     */
    public void insertOutboundOrderItems(OutboundOrders outboundOrders) {
        List<OutboundOrderItems> outboundOrderItemsList = outboundOrders.getOutboundOrderItemsList();
        String id = outboundOrders.getId();
        if (CollectionUtils.isEmpty(outboundOrderItemsList)) {
            return;
        }

        // 库存校验：失败时抛异常
        boolean isValid = inventoryService.inventoryLockValidation(outboundOrderItemsList);
        if (!isValid) {
            throw new RuntimeException("库存被修改请重新确认");
        }

        // 为明细设置订单ID和主键ID
        for (OutboundOrderItems items : outboundOrderItemsList) {
            items.setOutboundOrderId(id);
            items.setOrderId(outboundOrders.getOrderId());
            items.setId(UUID.randomUUID().toString().replace("-", ""));
        }

        // 批量插入出库单明细
        outboundOrdersMapper.batchOutboundOrderItems(outboundOrderItemsList);

        // 拷贝明细到日志列表
        List<String> inventoryIds = new ArrayList<>();
        List<OutboundOrderLog> outboundOrderLogs = new ArrayList<>();
        for (OutboundOrderItems items : outboundOrderItemsList) {
            OutboundOrderLog log = new OutboundOrderLog();
            BeanUtils.copyProperties(items, log);
            log.setOrderId(items.getOutboundOrderId());
            outboundOrderLogs.add(log);
            inventoryIds.add(log.getInventoryId());
        }

        // 插入日志 + 刷新库存
        if (!outboundOrderLogs.isEmpty()) {
            outboundOrderLogMapper.batchOutboundOrderLog(outboundOrderLogs);
        }
        if (!inventoryIds.isEmpty()) {
            inventoryService.RefreshInventory(inventoryIds);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String importOutboundOrders(List<OutboundTemplateVO> inboundOrdersList, Boolean isUpdateSupport, String operName, Integer orderType) {
        // 1. 基础空值校验
        if (CollectionUtils.isEmpty(inboundOrdersList)) {
            throw new ServiceException("导入数据不能为空！");
        }

        // 2. 初始化变量
        int totalMainSuccess = 0;
        int totalMainFailure = 0;
        int totalItemSuccess = 0;
        int totalItemFailure = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        Date now = DateUtils.getNowDate();
        Long userId = SecurityUtils.getUserId();
        String operId = userId != null ? userId.toString() : "system";

        Map<String, OutboundOrders> validMainMap = new HashMap<>();
        Map<String, List<OutboundOrderItems>> validItemMap = new HashMap<>();
        boolean hasValidateError = false;

        // 3. 预加载映射缓存
        Map<String, String> sapToMaterialIdMap = loadSapToMaterialIdMap();
        Map<String, String> locationNameToIdMap = loadLocationNameToIdMap();
        Map<String, String> warehouseNameToIdMap = loadWarehouseNameToIdMap();
        Map<String, String> ownerNameToIdMap = loadOwnerNameToIdMap();
        Map<String, AbstractMap.SimpleEntry<String, Long>> inventoryTOIdMap = loadInventoryTOIdMap();

        // 4. 按入库单号分组
        Map<String, List<OutboundTemplateVO>> orderGroupMap = inboundOrdersList.stream()
                .filter(vo -> StringUtils.isNotBlank(vo.getOrderId()))
                .collect(Collectors.groupingBy(OutboundTemplateVO::getOrderId));

        // 5. 数据验证
        for (Map.Entry<String, List<OutboundTemplateVO>> entry : orderGroupMap.entrySet()) {
            String orderId = entry.getKey();
            List<OutboundTemplateVO> voList = entry.getValue();
            OutboundOrders mainDO = null;
            List<OutboundOrderItems> itemDOList = new ArrayList<>();

            try {
                OutboundTemplateVO firstVO = voList.get(0);
                // 检查出库单是否已存在
                OutboundOrders outboundOrdersQuery = new OutboundOrders();
                outboundOrdersQuery.setOrderId(orderId);
                List<OutboundOrders> existMains = outboundOrdersMapper.selectOutboundOrdersList(outboundOrdersQuery);

                if (existMains != null && existMains.size() > 1) {
                    throw new ServiceException(String.format("入库单号【%s】存在多条重复主表数据", orderId));
                }

                OutboundOrders existMain = CollectionUtils.isEmpty(existMains) ? null : existMains.get(0);
                if (existMain != null) {
                    if (!Boolean.TRUE.equals(isUpdateSupport)) {
                        throw new ServiceException(String.format("入库单号【%s】已存在，且不支持更新", orderId));
                    }
                    mainDO = existMain;
                    BeanUtils.copyProperties(firstVO, mainDO, "id", "createBy", "createTime");
                    mainDO.setUpdateBy(operId);
                    mainDO.setWarehouseId(WarehouseConfig.DEFAULT_WAREHOUSE_ID);
                    mainDO.setUpdateTime(now);
                    mainDO.setUpdateUserCode(operId);
                } else {
                    mainDO = new OutboundOrders();
                    BeanUtils.copyProperties(firstVO, mainDO,
                            "sapNo", "materialName", "plannedQuantity", "actualQuantity",
                            "plannedPackages", "materialUnit", "materialRemark");

                    // 货主校验
                    String ownerName = firstVO.getOwnerName();
                    String ownerId = firstVO.getOwnerId();
                    if (StringUtils.isNotBlank(ownerName)) {
                        String mappedOwnerId = ownerNameToIdMap.get(ownerName.trim());
                        if (StringUtils.isBlank(mappedOwnerId)) {
                            throw new ServiceException(String.format("业主【%s】不存在，无法新增入库单【%s】",
                                    ownerName, orderId));
                        }
                        if (ownerId != null && !ownerId.equals(mappedOwnerId)) {
                            throw new ServiceException(String.format("入库单号【%s】的业主ID【%s】与业主名称【%s】不匹配",
                                    orderId, ownerId, ownerName));
                        }
                        mainDO.setOwnerId(mappedOwnerId);
                    } else if (ownerId != null) {
                        Owners ownerById = ownersService.selectOwnersById(ownerId);
                        if (ownerById == null) {
                            throw new ServiceException(String.format("入库单号【%s】的业主ID【%s】不存在",
                                    orderId, ownerId));
                        }
                        mainDO.setOwnerId(ownerId);
                    } else {
                        throw new ServiceException(String.format("入库单号【%s】的业主名称/ID不能为空", orderId));
                    }

                    // 填充主表必填字段
                    mainDO.setId(UUID.randomUUID().toString());
                    mainDO.setOrderId(orderId);
                    mainDO.setOrderStatus(2L);
                    mainDO.setCreateBy(operId);
                    mainDO.setCreateTime(now);
                    mainDO.setOrderTypeId(String.valueOf(orderType));
                    mainDO.setCreateUserCode(operId);
                    mainDO.setUpdateBy(operId);
                    mainDO.setUpdateTime(now);
                    mainDO.setUpdateUserCode(operId);
                    mainDO.setSortNo(Optional.ofNullable(mainDO.getSortNo()).orElse(0L));
                }

                // 明细校验
                for (int i = 0; i < voList.size(); i++) {
                    OutboundTemplateVO vo = voList.get(i);
                    int lineNo = i + 1;
                    OutboundOrderItems itemDO = new OutboundOrderItems();

                    BeanUtils.copyProperties(vo, itemDO,
                            "orderId", "systemNo", "orderTypeId", "batchId");

                    // 填充明细必填字段
                    itemDO.setId(UUID.randomUUID().toString());
                    itemDO.setOrderId(orderId);
                    itemDO.setBatchCode(Optional.ofNullable(mainDO.getBatchCode()).orElse(""));
                    itemDO.setOutboundOrderId(mainDO.getId());
                    itemDO.setCreateBy(operId);
                    itemDO.setCreateTime(now);
                    itemDO.setCreateUserCode(operId);
                    itemDO.setSortNo(0L);

                    // 物料SAP校验
                    String sapNo = vo.getSapNo() != null ? vo.getSapNo().trim() : "";
                    if (StringUtils.isBlank(sapNo)) {
                        throw new ServiceException(String.format("入库单号【%s】第%d条明细的物料SAP号不能为空",
                                orderId, lineNo));
                    }
                    String materialId = sapToMaterialIdMap.get(sapNo);
                    if (StringUtils.isBlank(materialId)) {
                        throw new ServiceException(String.format("入库单号【%s】第%d条明细的SAP号【%s】对应的物料不存在",
                                orderId, lineNo, sapNo));
                    }
                    itemDO.setMaterialId(materialId);

                    // 库位校验
                    String locationName = vo.getLocationName() != null ? vo.getLocationName().trim() : "";
                    if (StringUtils.isBlank(locationName)) {
                        throw new ServiceException(String.format("入库单号【%s】第%d条明细的库位名称不能为空",
                                orderId, lineNo));
                    }
                    String locationId = locationNameToIdMap.get(locationName);
                    if (StringUtils.isBlank(locationId)) {
                        throw new ServiceException(String.format("入库单号【%s】第%d条明细的库位【%s】不存在",
                                orderId, lineNo, locationName));
                    }
                    itemDO.setLocationId(locationId);

                    // 仓库校验
                    String warehouseName = vo.getWarehouseName() != null ? vo.getWarehouseName().trim() : "";
                    String warehouseId = warehouseNameToIdMap.get(warehouseName);
                    if (StringUtils.isBlank(warehouseId)) {
                        throw new ServiceException(String.format("系统未配置仓库【%s】，无法导入入库单号【%s】的第%d条明细",
                                warehouseName, orderId, lineNo));
                    }
                    itemDO.setWarehouseId(warehouseId);

                    // 库存校验（包含inventoryType）
                    String inventoryTypeStr = Optional.ofNullable(orderType).map(String::valueOf).orElse("");
                    String inventoryMatchKey = String.join("_", warehouseId, materialId, locationId, inventoryTypeStr);
                    AbstractMap.SimpleEntry<String, Long> inventoryEntry = inventoryTOIdMap.get(inventoryMatchKey);
                    if (inventoryEntry == null) {
                        throw new ServiceException(String.format(
                                "入库单号【%s】第%d条明细：仓库【%s】+物料【%s】+库位【%s】+库存类型【%s】组合的库存记录不存在",
                                orderId, lineNo, vo.getWarehouseName(), vo.getMaterialName(), vo.getLocationName(), inventoryTypeStr));
                    }
                    itemDO.setInventoryId(inventoryEntry.getKey());
                    itemDO.setInventoryType(inventoryTypeStr); // 填充库存类型
                    itemDO.setItemStatus(3L);
                    itemDOList.add(itemDO);
                }

                validMainMap.put(orderId, mainDO);
                validItemMap.put(orderId, itemDOList);

            } catch (Exception e) {
                hasValidateError = true;
                totalMainFailure++;
                totalItemFailure += voList.size();
                failureMsg.append(String.format("入库单号【%s】验证失败：%s；\n", orderId, e.getMessage()));
            }
        }

        // 6. 有验证失败直接抛异常
        if (hasValidateError) {
            throw new ServiceException(String.format("验证失败，导入终止！失败详情：%s", failureMsg.toString()));
        }

        // 7. 执行入库/更新操作
        for (Map.Entry<String, OutboundOrders> entry : validMainMap.entrySet()) {
            String orderId = entry.getKey();
            OutboundOrders mainDO = entry.getValue();
            List<OutboundOrderItems> itemDOList = validItemMap.get(orderId);

                outboundOrdersMapper.insertOutboundOrders(mainDO);
                totalMainSuccess++;
                successMsg.append(String.format("入库单号【%s】已新增；\n", orderId));


            if (!CollectionUtils.isEmpty(itemDOList)) {
                int itemSuccess = outboundOrderItemsMapper.batchInsertOutboundOrderItems(itemDOList);
                totalItemSuccess += itemSuccess;
                int itemFail = itemDOList.size() - itemSuccess;
                totalItemFailure += itemFail;

                successMsg.append(String.format("入库单号【%s】成功导入%d条物料明细；\n", orderId, itemSuccess));
                if (itemFail > 0) {
                    failureMsg.append(String.format("入库单号【%s】有%d条物料明细导入失败；\n", orderId, itemFail));
                }
            }
        }

        // 8. 事务提交后执行库存扣减
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            Map<String, List<OutboundOrderItems>> finalValidItemMap = new HashMap<>(validItemMap);
            String finalOperId = operId;
            Date finalNow = now;

            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    for (List<OutboundOrderItems> itemList : finalValidItemMap.values()) {
                        deductInventory(itemList, finalOperId, finalNow);
                    }
                }
            });
        } else {
            for (List<OutboundOrderItems> itemList : validItemMap.values()) {
                deductInventory(itemList, operId, now);
            }
        }

        // 9. 结果汇总
        if (totalMainFailure > 0 || totalItemFailure > 0) {
            String finalFailureMsg = String.format(
                    "导入结果：成功新增/更新%d个入库单，失败%d个；成功导入%d条明细，失败%d条。失败详情：%s",
                    totalMainSuccess, totalMainFailure, totalItemSuccess, totalItemFailure, failureMsg.toString()
            );
            throw new ServiceException(finalFailureMsg);
        } else {
            String finalSuccessMsg = String.format(
                    "恭喜您，数据已全部导入成功！共处理%d个入库单，成功导入%d条物料明细。详情：%s",
                    totalMainSuccess, totalItemSuccess, successMsg.toString()
            );
            return finalSuccessMsg;
        }
    }

    // ========== 预加载映射辅助方法 ==========
    private Map<String, String> loadSapToMaterialIdMap() {
        List<Materials> materialsList = materialsService.selectMaterialsList(new Materials());
        if (CollectionUtils.isEmpty(materialsList)) {
            return Collections.emptyMap();
        }
        return materialsList.stream()
                .filter(m -> StringUtils.isNotBlank(m.getSapNo()))
                .collect(Collectors.toMap(
                        m -> m.getSapNo().trim(),
                        Materials::getId,
                        (k1, k2) -> k1
                ));
    }

    private Map<String, String> loadLocationNameToIdMap() {
        StorageLocations query = new StorageLocations();
        query.setIsUsed(1L);
        List<StorageLocations> locationList = storageLocationsService.selectStorageLocationsList(query);
        if (CollectionUtils.isEmpty(locationList)) {
            return Collections.emptyMap();
        }
        return locationList.stream()
                .filter(l -> StringUtils.isNotBlank(l.getLocationCode()))
                .collect(Collectors.toMap(
                        l -> l.getLocationCode().trim(),
                        StorageLocations::getId,
                        (k1, k2) -> k1
                ));
    }

    private Map<String, String> loadWarehouseNameToIdMap() {
        Warehouses query = new Warehouses();
        query.setIsUsed(1L);
        List<Warehouses> warehouseList = warehousesService.selectWarehousesList(query);
        if (CollectionUtils.isEmpty(warehouseList)) {
            return Collections.emptyMap();
        }
        return warehouseList.stream()
                .filter(w -> StringUtils.isNotBlank(w.getWarehousesName()))
                .collect(Collectors.toMap(
                        w -> w.getWarehousesName().trim(),
                        Warehouses::getId,
                        (k1, k2) -> k1
                ));
    }

    private Map<String, String> loadOwnerNameToIdMap() {
        List<Owners> ownerList = ownersService.selectOwnersList(new Owners());
        if (CollectionUtils.isEmpty(ownerList)) {
            return Collections.emptyMap();
        }
        return ownerList.stream()
                .filter(o -> StringUtils.isNotBlank(o.getOwnerName()))
                .collect(Collectors.toMap(
                        o -> o.getOwnerName().trim(),
                        Owners::getId,
                        (k1, k2) -> k1
                ));
    }

    private Map<String, AbstractMap.SimpleEntry<String, Long>> loadInventoryTOIdMap() {
        Inventory inventory = new Inventory();
        inventory.setInventoryStatus(1L);
        inventory.setIsUsed(1L);
        List<Inventory> inventoryList = inventoryService.selectInventoryList(inventory);

        if (CollectionUtils.isEmpty(inventoryList)) {
            return Collections.emptyMap();
        }

        Map<String, AbstractMap.SimpleEntry<String, Long>> emptyLocationMap = inventoryList.stream()
                .filter(inv -> StringUtils.isNotBlank(inv.getWarehousesId())
                        && StringUtils.isNotBlank(inv.getMaterialId())
                        && inv.getInventoryType() != null
                        && StringUtils.isNotBlank(inv.getId())
                        && StringUtils.isBlank(inv.getLocationId()))
                .collect(Collectors.toMap(
                        inv -> String.join("_",
                                inv.getWarehousesId().trim(),
                                inv.getMaterialId().trim(),
                                "", inv.getInventoryType().toString()),
                        inv -> new AbstractMap.SimpleEntry<>(inv.getId().trim(), Optional.ofNullable(inv.getQuantity()).orElse(0L)),
                        (k1, k2) -> k1,
                        HashMap::new
                ));

        Map<String, AbstractMap.SimpleEntry<String, Long>> nonEmptyLocationMap = inventoryList.stream()
                .filter(inv -> StringUtils.isNotBlank(inv.getWarehousesId())
                        && StringUtils.isNotBlank(inv.getMaterialId())
                        && StringUtils.isNotBlank(inv.getLocationId())
                        && StringUtils.isNotBlank(inv.getId())
                        && inv.getInventoryType() != null)
                .collect(Collectors.toMap(
                        inv -> String.join("_",
                                inv.getWarehousesId().trim(),
                                inv.getMaterialId().trim(),
                                inv.getLocationId().trim(),
                                inv.getInventoryType().toString()),
                        inv -> new AbstractMap.SimpleEntry<>(inv.getId().trim(), Optional.ofNullable(inv.getQuantity()).orElse(0L)),
                        (k1, k2) -> k1,
                        HashMap::new
                ));

        emptyLocationMap.putAll(nonEmptyLocationMap);
        return emptyLocationMap;
    }
}