/* FindMyFrag — Breaches ledger.
   The flip side of /refusals. When the site violates one of its 11 rules,
   the incident is recorded here with timestamp, duration, reader-impact,
   and resolution. Auto-populated from FMF.CHANGELOG (kind === "breach").
   First-class surface — not buried in a changelog. */

/* global React, FMF */

function Breaches() {
  const breaches = (FMF.CHANGELOG || []).filter(e => e.kind === "breach");
  const totalCost = breaches.reduce((sum, b) => sum + (b.costUsd || 0), 0);
  const lastBreachIso = breaches[0]?.iso;
  const daysSinceLast = lastBreachIso ? daysBetween(lastBreachIso, todayIso()) : null;

  return (
    <main>
      {/* Masthead */}
      <section className="container" style={{ paddingTop: 28, paddingBottom: 14 }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
          <div className="kicker">Transparency · breach ledger</div>
          <div className="mono body-xs" style={{ color: "var(--ink-mute)" }}>
            v4.2 · last revised 14 Apr 2026 · signed · <a href="#/refusals">see refusals</a>
          </div>
        </div>
      </section>
      <hr className="hairline-k" />

      {/* Cover */}
      <section className="container" style={{ padding: "64px 32px 48px" }}>
        <div className="stack-mobile" style={{ display: "grid", gridTemplateColumns: "1.05fr 0.85fr", gap: 72, alignItems: "end" }}>
          <h1 className="display-xxl" style={{ margin: 0, maxWidth: "12ch" }}>
            What <span className="fraun-itl">we broke</span>.
          </h1>
          <div>
            <p className="fraun" style={{ fontSize: 22, lineHeight: 1.4, letterSpacing: "-0.01em", margin: 0, color: "var(--ink-soft)", maxWidth: "40ch" }}>
              Every violation of the 11 refusals is recorded here within 72 hours.
              Duration, reader cost, resolution. Signed, dated, permanent.
            </p>
            <p className="mono body-s" style={{ marginTop: 22, color: "var(--ink-mute)", lineHeight: 1.7 }}>
              The refusals are the algorithm<Cite n={7} check="separated" />.
              {" "}This page is what happens when the algorithm fails. We never move this log behind a paywall<Cite n={12} check="free" />.
            </p>
          </div>
        </div>
      </section>

      <hr className="hairline" />

      {/* Stats strip — the surface tells you instantly how honest the site has been */}
      <section className="container" style={{ padding: "40px 32px 24px" }}>
        <div className="stack-mobile" style={{
          display: "grid",
          gridTemplateColumns: "1fr 1fr 1fr 1fr",
          gap: 40,
          borderTop: "1px solid var(--ink)",
          borderBottom: "1px solid var(--ink)",
          padding: "28px 0",
        }}>
          <StatCell label="Breaches · total"      big={breaches.length}                      meta="since 3 Nov 2024" />
          <StatCell label="Reader cost · total"   big={FMF.fmtUsdNoCents(totalCost)}         meta="dollars impacted" />
          <StatCell label="Days since last"       big={daysSinceLast ?? "—"}                 meta={breaches[0] ? `§${breaches[0].refusalN} · ${breaches[0].date}` : "no breaches on record"} />
          <StatCell label="Refusals in force"     big={FMF.REFUSALS.length}                   meta="signed, dated, auditable" />
        </div>
      </section>

      {/* Breach list */}
      <section className="container" style={{ padding: "20px 32px 48px" }}>
        <div className="kicker" style={{ marginBottom: 28 }}>
          {breaches.length === 0 ? "Clean record" : `On record · ${breaches.length} breach${breaches.length === 1 ? "" : "es"}`}
        </div>
        {breaches.length === 0 ? (
          <div className="fraun" style={{ fontSize: 34, color: "var(--ink-soft)", lineHeight: 1.4, maxWidth: "30ch", margin: "40px 0" }}>
            No breaches <span className="fraun-itl">on record</span>.
            <div className="mono body-s" style={{ color: "var(--ink-mute)", marginTop: 20, letterSpacing: "0.04em" }}>
              This page will auto-populate the next time we fail.
            </div>
          </div>
        ) : (
          <ol style={{ listStyle: "none", padding: 0, margin: 0 }}>
            {breaches.map((b, i) => <BreachCard key={b.iso || b.date} idx={i} b={b} />)}
          </ol>
        )}
      </section>

      <hr className="hairline-k" />

      {/* Footer note — return to the rules */}
      <section className="container" style={{ padding: "40px 32px 56px" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", gap: 32, flexWrap: "wrap" }}>
          <p className="fraun" style={{ fontSize: 22, lineHeight: 1.4, color: "var(--ink-soft)", margin: 0, maxWidth: "52ch" }}>
            Every breach is adjudicated against the refusals list in force at the time of the violation.
            Rollbacks, tests, and resolutions are required within 72 hours.
          </p>
          <a href="#/refusals" className="mono body-s" style={{ color: "var(--ink)", textDecoration: "none", borderBottom: "1px solid var(--ink)", paddingBottom: 2 }}>
            The eleven things we refuse to do →
          </a>
        </div>
      </section>
    </main>
  );
}

/* A big stat cell for the breach-ledger overview. Editorial, not dashboard. */
function StatCell({ label, big, meta }) {
  return (
    <div>
      <div className="kicker" style={{ marginBottom: 10 }}>{label}</div>
      <div className="fraun" style={{ fontSize: 52, letterSpacing: "-0.025em", lineHeight: 1, color: "var(--ink)" }}>
        {big}
      </div>
      <div className="mono body-xs" style={{ color: "var(--ink-mute)", marginTop: 10, letterSpacing: "0.04em" }}>
        {meta}
      </div>
    </div>
  );
}

/* A breach row — oxblood top rule, structured right-column ledger. */
function BreachCard({ idx, b }) {
  const refusal = FMF.refusalByN(b.refusalN);
  return (
    <li className="stack-mobile" style={{
      display: "grid",
      gridTemplateColumns: "80px 1fr 280px",
      gap: 32,
      padding: "36px 0",
      borderTop: "2px solid var(--oxblood)",
    }}>
      <div className="mono" style={{ fontSize: 22, color: "var(--oxblood-ink)" }}>
        {String(idx + 1).padStart(2, "0")}
      </div>
      <div>
        <div style={{ display: "flex", alignItems: "baseline", gap: 14, marginBottom: 16, flexWrap: "wrap" }}>
          <span className="chip chip-ox">Breach</span>
          <span className="mono body-xs" style={{ color: "var(--ink-mute)", letterSpacing: "0.08em", textTransform: "uppercase" }}>
            {b.date}
          </span>
          {refusal && (
            <a href={`#/refusals#${refusal.id}`} className="mono body-xs" style={{ color: "var(--oxblood-ink)", letterSpacing: "0.04em", borderBottom: "1px solid var(--oxblood)", paddingBottom: 1 }}>
              §{b.refusalN} — {refusal.title.replace(/\.$/, "")}
            </a>
          )}
        </div>
        <div className="fraun" style={{ fontSize: 24, lineHeight: 1.35, color: "var(--ink)", marginBottom: 14, letterSpacing: "-0.01em" }}>
          {b.summary}
        </div>
        <div className="body-m" style={{ color: "var(--ink-soft)", maxWidth: "60ch" }}>
          {b.resolution}
        </div>
      </div>
      <div style={{ fontFamily: "var(--font-mono)", fontSize: 12, lineHeight: 1.8, color: "var(--ink-mute)" }}>
        <LedgerRow k="duration"       v={`${b.durationMin} min`} />
        <LedgerRow k="reader cost"    v={FMF.fmtUsdNoCents(b.costUsd || 0)} />
        <LedgerRow k="rule cited"     v={`§${b.refusalN}`} />
        <LedgerRow k="logged within"  v="72 hours" />
        <LedgerRow k="status"         v="closed" />
      </div>
    </li>
  );
}

function LedgerRow({ k, v }) {
  return (
    <div style={{ display: "flex", justifyContent: "space-between", borderTop: "1px solid var(--rule)", padding: "6px 0" }}>
      <span>{k}</span>
      <span style={{ color: "var(--ink)" }}>{v}</span>
    </div>
  );
}

function todayIso() {
  const d = new Date();
  return d.toISOString().slice(0, 10);
}

function daysBetween(a, b) {
  const ms = new Date(b).getTime() - new Date(a).getTime();
  return isNaN(ms) ? null : Math.max(0, Math.floor(ms / (1000 * 60 * 60 * 24)));
}

Object.assign(window, { Breaches });
