package com.aps.macroplanner.model;

import com.google.ortools.linearsolver.MPSolver;
import com.google.ortools.linearsolver.MPVariable;

import java.util.HashMap;
import java.util.Map;

/**
 * 优化模型容器 — 持有求解器、所有决策变量和 KPI 汇总变量。
 *
 * <p>设计原则: 所有变量通过此类的 getter 方法暴露,
 * 各约束构建器和目标函数构建器通过此模型相互协作。</p>
 *
 * <h3>变量索引键命名规则</h3>
 * <pre>
 *   生产变量:   {operationId}_{periodIndex}
 *   库存变量:   {productId}_{spId}_{periodIndex}
 *   准能松弛:   {unitId}_{periodIndex}
 *   供应松弛:   {specName}
 *   批次松弛:   {operationId}_{periodIndex}
 *   BOM 变量:   {operationId}_{productId}_{spId}_{periodIndex}
 * </pre>
 */
public class MacroPlannerModel {

    // ==================== 求解器 ====================
    /** MIP 求解器实例 (SCIP) */
    private final MPSolver solver;

    // ==================== 生产变量 ====================
    /** PTQty[operationId_periodIndex] — 生产量, 范围 [0, +∞) */
    private final Map<String, MPVariable> ptQtyVars = new HashMap<>();

    // ==================== 库存变量 ====================
    /** InvQty[productId_spId_periodIndex] — 期末库存, 范围 [0, +∞) */
    private final Map<String, MPVariable> invQtyVars = new HashMap<>();

    // ==================== 需求变量 ====================
    /** SalesDemandQty[productId_spId_periodIndex] — 销售需求满足量, 范围 [0, 需求量] */
    private final Map<String, MPVariable> salesDemandQtyVars = new HashMap<>();
    /** DemandSlack[productId_spId_periodIndex] — 需求松弛, 范围 [0, +∞) */
    private final Map<String, MPVariable> demandSlackVars = new HashMap<>();
    /** OperationDemandQty[inputKey_periodIndex] — BOM 消耗量, 范围 [0, +∞) */
    private final Map<String, MPVariable> operationDemandQtyVars = new HashMap<>();
    /** DependentDemandInPISPIP[productId_spId_periodIndex] — PISPIP 总依赖需求, 范围 [0, +∞) */
    private final Map<String, MPVariable> dependentDemandVars = new HashMap<>();
    /** DemandFulfillmentInPISPIP[productId_spId_periodIndex] — PISPIP 总需求满足量,
     *  用于安全库存天数计算。等于 SalesDemandQty + OperationDemandQty 之和。
     *  范围 [0, +∞) */
    private final Map<String, MPVariable> demandFulfillmentVars = new HashMap<>();

    // ==================== 产能松弛变量 ====================
    /** CapacityOverloaded[unitId_periodIndex] — 产能超载, 范围 [0, +∞) */
    private final Map<String, MPVariable> capacityOverloadedVars = new HashMap<>();
    /** CapacityNotMet[unitId_periodIndex] — 产能未满足, 范围 [0, +∞) */
    private final Map<String, MPVariable> capacityNotMetVars = new HashMap<>();

    // ==================== 库存松弛变量 ====================
    /** MinInvQtyUnder[productId_spId_periodIndex] — 低于最小库存, 范围 [0, +∞) */
    private final Map<String, MPVariable> minInvQtyUnderVars = new HashMap<>();
    /** MaxInvQtyOver[productId_spId_periodIndex] — 超过最大库存, 范围 [0, +∞) */
    private final Map<String, MPVariable> maxInvQtyOverVars = new HashMap<>();
    /** InvQtyUnderTarget[productId_spId_periodIndex] — 低于目标库存, 范围 [0, +∞) */
    private final Map<String, MPVariable> invQtyUnderTargetVars = new HashMap<>();

    // ==================== 供应松弛变量 ====================
    /** SupplyTargetQtyUnder[specName] — 供应目标不足, 范围 [0, +∞) */
    private final Map<String, MPVariable> supplyTargetQtyUnderVars = new HashMap<>();
    /** MinSupplyQtyUnder[specName] — 最小供应不足, 范围 [0, +∞) */
    private final Map<String, MPVariable> minSupplyQtyUnderVars = new HashMap<>();
    /** MaxSupplyQtyOver[specName] — 最大供应超出, 范围 [0, +∞) */
    private final Map<String, MPVariable> maxSupplyQtyOverVars = new HashMap<>();

    // ==================== 批次松弛变量 ====================
    /** PTLotSizeOver[operationId_periodIndex] — 批次超出, 范围 [0, +∞) */
    private final Map<String, MPVariable> ptLotSizeOverVars = new HashMap<>();
    /** PTLotSizeUnder[operationId_periodIndex] — 批次不足, 范围 [0, +∞) */
    private final Map<String, MPVariable> ptLotSizeUnderVars = new HashMap<>();

    // ==================== KPI 汇总变量 ====================
    private MPVariable totalFulfillment;
    private MPVariable totalLotSize;
    private MPVariable totalMaxInventoryLevel;
    private MPVariable totalMinInventoryLevel;
    private MPVariable totalTargetInvLevel;
    private MPVariable totalUnitCapacity;
    private MPVariable totalSupplyTarget;
    private MPVariable totalMinSupply;
    private MPVariable totalMaxSupply;
    private MPVariable totalSalesDemandPriority;
    private MPVariable totalPostponementPenalty;
    private MPVariable totalProcessMaxQuantity;

    // ==================== 构造 ====================

    /**
     * 创建模型容器, 初始化 SCIP 求解器。
     * 变量创建由 {@link VariableFactory} 负责。
     */
    public MacroPlannerModel() {
        this.solver = MPSolver.createSolver("SCIP");

        if (solver == null) {
            throw new RuntimeException("无法加载 SCIP 求解器，请检查 OR-Tools 依赖");
        }
        solver.enableOutput();


    }

    // ==================== KPI 变量 setter (由 KpiAggregator 调用) ====================

    public void setTotalFulfillment(MPVariable v) { this.totalFulfillment = v; }
    public void setTotalLotSize(MPVariable v) { this.totalLotSize = v; }
    public void setTotalMaxInventoryLevel(MPVariable v) { this.totalMaxInventoryLevel = v; }
    public void setTotalMinInventoryLevel(MPVariable v) { this.totalMinInventoryLevel = v; }
    public void setTotalTargetInvLevel(MPVariable v) { this.totalTargetInvLevel = v; }
    public void setTotalUnitCapacity(MPVariable v) { this.totalUnitCapacity = v; }
    public void setTotalSupplyTarget(MPVariable v) { this.totalSupplyTarget = v; }
    public void setTotalMinSupply(MPVariable v) { this.totalMinSupply = v; }
    public void setTotalMaxSupply(MPVariable v) { this.totalMaxSupply = v; }
    public void setTotalSalesDemandPriority(MPVariable v) { this.totalSalesDemandPriority = v; }
    public void setTotalPostponementPenalty(MPVariable v) { this.totalPostponementPenalty = v; }
    public void setTotalProcessMaxQuantity(MPVariable v) { this.totalProcessMaxQuantity = v; }

    // ==================== Getters ====================

    public MPSolver getSolver() { return solver; }

    public Map<String, MPVariable> getPtQtyVars() { return ptQtyVars; }
    public Map<String, MPVariable> getInvQtyVars() { return invQtyVars; }
    public Map<String, MPVariable> getSalesDemandQtyVars() { return salesDemandQtyVars; }
    public Map<String, MPVariable> getDemandSlackVars() { return demandSlackVars; }
    public Map<String, MPVariable> getOperationDemandQtyVars() { return operationDemandQtyVars; }
    public Map<String, MPVariable> getDependentDemandVars() { return dependentDemandVars; }
    public Map<String, MPVariable> getDemandFulfillmentVars() { return demandFulfillmentVars; }
    public Map<String, MPVariable> getCapacityOverloadedVars() { return capacityOverloadedVars; }
    public Map<String, MPVariable> getCapacityNotMetVars() { return capacityNotMetVars; }
    public Map<String, MPVariable> getMinInvQtyUnderVars() { return minInvQtyUnderVars; }
    public Map<String, MPVariable> getMaxInvQtyOverVars() { return maxInvQtyOverVars; }
    public Map<String, MPVariable> getInvQtyUnderTargetVars() { return invQtyUnderTargetVars; }
    public Map<String, MPVariable> getSupplyTargetQtyUnderVars() { return supplyTargetQtyUnderVars; }
    public Map<String, MPVariable> getMinSupplyQtyUnderVars() { return minSupplyQtyUnderVars; }
    public Map<String, MPVariable> getMaxSupplyQtyOverVars() { return maxSupplyQtyOverVars; }
    public Map<String, MPVariable> getPtLotSizeOverVars() { return ptLotSizeOverVars; }
    public Map<String, MPVariable> getPtLotSizeUnderVars() { return ptLotSizeUnderVars; }

    public MPVariable getTotalFulfillment() { return totalFulfillment; }
    public MPVariable getTotalLotSize() { return totalLotSize; }
    public MPVariable getTotalMaxInventoryLevel() { return totalMaxInventoryLevel; }
    public MPVariable getTotalMinInventoryLevel() { return totalMinInventoryLevel; }
    public MPVariable getTotalTargetInvLevel() { return totalTargetInvLevel; }
    public MPVariable getTotalUnitCapacity() { return totalUnitCapacity; }
    public MPVariable getTotalSupplyTarget() { return totalSupplyTarget; }
    public MPVariable getTotalMinSupply() { return totalMinSupply; }
    public MPVariable getTotalMaxSupply() { return totalMaxSupply; }
    public MPVariable getTotalSalesDemandPriority() { return totalSalesDemandPriority; }
    public MPVariable getTotalPostponementPenalty() { return totalPostponementPenalty; }
    public MPVariable getTotalProcessMaxQuantity() { return totalProcessMaxQuantity; }
}