"""
Scenario stress — transplanted from the retired shared ``core/calculations/scenarios.py``
with identical semantics.

Forrester TEI risk-adjusts benefits *down* and costs *up*; scenarios stress
both levers:

* ``adoption`` scales nominal values (``year_values`` and ``initial``).
* ``risk_delta`` is *added* to a benefit's risk factor and *subtracted*
  from a cost's (conservative = more uncertainty on benefits, less padding
  on costs), then clamped to [0, 1].

``"moderate"`` is the identity — the headless default reproduces the
published study. Note the counterintuitive corollary: the conservative
scenario *lowers* costs PV, because 80% adoption shrinks consumption-priced
usage and the clamp caps cost padding.
"""

from __future__ import annotations

from copy import deepcopy

SCENARIOS: dict[str, dict[str, float]] = {
    "conservative": {"adoption": 0.80, "risk_delta": 0.10},
    "moderate":     {"adoption": 1.00, "risk_delta": 0.00},
    "aggressive":   {"adoption": 1.15, "risk_delta": -0.05},
}


def apply_scenario(
    items: list[dict],
    scenario: str = "moderate",
    *,
    multipliers: dict[str, dict[str, float]] | None = None,
    table: str | None = None,
) -> list[dict]:
    """
    Deep-copied value rows with the scenario applied; inputs are not mutated.

    Each row needs ``year_values`` (year-string → float), optionally
    ``initial`` and ``risk_adjustment``, and a ``table`` of ``"benefits"``
    or ``"costs"`` (or pass ``table=`` to force one) — the table decides the
    sign of ``risk_delta``.
    """
    cfg = (multipliers or SCENARIOS).get(scenario)
    if cfg is None:
        raise KeyError(f"Unknown scenario: {scenario!r}")
    adoption = float(cfg.get("adoption", 1.0))
    risk_delta = float(cfg.get("risk_delta", 0.0))

    out: list[dict] = []
    for raw in items:
        item = deepcopy(raw)
        item_table = item.get("table") or table or "benefits"
        item["table"] = item_table

        item["year_values"] = {
            k: float(v) * adoption for k, v in item["year_values"].items()
        }
        if item.get("initial") is not None:
            item["initial"] = float(item["initial"]) * adoption

        ra = float(item.get("risk_adjustment") or 0.0)
        new_ra = ra + risk_delta if item_table == "benefits" else ra - risk_delta
        item["risk_adjustment"] = max(0.0, min(1.0, new_ra))
        out.append(item)
    return out
