package com.awspaas.user.apps.donenow_ivt.service;

import com.actionsoft.bpms.bo.engine.BO;
import com.actionsoft.bpms.bpmn.engine.model.run.delegate.ProcessInstance;
import com.actionsoft.bpms.server.UserContext;
import com.actionsoft.sdk.local.SDK;
import com.actionsoft.sdk.local.api.Logger;
import org.apache.commons.lang3.StringUtils;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;

/**
 * 仓库产品服务类 - 处理产品库存转移等操作
 */
public class WarehouseProductService {
    // 常量定义
    private static final Logger serviceLogger = SDK.getLogAPI().getLogger(WarehouseProductService.class);
    private static final String BO_WAREHOUSE_PRODUCT = "BO_EU_DNIVT_WAREHOUSE_PRODUCT";
    private static final String BO_WAREHOUSE_PRODUCT_LOT = "BO_EU_DNIVT_WAREHOUSE_PRODUCT_LOT";

    // 单例模式
    private static volatile WarehouseProductService instance;

    private WarehouseProductService() {
    }

    public static WarehouseProductService getInstance() {
        if (instance == null) {
            synchronized (WarehouseProductService.class) {
                if (instance == null) {
                    instance = new WarehouseProductService();
                }
            }
        }
        return instance;
    }

    /**
     * 核心转移方法 - 处理整个产品转移流程
     */
    public void transfer(UserContext uc, Connection conn, String productId, String fromWarehouseId,
                         String toWarehouseId, int quantity, String serialNumbers, int type, Map<String, Object> params) throws SQLException {
        // 参数校验
        if (quantity <= 0) {
            serviceLogger.warn("转移数量必须大于0，当前数量：" + quantity);
            return;
        }
        if (fromWarehouseId.equals(toWarehouseId)) {
            serviceLogger.warn("源仓库与目标仓库相同，无需转移：" + fromWarehouseId);
            return;
        }

        try {
            // 1. 更新目标仓库库存（增加）
            BO targetWarehouseBO = null;
            if (StringUtils.isNotBlank(toWarehouseId)) {
                targetWarehouseBO = updateWarehouseStock(uc, conn, productId, toWarehouseId, quantity, true);
            }
            // 2. 更新源仓库库存（减少）
            BO sourceWarehouseBO = updateWarehouseStock(uc, conn, productId, fromWarehouseId, quantity, false);

            // 3. 处理批次和序列号转移
            processLotAndSerialTransfer(uc, conn, sourceWarehouseBO, targetWarehouseBO, quantity, serialNumbers);

            serviceLogger.info("产品转移成功，产品ID：" + productId + "，数量：" + quantity +
                    "，从仓库：" + fromWarehouseId + "到仓库：" + toWarehouseId);


            //移库记录
            ProcessInstance transfeProcessIns = SDK.getProcessAPI().createBOProcessInstance("obj_e15a8fedeaeb43dc85aa258a7e1cffcf", uc.getUID(), "库存转移");
            BO ivtTransfer = new BO();
            ivtTransfer.setAll(params);
            ivtTransfer.setBindId(transfeProcessIns.getId());
            ivtTransfer.set("FROM_WAREHOUSE_ID", fromWarehouseId);
            ivtTransfer.set("TO_WAREHOUSE_ID", toWarehouseId);
            ivtTransfer.set("TYPE_ID", type);
            ivtTransfer.set("PRODUCT_ID", productId);
            ivtTransfer.set("QUANTITY", quantity);
            ivtTransfer.set("SN", serialNumbers);//产品序列号
            SDK.getBOAPI().create("BO_EU_DNIVT_TRANSFER", ivtTransfer, transfeProcessIns, uc, conn);

        } catch (Exception e) {
            serviceLogger.error("产品转移失败：" + e.getMessage(), e);
            throw new SQLException("产品转移过程中发生错误", e);
        }
    }

    /**
     * 统一处理仓库库存更新（增加或减少）
     * @param isTarget  true表示目标仓库（增加库存），false表示源仓库（减少库存）
     */
    private BO updateWarehouseStock(UserContext uc, Connection conn, String productId,
                                    String warehouseId, int quantity, boolean isTarget) throws SQLException {
        // 查询仓库中是否已有该产品记录
        BO warehouseBO = SDK.getBOAPI().query(BO_WAREHOUSE_PRODUCT)
                .connection(conn)
                .addQuery("PRODUCT_ID=", productId)
                .addQuery("WAREHOUSE_ID=", warehouseId)
                .detail();

        if (warehouseBO != null) {
            // 已有记录，更新库存
            int currentQty = objToInt(warehouseBO.get("QUANTITY"));
            int newQty = isTarget ? currentQty + quantity : currentQty - quantity;

            // 源仓库库存不足校验
            if (!isTarget && newQty < 0) {
                throw new SQLException("仓库库存不足，产品ID：" + productId + "，当前库存：" + currentQty +
                        "，需操作：" + quantity);
            }

            warehouseBO.set("QUANTITY", newQty);
            SDK.getBOAPI().update(BO_WAREHOUSE_PRODUCT, warehouseBO, conn);
            serviceLogger.debug((isTarget ? "更新目标仓库" : "更新源仓库") + "库存，产品ID：" + productId +
                    "，仓库：" + warehouseId + "，原数量：" + currentQty +
                    (isTarget ? "，新增：" : "，减少：") + quantity);
        } else {
            // 无记录，仅目标仓库需要创建新记录
            if (isTarget) {
                ProcessInstance processIns = SDK.getProcessAPI()
                        .createBOProcessInstance("obj_e15a8fedeaeb43dc85aa258a7e1cffcf", uc.getUID(), "库存转移");
                warehouseBO = new BO();
                warehouseBO.setBindId(processIns.getId());
                warehouseBO.set("WAREHOUSE_ID", warehouseId);
                warehouseBO.set("PRODUCT_ID", productId);
                warehouseBO.set("QUANTITY", quantity);
                SDK.getBOAPI().create(BO_WAREHOUSE_PRODUCT, warehouseBO, processIns, uc, conn);
                serviceLogger.debug("创建目标仓库库存记录，产品ID：" + productId + "，仓库：" + warehouseId +
                        "，初始数量：" + quantity);
            } else {
                // 源仓库无记录则抛出异常
                throw new SQLException("源仓库不存在该产品库存记录，产品ID：" + productId + "，仓库：" + warehouseId);
            }
        }
        return warehouseBO;
    }

    /**
     * 处理批次和序列号转移（合并原多个方法为一个）
     */
    private void processLotAndSerialTransfer(UserContext uc, Connection conn, BO sourceWarehouseBO,
                                             BO targetWarehouseBO, int totalQuantity, String serialNumbers) throws SQLException {
        String sourceBindId = sourceWarehouseBO.getBindId();
        String targetBindId = targetWarehouseBO == null ? StringUtils.EMPTY : targetWarehouseBO.getBindId();
        String productId = targetWarehouseBO.getString("PRODUCT_ID");
        String targetWarehouseId = targetWarehouseBO.getString("WAREHOUSE_ID");

        // 处理序列号
        String[] snArray = StringUtils.isBlank(serialNumbers) ? new String[0] : serialNumbers.split(",");
        Set<String> snSet = new HashSet<>(Arrays.asList(snArray));
        List<BO> sourceLots = SDK.getBOAPI().query(BO_WAREHOUSE_PRODUCT_LOT)
                .addQuery("BINDID=", sourceBindId)
                .addQuery("QUANTITY>", 0)
                .orderByCreated()
                .list();

        // 区分序列化和非序列化产品处理
        if (snArray.length > 0) {
            // 处理序列化产品转移
            int processedCount = 0;
            int totalNeedProcess = snSet.size();

            for (BO lot : sourceLots) {
                if (processedCount >= totalNeedProcess) break;

                String lotSN = lot.getString("SN");
                if (StringUtils.isBlank(lotSN)) continue;

                // 提取当前批次中需要转移的序列号
                Set<String> currentLotSNs = new HashSet<>(Arrays.asList(lotSN.split(",")));
                currentLotSNs.retainAll(snSet);//交集

                if (!currentLotSNs.isEmpty()) {
                    // 更新源批次
                    Set<String> remainingSNs = new HashSet<>(Arrays.asList(lotSN.split(",")));
                    remainingSNs.removeAll(currentLotSNs);
                    lot.set("SN", StringUtils.join(remainingSNs, ","));
                    lot.set("QUANTITY", remainingSNs.size());
                    SDK.getBOAPI().update(BO_WAREHOUSE_PRODUCT_LOT, lot, conn);

                    // 更新或创建目标批次
                    if (StringUtils.isNotBlank(targetBindId)) {
                        updateOrCreateTargetLot(uc, conn, lot, targetBindId, productId, targetWarehouseId,
                                currentLotSNs.size(), StringUtils.join(currentLotSNs, ","), true);
                    }
                    processedCount += currentLotSNs.size();
                    snSet.removeAll(currentLotSNs);
                }
            }

            if (!snSet.isEmpty()) {
                serviceLogger.warn("部分序列号未找到对应批次，未处理SN：" + StringUtils.join(snSet, ","));
            }
        } else {
            // 处理非序列化产品转移
            int remainingQuantity = totalQuantity;

            for (BO lot : sourceLots) {
                if (remainingQuantity <= 0) break;

                int lotQuantity = objToInt(lot.get("QUANTITY"));
                if (lotQuantity <= 0) continue;

                // 计算本次转移数量
                int transferQty = Math.min(lotQuantity, remainingQuantity);

                // 更新源批次
                lot.set("QUANTITY", lotQuantity - transferQty);
                SDK.getBOAPI().update(BO_WAREHOUSE_PRODUCT_LOT, lot, conn);

                // 更新或创建目标批次
                if (StringUtils.isNotBlank(targetBindId))
                    updateOrCreateTargetLot(uc, conn, lot, targetBindId, productId, targetWarehouseId,
                            transferQty, "", false);

                remainingQuantity -= transferQty;
            }

            if (remainingQuantity > 0) {
                throw new SQLException("源批次库存不足，剩余未转移数量：" + remainingQuantity);
            }
        }
    }

    /**
     * 工具方法：更新或创建目标批次（内部使用）
     */
    private void updateOrCreateTargetLot(UserContext uc, Connection conn, BO sourceLot, String targetBindId,
                                         String productId, String targetWarehouseId,
                                         int transferQty, String snStr, boolean isSerialized) throws SQLException {
        BO targetLot = SDK.getBOAPI().query(BO_WAREHOUSE_PRODUCT_LOT)
                .addQuery("LOT=", sourceLot.get("LOT"))
                .addQuery("ORDER_PRODUCT_ID=", sourceLot.get("ORDER_PRODUCT_ID"))
                .addQuery("BINDID=", targetBindId)
                .detail();

        if (targetLot != null) {
            int newQty = objToInt(targetLot.get("QUANTITY")) + transferQty;
            targetLot.set("QUANTITY", newQty);
            if (isSerialized) {
                String currentSN = targetLot.getString("SN");
                targetLot.set("SN", StringUtils.isBlank(currentSN) ? snStr : currentSN + "," + snStr);
            }
            SDK.getBOAPI().update(BO_WAREHOUSE_PRODUCT_LOT, targetLot, conn);
        } else {
            BO newLot = new BO();
            newLot.setAll(sourceLot.asMap());
            newLot.setId(null);
            newLot.setBindId(targetBindId);
            newLot.set("WAREHOUSE_ID", targetWarehouseId);
            newLot.set("PRODUCT_ID", productId);
            newLot.set("QUANTITY", transferQty);
            newLot.set("SN", snStr);
            SDK.getBOAPI().createDataBO(BO_WAREHOUSE_PRODUCT_LOT, newLot, uc, conn);
        }
    }

    /**
     * 工具方法：安全的Object转int
     */
    private int objToInt(Object obj) {
        if (obj == null) return 0;

        try {
            String objStr = obj.toString().trim();
            if (objStr.isEmpty()) return 0;
            if (objStr.contains(".")) {
                objStr = objStr.substring(0, objStr.indexOf("."));
            }
            return Integer.parseInt(objStr);
        } catch (NumberFormatException e) {
            serviceLogger.error("对象转换为int失败，值：" + obj, e);
            return 0;
        }
    }
}
