"use client";

/**
 * 6.2 Сценарии — conservative / base / aggressive side by side.
 *
 * For each scenario shows the deficit_index at the target horizon (preferring
 * the scenario's own forecast row, falling back to scenarios_summary) and the
 * rate_path across all horizons (ключевая ставка, % годовых).
 */

import { Badge } from "@/components/ui/Badge";
import type {
  DemandSupplyForecast,
  RatePath,
  ReportScenarios,
  ScenarioKey,
  ScenariosSummary,
} from "@/types/forecast";
import {
  DEFICIT_BALANCE_EPS,
  deficitVariant,
  deficitWord,
  fmtNum,
  type DeficitPegState,
} from "./forecast-helpers";
import { DeficitPegPlaque } from "./ForecastHorizonsBlock";

interface Props {
  scenarios: ReportScenarios;
  scenariosSummary: ScenariosSummary | null;
  targetHorizon: number;
  /**
   * B1 (#1958/#1959) — pegged-signal state (deficit_index уперся в край шкалы на
   * всех горизонтах). Тот же объект, что у 6.1 — считается один раз в
   * Section6Forecast. Когда pegged, над карточками показываем честную плашку
   * «на пределе», т.к. −1.00 одинаков во всех сценариях.
   */
  peg?: DeficitPegState;
}

// Display order: conservative → base → aggressive (worst-to-best rate path).
const SCENARIO_ORDER: ScenarioKey[] = ["conservative", "base", "aggressive"];

const SCENARIO_RU: Record<ScenarioKey, string> = {
  conservative: "Консервативный",
  base: "Базовый",
  aggressive: "Агрессивный",
};

const SCENARIO_HINT: Record<ScenarioKey, string> = {
  conservative: "ставка выше",
  base: "ставка без изменений",
  aggressive: "ставка ниже",
};

function pickHorizonForecast(
  forecasts: DemandSupplyForecast[],
  targetHorizon: number,
): DemandSupplyForecast | null {
  if (forecasts.length === 0) return null;
  const exact = forecasts.find((f) => f.horizon_months === targetHorizon);
  if (exact) return exact;
  // Fall back to the longest available horizon.
  return [...forecasts].sort((a, b) => b.horizon_months - a.horizon_months)[0];
}

interface ScenarioDeficit {
  value: number | null;
  /** Horizon (months) the value actually corresponds to, or null when unknown. */
  horizon: number | null;
}

function deficitForScenario(
  key: ScenarioKey,
  scenarios: ReportScenarios,
  scenariosSummary: ScenariosSummary | null,
  targetHorizon: number,
): ScenarioDeficit {
  const sc = scenarios.by_scenario[key];
  const fc = sc ? pickHorizonForecast(sc.forecasts, targetHorizon) : null;
  if (fc) return { value: fc.deficit_index, horizon: fc.horizon_months };
  // scenarios_summary is, by contract, the deficit_index at the target horizon.
  if (scenariosSummary)
    return { value: scenariosSummary[key], horizon: targetHorizon };
  return { value: null, horizon: null };
}

export function ScenariosBlock({
  scenarios,
  scenariosSummary,
  targetHorizon,
  peg,
}: Props) {
  const pegPlaque =
    peg?.pegged && peg.sign != null ? (
      <DeficitPegPlaque sign={peg.sign} />
    ) : null;
  const present = SCENARIO_ORDER.filter(
    (k) => scenarios.by_scenario[k] != null || scenariosSummary != null,
  );

  if (present.length === 0) {
    return (
      <p style={{ fontSize: 13, color: "var(--fg-tertiary)", margin: 0 }}>
        Сценарный прогноз недоступен.
      </p>
    );
  }

  // #1871 P1 — when backend `compute_scenarios` collapses three scenarios into
  // a single line (failed §9.6 β rate-sensitivity gate → demand_normalization
  // returns coefficient=1.0 across the envelope) we render ONE «Базовый» card
  // + a dark headline-bar with the reason from backend instead of three
  // visually-identical copies. Caveat text is the source-of-truth backend
  // constant `_COLLAPSE_REASON_LOW_BETA`, NEVER hardcoded in TSX.
  if (scenarios.scenarios_collapsed === true) {
    const sc = scenarios.by_scenario.base;
    const di = deficitForScenario(
      "base",
      scenarios,
      scenariosSummary,
      targetHorizon,
    );
    return (
      <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
        {pegPlaque}
        <div
          style={{
            borderRadius: 12,
            background: "var(--bg-headline)",
            color: "var(--fg-on-dark)",
            padding: "14px 18px",
            display: "flex",
            flexDirection: "column",
            gap: 6,
          }}
        >
          <div style={{ fontSize: 14, fontWeight: 600 }}>
            Почему один сценарий, а не три
          </div>
          {scenarios.scenarios_collapse_reason && (
            <div
              style={{
                fontSize: 12,
                lineHeight: 1.5,
                color: "var(--fg-on-dark-muted)",
              }}
            >
              {scenarios.scenarios_collapse_reason}
            </div>
          )}
        </div>
        <div
          style={{
            display: "grid",
            gridTemplateColumns: "minmax(220px, 480px)",
            gap: 12,
          }}
        >
          <ScenarioCard
            name={SCENARIO_RU.base}
            hint={SCENARIO_HINT.base}
            deficitIndex={di.value}
            deficitHorizon={di.horizon}
            ratePath={sc?.rate_path}
            targetHorizon={targetHorizon}
          />
        </div>
      </div>
    );
  }

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
      {pegPlaque}
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))",
          gap: 12,
        }}
      >
        {present.map((key) => {
          const sc = scenarios.by_scenario[key];
          const di = deficitForScenario(
            key,
            scenarios,
            scenariosSummary,
            targetHorizon,
          );
          return (
            <ScenarioCard
              key={key}
              name={SCENARIO_RU[key]}
              hint={SCENARIO_HINT[key]}
              deficitIndex={di.value}
              deficitHorizon={di.horizon}
              ratePath={sc?.rate_path}
              targetHorizon={targetHorizon}
            />
          );
        })}
      </div>
      <p style={{ fontSize: 12, color: "var(--fg-tertiary)", margin: 0 }}>
        Индекс дефицита приведён на целевом горизонте {targetHorizon} мес.; если
        ряд на этом горизонте отсутствует, используется самый длинный доступный
        — его горизонт указан в подписи карточки. Конверт ставки — путь ключевой
        ставки (% годовых) по горизонтам.
      </p>
    </div>
  );
}

function ScenarioCard({
  name,
  hint,
  deficitIndex,
  deficitHorizon,
  ratePath,
  targetHorizon,
}: {
  name: string;
  hint: string;
  deficitIndex: number | null;
  /** Horizon (months) the deficit value corresponds to; falls back to target. */
  deficitHorizon: number | null;
  ratePath: RatePath | undefined;
  targetHorizon: number;
}) {
  // Label the number with the horizon it actually represents, not the target.
  const labelHorizon = deficitHorizon ?? targetHorizon;
  const horizons = ratePath
    ? Object.keys(ratePath)
        .map((h) => Number(h))
        .sort((a, b) => a - b)
    : [];

  return (
    <div
      style={{
        borderRadius: 12,
        border: "1px solid var(--border-card)",
        background: "var(--bg-card)",
        padding: 16,
        display: "flex",
        flexDirection: "column",
        gap: 12,
      }}
    >
      <div>
        <div
          style={{
            fontSize: 13,
            fontWeight: 600,
            color: "var(--fg-primary)",
          }}
        >
          {name}
        </div>
        <div
          style={{ fontSize: 12, color: "var(--fg-tertiary)", marginTop: 2 }}
        >
          {hint}
        </div>
      </div>

      {/* Deficit at target horizon */}
      <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
        <span
          style={{
            fontSize: 11,
            fontWeight: 500,
            letterSpacing: "0.04em",
            textTransform: "uppercase",
            color: "var(--fg-secondary)",
          }}
        >
          Индекс дефицита · {labelHorizon} мес.
        </span>
        {deficitIndex != null ? (
          <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <Badge variant={deficitVariant(deficitIndex)} size="md">
              {deficitIndex > 0 ? "+" : ""}
              {fmtNum(deficitIndex, 2)}
            </Badge>
            <span style={{ fontSize: 12, color: "var(--fg-secondary)" }}>
              {Math.abs(deficitIndex) < DEFICIT_BALANCE_EPS
                ? "баланс"
                : deficitWord(deficitIndex)}
            </span>
          </div>
        ) : (
          <span style={{ fontSize: 13, color: "var(--fg-tertiary)" }}>—</span>
        )}
      </div>

      {/* Rate path */}
      {horizons.length > 0 && ratePath && (
        <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
          <span
            style={{
              fontSize: 11,
              fontWeight: 500,
              letterSpacing: "0.04em",
              textTransform: "uppercase",
              color: "var(--fg-secondary)",
            }}
          >
            Конверт ставки
          </span>
          <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
            {horizons.map((h) => (
              <span
                key={h}
                style={{
                  fontSize: 12,
                  color: "var(--fg-primary)",
                  background: "var(--bg-card-alt)",
                  border: "1px solid var(--border-soft)",
                  borderRadius: 6,
                  padding: "2px 6px",
                  fontVariantNumeric: "tabular-nums",
                }}
              >
                {h} мес.: {fmtNum(ratePath[String(h)], 2)}%
              </span>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}
