// app.jsx — root component: sidebar nav + page header + tweaks panel + router

const { useState: aState, useEffect: aEffect, useMemo } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "density": "comfortable",
  "accent": "pine"
}/*EDITMODE-END*/;

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  // Phase 4 wiring: db starts null and is populated by a live fetch (below),
  // replacing the old `aState(() => window.MOCK)`.
  const [db, setDb] = aState(null);
  const [loadError, setLoadError] = aState(null);
  const [route, setRoute] = aState({ screen: "forecast" });
  const { push, Toasts } = useToasts();

  // Apply density + accent to root
  aEffect(() => {
    document.documentElement.dataset.density = t.density;
    document.documentElement.dataset.accent = t.accent;
  }, [t.density, t.accent]);

  // Phase 4 data load — fetch the live dataset, re-attach the cat() helper
  // exactly the way data.js did, mirror it onto window.MOCK so CategoryChip
  // keeps working, then setDb. (See build plan §3a / §4.)
  aEffect(() => {
    let cancelled = false;
    ViewerAPI.load()
      .then(data => {
        if (cancelled) return;
        data.cat = (id) => data.categories.find(c => c.id === id)
                           || { id, label: id, schedC: "" };
        window.MOCK = data;          // CategoryChip reads window.MOCK.cat
        setDb(data);
      })
      .catch(err => {
        if (cancelled) return;
        setLoadError(err && err.message || "failed to load bookkeeping data");
      });
    return () => { cancelled = true; };
  }, []);

  // Sidebar counts. This useMemo must run on EVERY render (Rules of Hooks),
  // so it sits ABOVE the loading guard and returns zeros while db is still
  // null — the guard below handles the actual not-loaded UI.
  const counts = useMemo(() => {
    if (!db) return { diag: 0, lowWeeks: 0, receivables: 0, txns: 0 };
    const unpairedR = db.receipts.filter(r => !db.transactions.some(t => t.receiptId === r.id)).length;
    const unpairedT = db.transactions.filter(t => !t.receiptId && t.amount < 0).length;
    const reviewT  = db.transactions.filter(t => t.needsReview).length;
    const lowWeeks = db.forecast.weeks.filter(w => w.below).length;
    return {
      diag: unpairedR + unpairedT + reviewT,
      lowWeeks,
      receivables: db.receivables.length,
      txns: db.transactions.length,
    };
  }, [db]);

  // Loading / error guard — screens and headFor() dereference db.transactions
  // etc. synchronously, so do not render the app shell until db is populated.
  // All hooks above this line run unconditionally; nothing below may be a hook.
  if (!db) {
    return (
      <div className="app-load">
        <div className="load-card">
          <div className="logo">EF</div>
          {loadError ? (
            <>
              <h2>Couldn't load the books</h2>
              <p>The viewer reached the Phase 4 backend but the request failed.</p>
              <div className="err-msg">{loadError}</div>
              <button className="btn" onClick={() => window.location.reload()}>
                <Icon name="refresh" size={12} /> Retry
              </button>
            </>
          ) : (
            <>
              <div className="spinner" />
              <h2>Loading bookkeeping data…</h2>
              <p>Fetching the live ledger from the Pi.</p>
            </>
          )}
        </div>
      </div>
    );
  }

  const navTo = (r) => {
    setRoute(r);
    // If route requests transactions with filters, attach as initial
    if (r.screen === "transactions" && (r.filterCat || r.filterMonth)) {
      // We'll thread through via route props (handled by TransactionsScreen via key)
    }
    window.scrollTo({ top: 0, behavior: "instant" });
  };
  // headFor()'s txn crumb reaches navTo through this global (it is built
  // outside the component); expose it so the breadcrumb link works.
  window.__navTo = navTo;

  // Page header content per screen
  const head = headFor(route, db);

  return (
    <div className="app">
      <aside className="sidebar">
        <div className="brand">
          <div className="logo">EF</div>
          <div>
            <div className="name">Exquisite Finishing</div>
            <div className="sub">Loveland, CO · Bookkeeping</div>
          </div>
        </div>
        <nav className="nav">
          <NavItem icon="forecast" label="Cash flow forecast" active={route.screen === "forecast"} onClick={() => navTo({ screen: "forecast" })}
            count={counts.lowWeeks ? `${counts.lowWeeks} low` : null} countWarn={!!counts.lowWeeks}/>
          <NavItem icon="list" label="Transactions" active={route.screen === "transactions"} onClick={() => navTo({ screen: "transactions" })}
            count={counts.txns}/>
          <NavItem icon="diagnostics" label="Diagnostics" active={route.screen === "diagnostics"} onClick={() => navTo({ screen: "diagnostics" })}
            count={counts.diag || null} countWarn={!!counts.diag}/>
          <NavItem icon="receipt" label="Receivables" active={route.screen === "receivables"} onClick={() => navTo({ screen: "receivables" })}
            count={counts.receivables}/>
          <NavItem icon="schedule" label="Schedule C summary" active={route.screen === "schedC"} onClick={() => navTo({ screen: "schedC" })}/>
        </nav>
        <div className="sidebar-foot">
          <div><span className="dot"></span>SQLite · synced 4m ago</div>
          <div>Pi @ 192.168.1.42 · v0.4-beta</div>
          <div>Today: {fmtDate(db.today)}, 2026</div>
        </div>
      </aside>

      <main className="main">
        <header className="page-head">
          <div>
            {head.crumbs && (
              <div className="crumbs">
                <a onClick={() => navTo(head.back || { screen: "forecast" })}><Icon name="arrowLeft" size={11} /></a>
                {head.crumbs.map((c, i) => (
                  <React.Fragment key={i}>
                    {i > 0 && <span>/</span>}
                    {c.onClick ? <a onClick={c.onClick}>{c.label}</a> : <span>{c.label}</span>}
                  </React.Fragment>
                ))}
              </div>
            )}
            <h1>{head.title}</h1>
            {head.subtitle && <div className="tiny muted" style={{ marginTop: 2 }}>{head.subtitle}</div>}
          </div>
          <div className="actions">
            {head.actions}
          </div>
        </header>

        <div>
          {route.screen === "forecast"     && <ForecastScreen        db={db} setDb={setDb} push={push} />}
          {route.screen === "transactions" && <TransactionsScreen    key={(route.filterCat||"")+(route.filterMonth||"")} db={db} setDb={setDb} navTo={navTo} push={push}
                                                                      initialFilter={{ category: route.filterCat, month: route.filterMonth }} />}
          {route.screen === "txn"          && <TransactionDetailScreen db={db} setDb={setDb} navTo={navTo} txnId={route.id} push={push} />}
          {route.screen === "receipt"      && <ReceiptDetailScreen   db={db} setDb={setDb} navTo={navTo} receiptId={route.id} push={push} />}
          {route.screen === "diagnostics"  && <DiagnosticsScreen     db={db} setDb={setDb} navTo={navTo} push={push} />}
          {route.screen === "receivables"  && <ReceivablesScreen     db={db} setDb={setDb} push={push} />}
          {route.screen === "schedC"       && <ScheduleCScreen       db={db} navTo={navTo} />}
        </div>
      </main>

      <Toasts />

      <TweaksPanel>
        <TweakSection label="Layout" />
        <TweakRadio
          label="Density"
          value={t.density}
          options={["comfortable", "compact"]}
          onChange={v => setTweak("density", v)}
        />
        <TweakSection label="Accent" />
        <TweakRadio
          label="Color"
          value={t.accent}
          options={["pine", "workshop", "indigo"]}
          onChange={v => setTweak("accent", v)}
        />
        <div style={{ marginTop: 8, padding: "8px 10px", borderRadius: 6, background: "rgba(0,0,0,.03)", fontSize: 11, color: "var(--ink-2)", lineHeight: 1.45 }}>
          This viewer is wired to the live Phase 4 backend. Editing the starting balance, re-categorizing transactions, pairing receipts, and shifting receivable dates write to the real bookkeeping.db.
        </div>
      </TweaksPanel>
    </div>
  );
}

function NavItem({ icon, label, active, onClick, count, countWarn }) {
  return (
    <div className={"nav-item" + (active ? " active" : "")} onClick={onClick}>
      <Icon name={icon} />
      <span>{label}</span>
      {count != null && (
        <span className="count" style={countWarn ? { color: "var(--warning)", fontWeight: 600 } : null}>{count}</span>
      )}
    </div>
  );
}

function headFor(route, db) {
  switch (route.screen) {
    case "forecast":
      return {
        title: "13-week cash flow forecast",
        subtitle: "Rolling projection from this Monday. Click any week column or bar to see what's in it.",
        actions: <>
          <button className="btn"><Icon name="refresh" size={12} /> Recompute</button>
          <button className="btn primary"><Icon name="download" size={12} /> Export</button>
        </>,
      };
    case "transactions":
      return {
        title: "Transactions",
        subtitle: `${db.transactions.length} entries across the last 3 months · bank + Jobber + Wix combined.`,
        actions: <>
          <button className="btn"><Icon name="download" size={12} /> Export CSV</button>
          <button className="btn primary" onClick={() => { window.__openManualEntry && window.__openManualEntry(); }}><Icon name="plus" size={12} /> Add manual entry</button>
        </>,
      };
    case "txn": {
      const t = db.transactions.find(x => x.id === route.id);
      return {
        title: t ? t.description : "Transaction",
        subtitle: t ? `${fmtDateLong(t.date)} · ${t.id}` : "",
        crumbs: [{ label: "Transactions", onClick: () => { window.__navTo && window.__navTo({ screen: "transactions" }); } }, { label: t ? t.id : "" }],
        back: { screen: "transactions" },
      };
    }
    case "receipt": {
      const r = db.receipts.find(x => x.id === route.id);
      return {
        title: r ? r.vendorShort : "Receipt",
        subtitle: r ? `${fmtDateLong(r.date)} · ${r.id} · ${r.arrival === "phone-snap" ? "Phone snap" : "Emailed PDF"}` : "",
        crumbs: [{ label: "Receipts" }, { label: r ? r.id : "" }],
        back: { screen: "transactions" },
      };
    }
    case "diagnostics":
      return {
        title: "Diagnostics",
        subtitle: "Unpaired items and anything flagged for review. Resolve here, weekly.",
      };
    case "receivables":
      return {
        title: "Receivables",
        subtitle: "Open invoices from Jobber and Wix. Adjusting an expected pay date updates the forecast.",
      };
    case "schedC":
      return {
        title: "Schedule C summary",
        subtitle: "Expense categories rolled up for tax-prep. Pulls from the visible transactions.",
        actions: null,
      };
    default:
      return { title: "Bookkeeping" };
  }
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
