package com.ruoyi.inventory.service.impl;

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

import com.ruoyi.common.annotation.SerialExecution;
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业务层处理
 *
 * @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;
    /**
     * 查询出库单主
     *
     * @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) {
        OutboundOrderItems outboundOrderItems1 = new OutboundOrderItems();
        outboundOrderItems1.setOutboundOrderId(outboundOrders.getId());
        outboundOrderItems1.setDivisor(null);
        List<OutboundOrderItems> outboundOrderItems = outboundOrderItemsMapper.selectOutboundOrderItemsList(outboundOrderItems1);
        List<OutboundOrderItems> outboundOrderItems2 = outboundOrderItems;
        OutboundOrderLog outboundOrderLog = new OutboundOrderLog();

        for (OutboundOrderItems outboundOrderItem : outboundOrderItems) {

            outboundOrderItem.setItemStatus(3l);
            outboundOrderItemsMapper.updateOutboundOrderItems(outboundOrderItem);

            outboundOrderLog.setId(outboundOrderItem.getId());
            outboundOrderLog.setItemStatus(outboundOrderItem.getItemStatus());
            outboundOrderLogMapper.updateOutboundOrderLog(outboundOrderLog);

        }


        outboundOrders.setId(outboundOrders.getId());
        outboundOrders.setOrderStatus(2l);
        outboundOrders.setUpdateTime(DateUtils.getNowDate());
        outboundOrders.setUpdateUserCode(SystemUtils.getUserName());
        outboundOrdersMapper.updateOutboundOrders(outboundOrders);

        inventoryService.ship(outboundOrderItems2);
        return 1;
    }

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

    @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();
        // 1. 先做空列表校验（提前返回，避免无效逻辑）
        if (outboundOrderItemsList == null || outboundOrderItemsList.isEmpty()) {
            return;
        }

        // 2. 库存校验：失败时抛异常（核心修正：! 取反 + 异常抛出后代码立即终止）
        boolean isValid = inventoryService.inventoryLockValidation(outboundOrderItemsList);
        if (!isValid) { // 校验失败（返回false）时抛异常
            throw new RuntimeException("库存被修改请重新确认"); // 抛异常后，方法立即停止运行
        }

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

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

        // 4. 正确拷贝明细列表到日志列表（修复核心错误：遍历逐个拷贝）
        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());
            deleteOutboundOrdersById(items.getId());
        }

        // 5. 非空校验后插入日志（避免空列表触发SQL语法错误）
        if (!outboundOrderLogs.isEmpty()) {

            outboundOrderLogMapper.batchOutboundOrderLog(outboundOrderLogs);

        }
        // 7. 非空校验后刷新库存
        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, List<OutboundTemplateVO>> orderGroupMap = inboundOrdersList.stream()
                .filter(vo -> StringUtils.isNotBlank(vo.getOrderId()))
                .collect(Collectors.groupingBy(OutboundTemplateVO::getOrderId));

        // 4. 第一步：仅验证所有数据（完全保留你的代码）
        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 (CollectionUtils.isEmpty(existMains) && 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.setUpdateTime(now);
                    mainDO.setUpdateUserCode(operId);
                } else {
                    mainDO = new OutboundOrders();
                    com.ruoyi.common.utils.bean.BeanUtils.copyProperties(firstVO, mainDO,
                            "sapNo", "materialName", "plannedQuantity", "actualQuantity",
                            "plannedPackages", "materialUnit", "materialRemark");

                    if (StringUtils.isNotBlank(firstVO.getOwnerName())) {
                        Owners ownerQuery = new Owners();
                        ownerQuery.setOwnerName(firstVO.getOwnerName());
                        List<Owners> owners = ownersService.selectOwnersList(ownerQuery);

                        if (CollectionUtils.isEmpty(owners)) {
                            throw new ServiceException(String.format("业主【%s】不存在，无法新增入库单【%s】",
                                    firstVO.getOwnerName(), orderId));
                        }

                        if (firstVO.getOwnerId() != null) {
                            boolean isMatch = owners.stream().anyMatch(o -> firstVO.getOwnerId().equals(o.getId()));
                            if (!isMatch) {
                                throw new ServiceException(String.format("入库单号【%s】的业主ID【%s】与业主名称【%s】不匹配",
                                        orderId, firstVO.getOwnerId(), firstVO.getOwnerName()));
                            }
                            mainDO.setOwnerId(firstVO.getOwnerId());
                        } else {
                            mainDO.setOwnerId(owners.get(0).getId());
                        }
                    } else if (firstVO.getOwnerId() != null) {
                        Owners ownerById = ownersService.selectOwnersById(firstVO.getOwnerId());
                        if (ownerById == null) {
                            throw new ServiceException(String.format("入库单号【%s】的业主ID【%s】不存在",
                                    orderId, firstVO.getOwnerId()));
                        }
                        mainDO.setOwnerId(firstVO.getOwnerId());
                    } 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();

                    com.ruoyi.common.utils.bean.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);

                    if (StringUtils.isBlank(vo.getSapNo())) {
                        throw new ServiceException(String.format("入库单号【%s】第%d条明细的物料SAP号不能为空",
                                orderId, lineNo));
                    }
                    Materials materialsQuery = new Materials();
                    materialsQuery.setSapNo(vo.getSapNo());
                    List<Materials> materialsList = materialsService.selectMaterialsList(materialsQuery);
                    if (CollectionUtils.isEmpty(materialsList)) {
                        throw new ServiceException(String.format("入库单号【%s】第%d条明细的SAP号【%s】对应的物料不存在",
                                orderId, lineNo, vo.getSapNo()));
                    }
                    itemDO.setMaterialId(materialsList.get(0).getId());

                    if (StringUtils.isBlank(vo.getLocationName())) {
                        throw new ServiceException(String.format("入库单号【%s】第%d条明细的库位名称不能为空",
                                orderId, lineNo));
                    }
                    StorageLocations storageQuery = new StorageLocations();
                    storageQuery.setLocationCode(vo.getLocationName());
                    List<StorageLocations> storageList = storageLocationsService.selectStorageLocationsList(storageQuery);
                    if (CollectionUtils.isEmpty(storageList)) {
                        throw new ServiceException(String.format("入库单号【%s】第%d条明细的库位【%s】不存在",
                                orderId, lineNo, vo.getLocationName()));
                    }
                    itemDO.setLocationId(storageList.get(0).getId());

                    Warehouses warehouses = new Warehouses();
                    warehouses.setWarehousesName(vo.getWarehouseName());
                    List<Warehouses> warehousesList = warehousesService.selectWarehousesList(warehouses);
                    if (CollectionUtils.isEmpty(warehousesList)) {
                        throw new ServiceException(String.format("系统未配置仓库，无法导入入库单号【%s】的第%d条明细",
                                orderId, lineNo));
                    }
                    itemDO.setWarehouseId(warehousesList.get(0).getId());

                    Inventory itemsList = new Inventory();
                    itemsList.setWarehousesId(itemDO.getWarehouseId());
                    itemsList.setMaterialId(itemDO.getMaterialId());
                    itemsList.setLocationId(itemDO.getLocationId());
                    List<Inventory> inventory = inventoryService.selectInventoryList(itemsList);
                    if (CollectionUtils.isEmpty(inventory)) {
                        throw new ServiceException(String.format(
                                "入库单号【%s】第%d条明细：仓库【%s】+物料【%s】+库位【%s】组合的库存记录不存在",
                                orderId, lineNo, itemDO.getWarehouseName(),firstVO.getMaterialName(), firstVO.getLocationName()));
                    }
                    itemDO.setInventoryId(inventory.get(0).getId());

                    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()));
            }
        }

        // 5. 有验证失败直接抛异常（完全保留你的代码）
        if (hasValidateError) {
            throw new ServiceException(String.format("验证失败，导入终止！失败详情：%s", failureMsg.toString()));
        }

        // 6. 验证全通过：统一执行入库/更新操作（完全保留你的代码）
        for (Map.Entry<String, OutboundOrders> entry : validMainMap.entrySet()) {
            String orderId = entry.getKey();
            OutboundOrders mainDO = entry.getValue();
            List<OutboundOrderItems> itemDOList = validItemMap.get(orderId);

            if (mainDO != null) {
                outboundOrdersMapper.insertOutboundOrders(mainDO);
                totalMainSuccess++;
                successMsg.append(String.format("入库单号【%s】已新增；\n", orderId));
            } else {
                outboundOrdersMapper.updateOutboundOrders(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));
                }
            }
        }

        // ========== 仅新增这一段代码（核心：事务提交后执行自定义逻辑） ==========
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            // 保存当前需要的变量，用于事务提交后执行
            Map<String, OutboundOrders> finalValidMainMap = new HashMap<>(validMainMap);
            Map<String, List<OutboundOrderItems>> finalValidItemMap = new HashMap<>(validItemMap);
            String finalOperId = operId;
            Date finalNow = now;

            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    // 事务提交后，调用你原来的executeCustomLogic方法
                    executeCustomLogic(finalValidMainMap, finalValidItemMap, finalOperId, finalNow);
                }
            });
        } else {
            // 无事务时，直接执行（和你原有逻辑一致）
            executeCustomLogic(validMainMap, validItemMap, operId, now);
        }
        // ========== 新增代码结束 ==========

        // 8. 结果汇总（完全保留你的代码）
        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;
        }
    }

    // 仅修改这个方法中【设置日志ID】的一行代码，其余完全保留
    private void executeCustomLogic(Map<String, OutboundOrders> validMainMap,
                                    Map<String, List<OutboundOrderItems>> validItemMap,
                                    String operId, Date now) {

        for (String orderId : validMainMap.keySet()) {
            OutboundOrders mainDO = validMainMap.get(orderId);
            List<OutboundOrderItems> itemList = validItemMap.get(orderId);
            System.out.println(String.format("订单【%s】导入成功，主表ID：%s，明细数：%d",
                    orderId, mainDO.getId(), itemList.size()));

            List<OutboundOrderLog> outboundOrderLogs = new ArrayList<>();
            for (OutboundOrderItems item : itemList) {
                OutboundOrderLog outboundOrderLog = new OutboundOrderLog();
                // ========== 唯一改动：设置日志ID = 明细ID ==========
                outboundOrderLog.setId(item.getId());
                outboundOrderLog.setOrderId(item.getOutboundOrderId());
                BeanUtils.copyProperties(item, outboundOrderLog);
                outboundOrderLogs.add(outboundOrderLog);
            }

            outboundOrderLogMapper.batchOutboundOrderLog(outboundOrderLogs);
            ship(itemList);
        }
    }
    public int ship(List<OutboundOrderItems> outboundOrderItems)
    {
        if (!outboundOrderItems.isEmpty()) {
            List<String> inventoryIds = new ArrayList<>(); // 手动收集inventoryId
            for (OutboundOrderItems outboundOrderItem : outboundOrderItems) {
                // 直接用明细的inventoryId，不查日志！
                String inventoryId = outboundOrderItem.getInventoryId();
                if (StringUtils.isBlank(inventoryId)) {
                    throw new ServiceException("明细ID【" + outboundOrderItem.getId() + "】的库存ID为空，无法扣减");
                }

                Inventory inventory = inventoryService.selectInventoryById(inventoryId);
                if (inventory == null) {
                    throw new ServiceException("库存ID【" + inventoryId + "】不存在，无法扣减");
                }

                // 扣减库存
                inventory.setQuantity(inventory.getQuantity() - outboundOrderItem.getActualQuantity());
                if (inventory.getQuantity() == 0) {
                    inventory.setInventoryStatus(0L);
                }
                inventoryService.updateInventory(inventory);

                inventoryIds.add(inventoryId); // 收集库存ID用于刷新
            }
            inventoryService.RefreshInventory(inventoryIds);
        }
        return 1;
    }
}

