/* Ledger home (formerly "Newsroom"; relabelled 2026-09-18, route id and
   window.LedgerNewsroom kept so links and the mount check don't move) — live dashboard. KPIs + recent matters from the live API.
   Exercises the authenticated read path. Assigns window.LedgerNewsroom

   THE LANE IS A FILTER ON THIS PAGE (2026-09-11). It used to be neither: the tab
   renamed itself to "Worklist" and app.jsx mounted a different component when the
   lane was Police Videos, while these three panels asked for data with no lane at
   all — so pressing the chip replaced the page and narrowed nothing on it. Now the
   page is always the Newsroom, and every panel below inherits the scope the same
   way Matters and Search always have. */
(function () {
  // Today's coverage is a reading surface on a dashboard, not a desk. Ten rows is
  // about a screen.
  //
  // WHAT IT SHOWS (operator, 2026-09-18): matters we are COVERING — coverage_status
  // `assigned` — with a checkbox to add the ones we are only `monitoring`. The
  // unfiltered board was 46 events on 2026-09-18, 39 of them monitoring, so the
  // seven we are actually covering were buried under the ones we are not.
  //
  // PAGED IN THE BROWSER, on purpose. event_time is COURT-LOCAL, so the database's
  // ORDER BY event_time puts an 8:30 PT hearing (11:30 ET) ahead of a 9:00 ET one.
  // The right order only exists after conversion to Eastern, which needs the whole
  // day. One day is bounded (~50 events at most so far), so fetching it and paging
  // here costs little and is the only way the order is correct across pages.
  const TODAY_PAGE = 10;
  const COVERAGE_ASSIGNED = ["assigned"];
  const COVERAGE_WITH_MONITORING = ["assigned", "monitoring"];
  // The checkbox is sticky per browser; storage can be missing (private mode).
  const MON_KEY = "ledger.home.includeMonitoring";
  const readMon = () => { try { return window.localStorage.getItem(MON_KEY) === "1"; } catch { return false; } };
  const writeMon = (v) => { try { window.localStorage.setItem(MON_KEY, v ? "1" : "0"); } catch {} };
  // The top tiles open on Today (B6); "This month" is the earlier set with month-over-month.
  const VIEW_KEY = "ledger.home.tiles";
  const readView = () => { try { return window.localStorage.getItem(VIEW_KEY) === "month" ? "month" : "today"; } catch { return "today"; } };
  const writeView = (v) => { try { window.localStorage.setItem(VIEW_KEY, v); } catch {} };

  function Newsroom({ onOpenMatter, onNew, onNav, lane }) {
    const { StatTile, Card, Button } = window.LawCrimeDesignSystem_e18d68;
    const [kpis, setKpis] = React.useState(null);
    const [matters, setMatters] = React.useState(null);
    const [todayAll, setTodayAll] = React.useState(null); // today's board, whole day, ET-sorted
    const [todayPage, setTodayPage] = React.useState(0);
    const [withMonitoring, setWithMonitoring] = React.useState(readMon);
    const [tileView, setTileView] = React.useState(readView);
    const [intake, setIntake] = React.useState(null);
    const [err, setErr] = React.useState(null);

    // A lane change is a different question, so it starts at the first page — the
    // alternative is landing on page 3 of a one-page board and reading it as empty.
    React.useEffect(() => { setTodayPage(0); }, [lane, withMonitoring]);

    React.useEffect(() => {
      let live = true;
      (async () => {
        try {
          const [k, m] = await Promise.all([
            window.LedgerAPI.kpis(lane),
            // Recent matters only — the list is server-paged now, so ask for 8
            // rather than fetching the table and slicing in the browser.
            window.LedgerAPI.listMatters({ lane, pageSize: 8 }),
          ]);
          if (!live) return;
          setKpis(k);
          setMatters(m.rows);
        } catch (e) { if (live) setErr(e.message || String(e)); }
      })();
      return () => { live = false; };
    }, [lane]);

    // Today's intake tiles (B6): their own load, so a failure leaves the rest of the page.
    React.useEffect(() => {
      let live = true;
      setIntake(null);
      window.LedgerAPI.todayIntake(lane).then((r) => { if (live) setIntake(r); }).catch(() => { if (live) setIntake(false); });
      return () => { live = false; };
    }, [lane]);

    // Today's coverage is non-critical; load it separately so a failure here
    // never blocks the KPIs / recent matters.
    React.useEffect(() => {
      let live = true;
      setTodayAll(null);
      window.LedgerAPI.coverageBoard({
        lane, coverageStatuses: withMonitoring ? COVERAGE_WITH_MONITORING : COVERAGE_ASSIGNED,
        spanning: true,   // a trial that opened earlier in the week is still on today (B6)
      })
        .then((r) => {
          if (!live) return;
          const LT = window.LedgerTime;
          const rows = r.rows.map((e) => ({ ...e, et: LT.toEastern(e.event_date, e.event_time, (e.matters || {}).crime_location_state) }));
          // By Eastern clock time. Untimed events, and times whose court zone is
          // unknown (they cannot be placed on the Eastern clock), go last.
          const etKey = (e) => (e.et && e.et.known ? e.et.minutes : 1e9);
          rows.sort((a, b) => etKey(a) - etKey(b));
          setTodayAll(rows);
        })
        .catch(() => { if (live) setTodayAll([]); });
      return () => { live = false; };
    }, [lane, withMonitoring]);

    const todayTotal = todayAll ? todayAll.length : 0;
    const today = todayAll ? todayAll.slice(todayPage * TODAY_PAGE, (todayPage + 1) * TODAY_PAGE) : null;
    const etAbbr = window.LedgerTime.homeAbbr();
    const todayStr = window.LedgerTime.todayEastern();
    const toggleMonitoring = (v) => { setWithMonitoring(v); writeMon(v); };

    React.useEffect(() => { setTimeout(() => window.lucide && window.lucide.createIcons(), 30); }, [matters, todayAll, todayPage]);

    // Tiles (2026-10-08): see kpis() in api.js for what each one counts and why the
    // old four went. "New" is month to date against the same days of last month.
    const fmtMD = (iso) => window.LedgerTime.fmtDate(iso, { month: "short", day: "numeric" });
    const newDelta = kpis ? (() => {
      const diff = kpis.newMtd - kpis.newPrior;
      const sign = diff > 0 ? "+" : diff < 0 ? "−" : "±";
      // prevEnd is exclusive, so the window's last day is the day before it.
      const [py, pm, pd] = kpis.prevEnd.split("-").map(Number);
      const lastPrev = new Date(Date.UTC(py, pm - 1, pd - 1)).toISOString().slice(0, 10);
      return { text: `${sign}${Math.abs(diff).toLocaleString()} vs ${fmtMD(kpis.prevStart)}–${fmtMD(lastPrev)}`,
               trend: diff > 0 ? "up" : diff < 0 ? "down" : undefined };
    })() : null;
    const n = (v) => (kpis ? Number(v).toLocaleString() : "—");
    // Today (B6): Covering cases in court today by kind, then requests. Same scope as the
    // board below with "Include tracking" off.
    const iv = (v) => (intake ? Number(v).toLocaleString() : "—");
    const todayCells = (window.LEDGER_HOME_INTAKE || []).map((g) => ({
      label: g.label, value: iv(intake && intake.counts[g.key]),
      title: `Cases we are Covering with ${g.types ? g.types.map((t) => window.titleize(t).toLowerCase()).join(", ") : "any other court event"} in session today. Multi-day events count every day they run.`,
    })).concat([{
      label: "New requests · today", value: iv(intake && intake.requestsToday),
      delta: intake ? `${Number(intake.requestsYesterday).toLocaleString()} yesterday` : undefined,
      title: "Asset requests created today (Eastern). Requests made in Airtable reach Ledger with the nightly sync, so today's number fills in overnight.",
    }]);
    const cells = [
      { label: "Covering now", value: n(kpis && kpis.covering), title: "Matters with coverage status Covering." },
      { label: "Court dates · next 7 days", value: n(kpis && kpis.courtDates7), title: "Court events from today through the next six days on matters we are covering. Filing deadlines are left out." },
      { label: "Tracking", value: n(kpis && kpis.monitoring), title: "Matters with coverage status Tracking." },
      { label: kpis ? `New · ${fmtMD(kpis.monthStart)}–${fmtMD(kpis.today)}` : "New this month",
        value: n(kpis && kpis.newMtd), delta: newDelta && newDelta.text, trend: newDelta && newDelta.trend,
        title: "Matters added this month to date (Eastern), compared with the same days of last month." },
    ];

    return (
      <div>
        <div className="page-head">
          <div>
            <div className="eyebrow">Ledger · Live Status</div>
            <h1 className="page-title">Today at Law&amp;Crime<window.LedgerComment section="Ledger" /></h1>
          </div>
          <Button variant="primary" icon="circle-plus" onClick={onNew}>New Matter</Button>
        </div>

        {err && <div className="login__err" style={{ marginBottom: 16 }}>Couldn’t load data: {err}</div>}

        <div className="seg home-tiles-seg" role="group" aria-label="Top figures">
          {[["today", "Today"], ["month", "This month"]].map(([k, l]) => (
            <button key={k} type="button" className={tileView === k ? "seg--on" : ""} aria-pressed={tileView === k}
              onClick={() => { setTileView(k); writeView(k); }}>{l}</button>
          ))}
        </div>
        {tileView === "today" && intake === false && <div className="login__err" style={{ marginBottom: 16 }}>Couldn’t load today’s figures.</div>}
        <div className={"kpis" + (tileView === "today" ? " kpis--5" : "")}>
          {(tileView === "today" ? todayCells : cells).map((c, i) => (
            <div className="cell" key={tileView + i} title={c.title}><StatTile value={String(c.value)} label={c.label} delta={c.delta} trend={c.trend} /></div>
          ))}
        </div>

        <Card style={{ marginBottom: 18 }}>
          {/* RELABELLED 2026-10-08. This panel was "Today's coverage", and the team read
              it as the routing plan. It is not: it is today's court events on matters
              whose coverage status is Assigned (plus Monitoring when ticked). The
              Trial Routing Sheet is the source of truth for what we are actually
              taking; a sheet-backed view is planned under Content Operations. */}
          <Card.Head title={(withMonitoring ? "Today’s court dates · covering or tracking" : "Today’s court dates · cases we’re covering")
            + (todayTotal > TODAY_PAGE
              ? ` · ${todayPage * TODAY_PAGE + 1}–${Math.min((todayPage + 1) * TODAY_PAGE, todayTotal)} of ${todayTotal}`
              : "")}>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 14 }}>
              <label className="cal-keyonly" title="Covering = coverage status Covering. Tick to add matters we are only tracking.">
                <input type="checkbox" checked={withMonitoring} onChange={(e) => toggleMonitoring(e.target.checked)} />
                Include tracking
              </label>
              <Button size="sm" variant="ghost" icon="arrow-right" iconRight onClick={() => onNav && onNav("coverage")}>
                Full board
              </Button>
            </span>
          </Card.Head>
          <Card.Body style={{ padding: 0 }}>
            <div className="home-srcnote">
              From court dates in Ledger. The Trial Routing Sheet is still the source of truth for what we are taking.
            </div>
            {today === null && <div style={{ padding: 20, color: "var(--text-muted)", fontSize: 13 }}>Loading…</div>}
            {today && today.length === 0 && (
              <div className="ledger-empty" style={{ border: "none" }}>
                <i data-lucide="radio-tower" />
                <b>Nothing on today</b>
                {/* Scoped to Police Videos this panel is empty every day, not just
                    today — those matters have no proceeding to schedule. Saying so
                    is the difference between an empty board and a broken one. */}
                <span>{lane === "police_video"
                  ? "Police-video matters have no docket, so no court events are scheduled against them. Switch the lane to Trials to see the board."
                  : withMonitoring
                    ? "No court events scheduled for today."
                    : "Nothing we are covering is in court today. Tick “Include tracking” to see the matters we are watching."}</span>
              </div>
            )}
            {today && today.length > 0 && (
              <table className="tbl">
                <thead><tr><th style={{ width: 96 }}>Time ({etAbbr})</th><th>Matter</th><th>How it comes in</th><th>Feed / photographer</th></tr></thead>
                <tbody>
                  {today.map((e) => {
                    const m = e.matters || {};
                    const how = e.ingest_method ? window.LedgerCoverageUtil.methodShort(e.ingest_method) : "not set";
                    const whereWho = e.feed_location || e.photographer_name || (e.ingest_method ? "—" : "");
                    return (
                      <tr key={e.event_id} onClick={() => onOpenMatter && onOpenMatter(e.matter_id)}>
                        <td className="cdef" style={{ fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" }}
                            title={e.et ? [e.et.courtLabel ? "Court time " + e.et.courtLabel : null, e.et.note].filter(Boolean).join(" · ") || undefined : undefined}>
                          {e.et ? (e.et.known ? e.et.short : <span style={{ color: "var(--text-muted)" }}>{e.et.short} local</span>) : "—"}
                          {e.et && e.et.courtLabel && <span className="row-sub" style={{ marginLeft: 0 }}>{e.et.courtLabel} court</span>}
                        </td>
                        <td className="cname">{m.working_title || "Untitled"}
                          <span className="row-sub" style={{ display: "inline-flex", gap: 6, alignItems: "center", marginLeft: 0 }}>
                            {m.coverage_status ? <window.LedgerCoveragePill status={m.coverage_status} method={e.ingest_method} small /> : null}
                            <span>{e.event_date < todayStr
                              ? `${e.event_type === "trial_start" ? "Trial" : window.titleize(e.event_type)} · in session since ${fmtMD(e.event_date)}`
                              : window.titleize(e.event_type)}</span>
                          </span>
                        </td>
                        <td className="cdef">{e.ingest_method ? <b style={{ color: "var(--text)" }}>{how}</b> : <span style={{ color: "var(--lc-slate-300)" }}>not set</span>}{e.coverage_source === "event" ? " (override)" : ""}</td>
                        <td className="cdef">{whereWho}</td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            )}
            {todayTotal > TODAY_PAGE && (
              <div className="pager pager--incard">
                <span className="pager__count">
                  {todayTotal.toLocaleString()} court event{todayTotal === 1 ? "" : "s"} today{withMonitoring ? "" : " we are covering"}
                </span>
                <span className="pager__nav">
                  <Button size="sm" variant="ghost" icon="chevron-left" disabled={todayPage === 0}
                    onClick={() => setTodayPage((p) => Math.max(0, p - 1))}>Previous</Button>
                  <Button size="sm" variant="ghost" disabled={(todayPage + 1) * TODAY_PAGE >= todayTotal}
                    onClick={() => setTodayPage((p) => p + 1)}>Next</Button>
                </span>
              </div>
            )}
          </Card.Body>
        </Card>

        <Card>
          <Card.Head title="Recent Matters">
            <Button size="sm" variant="ghost" icon="arrow-right" iconRight onClick={() => onOpenMatter()}>
              All matters
            </Button>
          </Card.Head>
          <Card.Body style={{ padding: 0 }}>
            {matters === null && <div style={{ padding: 24, color: "var(--text-muted)", fontSize: 13 }}>Loading…</div>}
            {matters && matters.length === 0 && (
              <div className="ledger-empty" style={{ border: "none" }}>
                <i data-lucide="folder-plus" />
                <b>No matters yet</b>
                <span>Create the first matter to begin the lifecycle.</span>
              </div>
            )}
            {matters && matters.length > 0 && (
              <table className="tbl">
                <thead>
                  <tr><th>Title</th><th>Type</th><th>Legal status</th><th>Tracking</th><th>Jurisdiction</th><th>Updated</th></tr>
                </thead>
                <tbody>
                  {matters.map((m) => (
                    <tr key={m.matter_id} onClick={() => onOpenMatter(m.matter_id)}>
                      <td className="cname">{m.working_title}{m.matter_summary && <span className="row-sub">{m.matter_summary}</span>}</td>
                      <td className="cdef">{window.vocabLabel("matter_type", m.matter_type)}</td>
                      <td className="cdef">{m.legal_status ? window.titleize(m.legal_status) : "—"}</td>
                      <td className="cdef">{m.coverage_status ? <span className={"track track--" + m.coverage_status}>{window.vocabLabel("coverage_status", m.coverage_status)}</span> : "—"}</td>
                      <td className="cdef">{m.crime_location_state || "—"}</td>
                      <td style={{ color: "var(--text-muted)", fontSize: 12.5 }}>
                        {m.updated_at ? new Date(m.updated_at).toLocaleDateString() : "—"}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            )}
          </Card.Body>
        </Card>
      </div>
    );
  }

  window.LedgerNewsroom = Newsroom;
})();
