// Live dashboard — Task 8. Ports the original design prototype into
// components fed by GET /api/c/reports/dashboard (server/src/reports.ts).
// No debit/credit language anywhere (CLAUDE.md §9); every money figure is
// a NUMERIC(19,4) string passed straight through to fmtMoney(), never
// parsed into a JS number.

import { useCallback, useEffect, useState } from "react";
import { apiGet, ApiError } from "./lib/api";
import { fmtDate } from "./lib/date";
import { useCompany } from "./lib/company";
import { HealthChip } from "./components/HealthChip";
import {
  HealthPanel, type BillCountSummary, type OldestReceivable, type WrongSignRow,
  type NeverReconciledRow, type StaleReconciliationRow,
} from "./components/HealthPanel";
import { Tile } from "./components/Tile";
import { BarsChart, type YearRow } from "./components/BarsChart";
import { BalancePanel, type BalanceRow } from "./components/BalancePanel";
import { ActivityList, type ActivityRow } from "./components/ActivityList";
import { ErrorBanner } from "./components/ErrorBanner";
import { DashboardSkeleton } from "./components/DashboardSkeleton";
import type { NavTarget } from "./lib/useHashView";

interface DashboardData {
  health: {
    outOfBalance: string;
    balanced: boolean;
    wrongSign: WrongSignRow[];
    oldestReceivable: OldestReceivable | null;
    overdueBills: BillCountSummary;
    billsDueSoon: BillCountSummary;
    neverReconciled: NeverReconciledRow[];
    staleReconciliation: StaleReconciliationRow[];
    // The inventory milestone's headline invariant, as one number
    // (inventory_out_of_tie) — "0.0000" for a company that keeps no stock.
    inventoryOutOfTie: string;
    inventoryTies: boolean;
  };
  tiles: {
    youHave: string;
    youOwe: string;
    yearMoneyIn: string;
    yearProfit: string;
    netWorth: string;
  };
  years: YearRow[];
  balanceSheet: {
    assets: BalanceRow[];
    liabilities: BalanceRow[];
    equityTotal: string;
  };
  activity: ActivityRow[];
}

export function Dashboard({
  onSelectAccount,
  onSelectEntry,
  navigate,
}: {
  onSelectAccount: (accountId: string) => void;
  onSelectEntry: (entryId: string) => void;
  navigate: (target: NavTarget) => void;
}) {
  const { selectedCompanyId, selectedCompany } = useCompany();
  const [data, setData] = useState<DashboardData | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [reloadToken, setReloadToken] = useState(0);

  const retry = useCallback(() => setReloadToken((n) => n + 1), []);

  useEffect(() => {
    if (!selectedCompanyId) return;
    let cancelled = false;
    setLoading(true);
    setError(null);
    apiGet<DashboardData>("/api/c/reports/dashboard", selectedCompanyId)
      .then((body) => {
        if (!cancelled) setData(body);
      })
      .catch((err: unknown) => {
        if (!cancelled) {
          setError(err instanceof ApiError ? err.message : "Couldn't load the dashboard.");
        }
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, [selectedCompanyId, reloadToken]);

  if (loading && !data) {
    return <DashboardSkeleton />;
  }

  if (error && !data) {
    return (
      <div className="wrap">
        <ErrorBanner message={error} onRetry={retry} />
      </div>
    );
  }

  if (!data) return null;

  const companyName = selectedCompany?.name ?? "Your books";
  const hasHistory = data.years.length > 0;
  const latestDate = data.activity[0]?.date;
  const entryCount = selectedCompany?.entryCount ?? 0;

  return (
    <div className="wrap">
      {error && <ErrorBanner message={error} onRetry={retry} />}

      <header className="top">
        <h1>{companyName}</h1>
        <HealthChip balanced={data.health.balanced} outOfBalance={data.health.outOfBalance} />
        <div className="asof">
          {hasHistory && latestDate
            ? `Complete history · latest entry ${fmtDate(latestDate)} · ${entryCount.toLocaleString()} posted entries · every number below traces to a journal entry`
            : "No history yet"}
        </div>
      </header>

      <div className="tiles">
        <Tile label="You have" amount={data.tiles.youHave} sub="Cash and other assets" />
        <Tile label="You owe" amount={data.tiles.youOwe} sub="Bills and other liabilities" />
        <Tile label={`${new Date().getFullYear()} money in`} amount={data.tiles.yearMoneyIn} sub="Year to date" />
        <Tile label={`${new Date().getFullYear()} kept so far`} amount={data.tiles.yearProfit} sub="Money in minus money out" />
      </div>

      <HealthPanel
        companyId={selectedCompanyId}
        balanced={data.health.balanced}
        outOfBalance={data.health.outOfBalance}
        wrongSign={data.health.wrongSign}
        oldestReceivable={data.health.oldestReceivable}
        overdueBills={data.health.overdueBills}
        billsDueSoon={data.health.billsDueSoon}
        neverReconciled={data.health.neverReconciled}
        staleReconciliation={data.health.staleReconciliation}
        inventoryOutOfTie={data.health.inventoryOutOfTie}
        navigate={navigate}
        onSelectAccount={onSelectAccount}
      />

      {!hasHistory ? (
        <div className="empty-state">
          No entries yet — restore your history from your old software or record your first transaction.
        </div>
      ) : (
        <>
          <div className="card" style={{ marginBottom: 12 }}>
            <h2>Money in vs. money out, by year</h2>
            <div className="sub">Revenue and spending for each calendar year. The current year is year-to-date.</div>
            <div className="legend">
              <span>
                <i className="swatch" style={{ background: "var(--series-1)" }} />
                Money in
              </span>
              <span>
                <i className="swatch" style={{ background: "var(--series-2)" }} />
                Money out
              </span>
            </div>
            <BarsChart years={data.years} />
          </div>

          <div className="grid2">
            <BalancePanel
              assets={data.balanceSheet.assets}
              liabilities={data.balanceSheet.liabilities}
              youHave={data.tiles.youHave}
              youOwe={data.tiles.youOwe}
              netWorth={data.tiles.netWorth}
              onSelectAccount={onSelectAccount}
            />
            <ActivityList activity={data.activity} onSelectEntry={onSelectEntry} />
          </div>
        </>
      )}

      <footer className="dash-footer">
        Generated from the live ledger · out-of-balance check: {data.health.outOfBalance} · posted history is
        immutable — corrections happen as reversing entries.
      </footer>
    </div>
  );
}
