// Responsive styles live in index.html, keyed off [data-bp-and-below~="…"]
// or @container queries on .r-tower. Do not add new inline ternaries on
// viewport width or `compact` — convert to a CSS class instead.
// Cascading: [data-bp-and-below~="mobile"] also matches at narrow.
// Use exact [data-bp="…"] only when the rule applies at one bucket alone.

const { useState, useMemo, useEffect, useRef, Fragment } = React;

// ═══════════════════════════════════════════════════════════════
// Matrix — Towers (vertical capital stack as buildings)
// ═══════════════════════════════════════════════════════════════
function StackDiagram({ dark, lang, columns }) {
  const text = dark ? "#FAF7F3" : "#393433";
  const lime = "#EDFE38";
  const muted = dark ? "#8A827F" : "#6B6361";

  // Collect per-tier aggregate stats from currently visible columns
  const tierStats = useMemo(() => {
    const stats = {}; // { [tier]: {count, rLo, rHi} }
    if (!columns) return stats;
    for (const col of columns) {
      for (const [tier, cell] of col.cells.entries()) {
        if (!cell || !cell.product) continue;
        const rng = window.formatRange(cell.product);
        if (!rng || rng.kind === "multiple") {
          stats[tier] = stats[tier] || { count: 0, rLo: Infinity, rHi: -Infinity };
          stats[tier].count++;
          continue;
        }
        stats[tier] = stats[tier] || { count: 0, rLo: Infinity, rHi: -Infinity };
        stats[tier].count++;
        stats[tier].rLo = Math.min(stats[tier].rLo, rng.lo);
        stats[tier].rHi = Math.max(stats[tier].rHi, rng.hi);
      }
    }
    return stats;
  }, [columns]);

  const bands = window.SETTINGS?.capitalStackBands ?? [
    { label: "SR",   color: "#4866B2", tier: "senior-debt" },
    { label: "MEZZ", color: "#6D85C3", tier: "mezzanine" },
    { label: "PREF", color: "#A1B0D4", tier: "pref-equity" },
    { label: "COMM", color: "#D4B24A", tier: "common-equity" },
    { label: "LP",   color: lime,      tier: "syndicate-lp" },
  ];
  return (
    <svg viewBox="0 0 120 80" preserveAspectRatio="none" width="100%" height="100%" style={{ display: "block" }}>
      <rect width="120" height="80" fill={dark ? "#0D0D0D" : "#EAE4DB"}/>
      {bands.map((b, i) => {
        const y = 12 + i * 12;
        const stat = tierStats[b.tier];
        const hasRange = stat && isFinite(stat.rLo);
        return (
          <g key={i}>
            <rect x="20" y={y} width="80" height="12" fill={b.color} opacity={dark ? 0.85 : 1}/>
            <text x="26" y={y + 8.2} textAnchor="start" fontFamily="ui-monospace,monospace" fontSize="5.5" fill={i === 4 ? "#393433" : "#FFFFFF"} letterSpacing="1">
              {b.label}
            </text>
            {hasRange && (
              <text x="94" y={y + 8.2} textAnchor="end" fontFamily="ui-monospace,monospace" fontSize="5" fill={i === 4 ? "#393433" : "#FFFFFF"} opacity="0.9" letterSpacing="0.3">
                {Math.round(stat.rLo)}–{Math.round(stat.rHi)}%
              </text>
            )}
          </g>
        );
      })}
      <rect x="0" y="72" width="120" height="8" fill={text}/>
      <g stroke={muted} strokeWidth="0.7" fill="none">
        <line x1="8" y1="14" x2="8" y2="68"/>
        <path d="M 6 66 L 8 70 L 10 66"/>
        <line x1="112" y1="14" x2="112" y2="68"/>
        <path d="M 110 16 L 112 12 L 114 16"/>
      </g>
      <text x="8" y="78" fontFamily="ui-monospace,monospace" fontSize="3.5" fill={muted} textAnchor="middle" letterSpacing="0.5">PRIORITY</text>
      <text x="112" y="78" fontFamily="ui-monospace,monospace" fontSize="3.5" fill={muted} textAnchor="middle" letterSpacing="0.5">UPSIDE</text>
    </svg>
  );
}

function MatrixC({ columns, profile, t, lang, dark, selectedId, onSelectProduct, density, highlight, hideIneligible, onSetHideIneligible, statusFilter, onClearStatus }) {
  const text = dark ? "#FAF7F3" : "#393433";
  const muted = dark ? "#8A827F" : "#6B6361";
  const faint = dark ? "#5A5654" : "#C1C1C1";
  const border = dark ? "#2A2825" : "#E2E0DF";
  const accent = "#4866B2";
  const visibleCols = hideIneligible ? columns.filter(c => Array.from(c.cells.values()).some(v => v.eligible)) : columns;
  const mutedTiers = window.mutedTypeTiers ? window.mutedTypeTiers(profile) : null;

  // Width-axis "compact" is derived from the shared useBreakpoint hook so there
  // is one source of truth for responsive width-bucketing (used by CSS via
  // [data-bp-and-below~="…"] and by JS here). Height-axis vh is still tracked
  // independently because the floor-budget math needs the live viewport
  // height — no CSS equivalent for "fit 4 rows into available vh".
  const bp = window.useBreakpoint();
  // The offerings frame sits under the fixed site header (story-page.jsx, 48px), so the matrix gets
  // the window's height less that.
  const [vh, setVh] = useState(typeof window !== "undefined" ? window.innerHeight - 48 : 900);
  useEffect(() => {
    const onResize = () => { setVh(window.innerHeight - 48); };
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);

  // Measure the natural content height of every tower-head (via the inner
  // wrapper, which isn't affected by the head's own min-height). Publish the
  // max as the --tower-head-h CSS var on the grid so every head locks to the
  // tallest head's content. The legend top spacer reads the same var (see
  // .r-legend-head-spacer in index.html), so legend tier rows always align
  // with tower floors with zero JS-CSS sync lag.
  const matrixGridRef = useRef(null);
  useEffect(() => {
    const measure = () => {
      const grid = matrixGridRef.current;
      if (!grid) return;
      const inners = grid.querySelectorAll(".r-tower-head-inner");
      if (!inners.length) return;
      let maxInner = 0;
      inners.forEach(el => { if (el.offsetHeight > maxInner) maxInner = el.offsetHeight; });
      const head = grid.querySelector(".r-tower-head");
      if (!head) return;
      const cs = window.getComputedStyle(head);
      const pb = parseFloat(cs.paddingBottom || "0");
      const pt = parseFloat(cs.paddingTop || "0");
      grid.style.setProperty("--tower-head-h", (maxInner + pt + pb) + "px");
    };
    measure();
    const ro = new ResizeObserver(measure);
    const grid = matrixGridRef.current;
    if (grid) {
      ro.observe(grid);
      grid.querySelectorAll(".r-tower-head-inner").forEach(el => ro.observe(el));
    }
    return () => ro.disconnect();
  });
  const baseFloor = density === "compact" ? 54 : 64;
  // Compact density: bucket "mobile" / "narrow" via the shared breakpoint hook
  // (single source of truth for width). Short-landscape (vh<640) keeps its
  // own fallback because height-axis bucketing isn't expressed in data-bp.
  const compact = bp === "mobile" || bp === "narrow" || vh < 640;
  // The offerings' own header bar (68) shows only where the filters are a drawer (header.jsx).
  const mainHead = bp === "drawer" || bp === "mobile" || bp === "narrow" ? 68 : 0;
  // Non-floor vertical budget: main header + matrix body padding + tower header + bottom spacer.
  // Compact: header(68) + body pt(10) + tower-head real(~277 incl mb) + plinth(43) + grid pb(8) + scroll pb(12) + 15px viewport-bottom gap = 433.
  const nonFloorBudget = compact ? 433 - 68 + mainHead : (mainHead + 48 + 155 + 64);
  // One row per tier in TIER_ORDER. Non-compact head is dynamic, so its budget
  // leaves one floor's worth of slack (see nTiers below).
  // Budget divisor follows the tier count: compact packs n floors into the
  // budget, non-compact leaves one floor's worth of slack. Was hardcoded 4 / 5.
  const nTiers = TIER_ORDER.length;
  const maxFloor = compact ? Math.floor((vh - nonFloorBudget) / nTiers) : Math.floor((vh - nonFloorBudget) / (nTiers + 1));
  // Floor cells need ~58px min; let them grow to fill the viewport up to a generous cap.
  // Desktop cap raised so floors absorb whitespace below them instead of leaving a gap below the plinth.
  const floorCap = compact ? 160 : (density === "compact" ? 92 : 150);
  const floorH = Math.max(58, Math.min(floorCap, maxFloor));
  // Tower-head height absorbs whatever vertical space the matrix tiers didn't
  // claim, so the page fills the viewport. One floor cell per tier in TIER_ORDER
  // + a ~43px plinth bar + ~30px tower top/bottom margins, sitting under the
  // 68px main header. This used to hardcode 4 floors; retiring a tier then left
  // one floor's worth of dead space below the towers.
  const headMin = compact ? 280 : 260;
  const headMax = compact ? 620 : 560;
  const towerHeadH = Math.max(
    headMin,
    Math.min(headMax, vh - mainHead - 45 - 43 - nTiers * floorH)
  );
  const cellMode = vh >= 720 ? "roomy" : vh >= 600 ? "dense" : "tight";
  const bodyRef = useRef(null);
  const scrollWrapperRef = useRef(null);

  // Arrow-key navigation between focused floors
  const onMatrixKeyDown = (e) => {
    const tgt = e.target.closest("[data-floor]");
    if (!tgt) return;
    const [c, r] = tgt.getAttribute("data-floor").split(":").map(Number);
    let nc = c, nr = r;
    if (e.key === "ArrowUp") nr = r - 1;
    else if (e.key === "ArrowDown") nr = r + 1;
    else if (e.key === "ArrowLeft") nc = c - 1;
    else if (e.key === "ArrowRight") nc = c + 1;
    else if (e.key === "Home") { nc = 0; nr = 0; }
    else if (e.key === "End") { nc = visibleCols.length - 1; nr = TIER_ORDER.length - 1; }
    else return;
    e.preventDefault();
    // Find nearest existing floor (skip gaps)
    const findCell = (col, row) => bodyRef.current?.querySelector(`[data-floor="${col}:${row}"]`);
    let next = findCell(nc, nr);
    // If target missing (gap cell), step further in same direction up to grid edge
    if (!next && e.key === "ArrowUp") { while (nr > 0 && !next) { nr--; next = findCell(nc, nr); } }
    if (!next && e.key === "ArrowDown") { while (nr < TIER_ORDER.length - 1 && !next) { nr++; next = findCell(nc, nr); } }
    if (!next && e.key === "ArrowLeft") { while (nc > 0 && !next) { nc--; next = findCell(nc, nr); } }
    if (!next && e.key === "ArrowRight") { while (nc < visibleCols.length - 1 && !next) { nc++; next = findCell(nc, nr); } }
    next?.focus();
  };

  return (
    <div ref={bodyRef} onKeyDown={onMatrixKeyDown} className="r-matrix-body">
      <div ref={scrollWrapperRef} className="r-matrix-scroll">
      <div ref={matrixGridRef} className="r-matrix-grid" data-cell-mode={cellMode} style={{ "--floor-h": floorH + "px" }}>
        {/* Legend column on the left — tier rows only; flush to page edge with inner padding.
            Sticky-left so it pins to the viewport whenever the matrix-scroll wrapper
            overflows horizontally (small desktop and mobile). */}
        <div className="r-legend-col" style={{ borderRight: `1px dashed ${border}`, background: dark ? "#0D0D0D" : "#FAF7F3" }}>
          {/* Spacer structurally mirrors .r-tower-head (same min-height and
              margin-bottom via --tower-head-h / --tower-head-mb CSS vars),
              so legend tier rows always sit at the same Y as tower floors. */}
          <div className="r-legend-head-spacer">
            {t && t.denominationNote ? <p className="r-legend-note">{t.denominationNote.replace(/\n/g, " ")}</p> : null}
          </div>
          <div className="r-legend-tiers">
            {TIER_ORDER.map((tier, idxFromTop) => {
              const isLast = idxFromTop === TIER_ORDER.length - 1;
              return (
                <div key={tier}
                  onMouseEnter={() => { const root = bodyRef.current; if (root) root.setAttribute("data-tier-hover", tier); }}
                  onMouseLeave={() => { const root = bodyRef.current; if (root) root.removeAttribute("data-tier-hover"); }}
                  data-tier-row={tier}
                  className="r-legend-tier-row"
                  style={{
                    borderBottom: isLast ? "none" : `1px dashed ${border}`,
                  }}>
                  <div className="r-legend-tier-text">
                    <div className="r-legend-tier-label" style={{ color: text }}>
                      {TIER_LABELS[tier][lang]}
                    </div>
                    <div className="r-legend-tier-micro" style={{ color: muted }}>
                      {TIER_MICRO[tier][lang]}
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
          <div className="r-legend-foot"/>
        </div>

        {/* Towers */}
        {visibleCols.length === 0 && (
          <div style={{
            flex: 1, minHeight: 320, minWidth: 280,
            display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 16,
            color: muted, textAlign: "center", padding: "40px 24px",
            border: `1px dashed ${border}`,
          }}>
            <svg width="56" height="56" viewBox="0 0 56 56" fill="none" aria-hidden="true" style={{ opacity: 0.55 }}>
              <rect x="8" y="14" width="40" height="36" stroke={muted} strokeWidth="1.2" fill="none"/>
              <path d="M8 22h40M8 30h40M8 38h40" stroke={muted} strokeWidth="1" strokeDasharray="3 3"/>
              <circle cx="42" cy="14" r="7" fill={dark ? "#1A1817" : "#FAF7F3"} stroke={muted} strokeWidth="1.2"/>
              <path d="M39 14 L41.2 16.2 L45 12.5" stroke={muted} strokeWidth="1.3" fill="none" strokeLinecap="square"/>
            </svg>
            <div style={{ fontFamily: "var(--font-display)", fontSize: 22, color: text, letterSpacing: "-0.015em", lineHeight: 1.15, maxWidth: 320 }}>
              {t.noDealsFilter}
            </div>
            <div style={{ fontSize: 12.5, color: muted, lineHeight: 1.5, maxWidth: 340 }}>
              {t.noDealsFilterHelp}
            </div>
            <div style={{ display: "flex", gap: 8, flexWrap: "wrap", justifyContent: "center", marginTop: 6 }}>
              {statusFilter && statusFilter !== "all" && onClearStatus && (
                <button onClick={onClearStatus} style={{
                  padding: "8px 14px",
                  border: `1px solid ${text}`, background: text, color: dark ? "#1A1817" : "#FAF7F3",
                  fontFamily: "var(--font-mono)", fontSize: 10.5, letterSpacing: "0.14em", textTransform: "uppercase",
                  cursor: "pointer",
                }}>{t.showAll}</button>
              )}
              {hideIneligible && onSetHideIneligible && (
                <button onClick={() => onSetHideIneligible(false)} style={{
                  padding: "8px 14px",
                  border: `1px solid ${border}`, background: "transparent", color: text,
                  fontFamily: "var(--font-mono)", fontSize: 10.5, letterSpacing: "0.14em", textTransform: "uppercase",
                  cursor: "pointer",
                }}>{t.showMismatchesToo}</button>
              )}
            </div>
          </div>
        )}
        {visibleCols.map((col, i) => (
          <Tower key={col.name} col={col} floorH={floorH}
            t={t} lang={lang} dark={dark}
            selectedId={selectedId}
            onSelectProduct={onSelectProduct}
            highlight={highlight}
            colIndex={i}
            towerHeadH={towerHeadH}
            cellMode={cellMode}
            mutedTiers={mutedTiers}
          />
        ))}
      </div>
      </div>

      {false && <LegendStrip t={t} lang={lang} dark={dark} hideIneligible={hideIneligible} onSetHideIneligible={onSetHideIneligible} position="bottom"/>}

    </div>
  );
}

function LegendStrip({ t, lang, dark, hideIneligible, onSetHideIneligible, position }) {
  const text = dark ? "#FAF7F3" : "#393433";
  const muted = dark ? "#8A827F" : "#6B6361";
  const border = dark ? "#2A2825" : "#E2E0DF";
  const faint = dark ? "#5A5654" : "#C1C1C1";

  const lime = "#EDFE38";
  const limeDim = dark ? "#2A2A1A" : "#F0F0C0";

  const [hover, setHover] = useState(null);

  // When hovering a legend token, temporarily dim non-matching cells via CSS attribute on body root
  useEffect(() => {
    const root = document.querySelector(".r-matrix-body");
    if (!root) return;
    root.setAttribute("data-legend-hover", hover || "");
    return () => root.removeAttribute("data-legend-hover");
  }, [hover]);

  const items = [
    {
      key: "lit",
      label: t.legendLit,
      swatch: (
        <span style={{
          width: 16, height: 10,
          background: lime, border: `1px solid ${dark ? "#7A7818" : "#9C9A18"}`,
          display: "inline-block",
        }}/>
      ),
      click: () => onSetHideIneligible && onSetHideIneligible(!hideIneligible),
      active: hideIneligible,
      cta: hideIneligible ? t.showAll : t.hideIneligible,
    },
    {
      key: "gray",
      label: t.legendGray,
      swatch: (
        <span style={{
          width: 16, height: 10,
          background: dark ? "#1F1D1B" : "#FFFFFF", border: `1px solid ${border}`,
          display: "inline-block",
        }}/>
      ),
    },
    {
      key: "empty",
      label: t.legendEmpty,
      swatch: (
        <span style={{
          width: 16, height: 10,
          background: `repeating-linear-gradient(45deg, transparent 0 3px, ${dark ? "#1A1817" : "#F1EDE8"} 3px 6px)`,
          border: `1px solid ${border}`,
          display: "inline-block",
        }}/>
      ),
    },
  ];

  return (
    <>
      <style>{`
        .r-matrix-body[data-legend-hover="lit"]   .r-floor:not(.r-floor-lit) { opacity: 0.25; transition: opacity 180ms; }
        .r-matrix-body[data-legend-hover="lit"]   .r-floor.r-floor-lit { opacity: 1; transition: opacity 180ms; }
        .r-matrix-body[data-legend-hover="gray"]  .r-floor.r-floor-lit { opacity: 0.25; transition: opacity 180ms; }
        .r-matrix-body[data-legend-hover="gray"]  .r-floor:not(.r-floor-lit) { opacity: 1; transition: opacity 180ms; }
        .r-matrix-body[data-tier-hover] .r-floor { opacity: 0.22; transition: opacity 160ms; }
        .r-matrix-body[data-tier-hover="senior-debt"]   .r-floor[data-tier="senior-debt"]   { opacity: 1; }
        .r-matrix-body[data-tier-hover="mezzanine"]     .r-floor[data-tier="mezzanine"]     { opacity: 1; }
        .r-matrix-body[data-tier-hover="preferred-equity"] .r-floor[data-tier="preferred-equity"] { opacity: 1; }
        .r-matrix-body[data-tier-hover="common-equity"]    .r-floor[data-tier="common-equity"]    { opacity: 1; }
        .r-matrix-body[data-tier-hover="lp-syndicate"]     .r-floor[data-tier="lp-syndicate"]     { opacity: 1; }
      `}</style>
      <div style={{
        display: "flex", alignItems: "center", gap: 16, flexWrap: "wrap",
        position: "fixed", bottom: 16, right: 16, zIndex: 30,
        padding: "10px 14px",
        background: dark ? "rgba(26,24,23,0.92)" : "rgba(250,247,243,0.92)",
        backdropFilter: "blur(6px)",
        border: `1px solid ${border}`,
        boxShadow: "0 4px 16px rgba(0,0,0,0.08)",
      }}>
        <span style={{ fontFamily: "var(--font-mono)", fontSize: 9, letterSpacing: "0.18em", textTransform: "uppercase", color: muted }}>
          {t.legend}
        </span>
        {items.map(it => (
          <span key={it.key}
            onMouseEnter={() => setHover(it.key)}
            onMouseLeave={() => setHover(null)}
            onFocus={() => setHover(it.key)}
            onBlur={() => setHover(null)}
            onClick={it.click}
            role={it.click ? "button" : undefined}
            tabIndex={it.click ? 0 : undefined}
            onKeyDown={it.click ? (e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); it.click(); } } : undefined}
            style={{
              display: "inline-flex", alignItems: "center", gap: 8,
              padding: "5px 8px",
              border: `1px solid ${it.active ? text : "transparent"}`,
              background: it.active ? (dark ? "#22201E" : "#F6F2EC") : "transparent",
              cursor: it.click ? "pointer" : "default",
              transition: "background 150ms, border-color 150ms",
            }}>
            {it.swatch}
            <span style={{ fontSize: 11, color: text, letterSpacing: "-0.005em" }}>
              {it.label}
            </span>
            {it.cta && (
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 9, letterSpacing: "0.12em", textTransform: "uppercase", color: muted, paddingLeft: 6, borderLeft: `1px solid ${border}` }}>
                {it.cta}
              </span>
            )}
          </span>
        ))}
      </div>
    </>
  );
}


window.MatrixC = MatrixC;
