package com.aps.macroplanner.variable;

import com.google.ortools.linearsolver.MPSolver;
import com.aps.macroplanner.data.*;
import com.aps.macroplanner.model.MacroPlannerModel;

/**
 * 需求变量构建器 — 创建 SalesDemandQty 和 DemandSlack 变量。
 *
 * <h3>SalesDemandQty[productId_spId_periodIndex]</h3>
 * <ul>
 *   <li>索引: SalesDemand (Product × StockingPoint × Period)</li>
 *   <li>含义: 实际满足的独立销售需求量 (≤ 原始需求总量)</li>
 *   <li>范围: [0, 需求总量]</li>
 * </ul>
 *
 * <h3>DemandSlack[productId_spId_periodIndex]</h3>
 * <ul>
 *   <li>索引: Product × StockingPoint × Period</li>
 *   <li>含义: 物料平衡约束中的松弛量，用于防止模型不可行。
 *       当供应无法满足需求时，可由 DemandSlack "虚拟供应"来填补缺口。</li>
 *   <li>范围: [0, +∞)</li>
 *   <li>在目标函数中以高权重惩罚，确保只在必要时使用</li>
 * </ul>
 */
public class DemandVariableBuilder {

    public static void create(MacroPlannerModel model, TestDataBuilder data) {
        createSalesDemandQty(model, data);
        createDemandSlack(model, data);
    }

    private static void createSalesDemandQty(MacroPlannerModel model, TestDataBuilder data) {
        for (SalesDemand sd : data.getSalesDemands()) {
            model.getSalesDemandQtyVars().put(sd.getKey(),
                    model.getSolver().makeNumVar(0.0, sd.getQuantity(), "SDQty_" + sd.getKey()));
        }
    }

    private static void createDemandSlack(MacroPlannerModel model, TestDataBuilder data) {
        double inf = MPSolver.infinity();
        for (Product prod : data.getProducts()) {
            for (StockingPoint sp : data.getStockingPointsForProduct(prod.getId())) {

                for (Period p : data.getPeriods()) {
                    String key = prod.getId() + "_" + sp.getId() + "_" + p.getIndex();
                    model.getDemandSlackVars().put(key,
                            model.getSolver().makeNumVar(0.0, inf, "DemandSlack_" + key));
                }
            }
        }
    }
}