package com.aps.macroplanner.constraint;

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

import java.util.Map;

/**
 * BOM 依赖需求约束构建器 (BomConstraint)
 *
 * <p>建模多级供应链中的物料消耗关系:
 * 生产成品需要消耗原材料/半成品 (BOM 展开)。</p>
 *
 * <h3>约束 1: OperationDemandQty = PTQty × BOM 因子</h3>
 * <h3>约束 2: DependentDemandInPISPIP = Σ OperationDemandQty</h3>
 */
public class BomConstraint {

    /**
     * 构建 BOM 依赖需求约束。
     */
    public static void build(MacroPlannerModel model, TestDataBuilder data) {
        Map<String, MPVariable> ptQtyVars = model.getPtQtyVars();
        Map<String, MPVariable> operationDemandQtyVars = model.getOperationDemandQtyVars();
        Map<String, MPVariable> dependentDemandVars = model.getDependentDemandVars();

        // --- 约束 1: OperationDemandQty = input.Factor × ΣPTQty(跨所有Unit) ---
        for (OperationInput input : data.getOperationInputs()) {
            Operation op = input.getOperation();
            for (Period p : data.getPeriods()) {
                String odKey = input.getKey() + "_" + p.getIndex();
                MPVariable odVar = operationDemandQtyVars.get(odKey);
                if (odVar == null) continue;

                MPConstraint odd = model.getSolver().makeConstraint(0.0, 0.0,
                        "OpDemandDef_" + odKey);
                odd.setCoefficient(odVar, 1.0);
                for (UnitOperation uo : op.getUnitOperations()) {
                    MPVariable ptVar = ptQtyVars.get(op.ptQtyKey(uo, p.getIndex()));
                    if (ptVar != null) odd.setCoefficient(ptVar, -input.getFactor());
                }
            }
        }

        // --- 约束 2: DependentDemandInPISPIP = Σ OperationDemandQty ---
        for (Product prod : data.getProducts()) {
            for (StockingPoint sp : data.getStockingPointsForProduct(prod.getId())) {

                for (Period p : data.getPeriods()) {
                    String ddKey = prod.getId() + "_" + sp.getId() + "_" + p.getIndex();
                    MPVariable ddVar = dependentDemandVars.get(ddKey);
                    if (ddVar == null) continue;

                    MPConstraint ddCon = model.getSolver().makeConstraint(0.0, 0.0,
                            "DepDemandDef_" + ddKey);
                    ddCon.setCoefficient(ddVar, -1.0);

                    for (OperationInput input : data.getOperationInputs()) {
                        if (!input.getInputProduct().getId().equals(prod.getId())) continue;
                        if (!input.getInputSp().getId().equals(sp.getId())) continue;
                        MPVariable odVar = operationDemandQtyVars.get(
                                input.getKey() + "_" + p.getIndex());
                        if (odVar != null) ddCon.setCoefficient(odVar, 1.0);
                    }
                }
            }
        }
    }
}