// Reconcile-first home screen — Task 4 of docs/superpowers/plans/2026-08-01-bank-rec.md
// (CLAUDE.md §9: "Reconciliation is the home screen"). #home is the app's
// new DEFAULT landing view (lib/useHashView.ts's parseHash now falls back to
// "home" for an empty/unrecognized hash, not "dashboard" as Task 8 had it) —
// but the router has no access to company data, so the actual "home when
// eligible, dashboard otherwise" decision (design spec: "home when any money
// account exists with entries else dashboard") lives HERE, in what this
// component renders.
//
// Eligibility check: there's no endpoint that reports per-account entry
// existence directly (adding one would be server work, out of scope for
// this web-only task), so this approximates with two numbers already on
// hand — selectedCompany.entryCount (the company's total posted-entry
// count, loaded once via useCompany(), no extra round trip) and this
// screen's own GET /api/c/bank/overview response (empty until the chart of
// accounts has an active asset account). In practice a posted entry with no
// asset/liability leg at all is not a real-world transaction this system
// generates, so "the company has posted entries AND has a money account" is
// a safe, cheap proxy for "some money account has activity." The sidebar's
// own "Home" item still always routes to #home explicitly — clicking it on
// a brand-new, ineligible company shows Dashboard's own honest "no history
// yet" empty state, not a dead scratch-cards screen, since eligibility is
// re-checked on every render, not just at the "default hash" moment.

import { useCallback, useEffect, useState } from "react";
import { apiGet, ApiError } from "../lib/api";
import { useCompany } from "../lib/company";
import { fmtMoney } from "../lib/money";
import { fmtDate } from "../lib/date";
import { ErrorBanner } from "../components/ErrorBanner";
import { Tile } from "../components/Tile";
import { Dashboard } from "../Dashboard";
import type { NavTarget } from "../lib/useHashView";

interface OpenStatementSummary {
  id: string;
  filename: string;
  periodEnd: string | null;
  counts: Record<string, number>;
}

interface OverviewAccount {
  accountId: string;
  name: string;
  bookBalance: string;
  reconciledThrough: string | null;
  openStatements: OpenStatementSummary[];
}

interface OverviewResponse {
  accounts: OverviewAccount[];
}

interface DashboardTilesOnly {
  tiles: { youHave: string; youOwe: string; yearProfit: string };
}

function unsettledCount(statements: OpenStatementSummary[]): number {
  return statements.reduce((sum, s) => sum + (s.counts.unmatched ?? 0) + (s.counts.suggested ?? 0), 0);
}

function AccountCard({
  account,
  onImport,
  onReview,
}: {
  account: OverviewAccount;
  onImport: () => void;
  onReview: (statementId: string) => void;
}) {
  const toReview = unsettledCount(account.openStatements);
  // Design spec: the pill shows only when an open statement HAS unsettled
  // lines; "Continue reviewing" shows whenever an open statement exists at
  // all (even fully-settled, since it still needs the reconcile step —
  // Task 5's workbench), per this task's own brief distinguishing the two
  // conditions.
  const openStatement = account.openStatements[0] ?? null;

  return (
    <div className="account-card">
      <div className="account-card-head">
        <h2>{account.name}</h2>
        {account.reconciledThrough ? (
          <span className="chip">Reconciled through {fmtDate(account.reconciledThrough)}</span>
        ) : (
          <span className="chip chip-muted">Never reconciled</span>
        )}
      </div>
      <div className="account-card-balance">{fmtMoney(account.bookBalance)}</div>
      {toReview > 0 && (
        <div className="account-card-pill">
          <span className="chip chip-info">{toReview} to review</span>
        </div>
      )}
      <div className="account-card-actions">
        <button type="button" className="btn" onClick={onImport}>
          Import statement
        </button>
        {openStatement && (
          <button type="button" className="acct-link" onClick={() => onReview(openStatement.id)}>
            Continue reviewing
          </button>
        )}
      </div>
    </div>
  );
}

function HomeSummary({ companyId }: { companyId: string | null }) {
  const [data, setData] = useState<DashboardTilesOnly | null>(null);

  useEffect(() => {
    if (!companyId) return;
    let cancelled = false;
    apiGet<DashboardTilesOnly>("/api/c/reports/dashboard", companyId)
      .then((body) => {
        if (!cancelled) setData(body);
      })
      .catch(() => {
        // Best-effort strip — the account cards below are this screen's
        // real content, so a failed tiles fetch just omits the strip rather
        // than blocking the page with an error banner.
      });
    return () => {
      cancelled = true;
    };
  }, [companyId]);

  if (!data) return null;

  return (
    <div className="tiles tiles-compact">
      <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()} kept so far`} amount={data.tiles.yearProfit} sub="Money in minus money out" />
    </div>
  );
}

export function Home({
  navigate,
  onSelectAccount,
  onSelectEntry,
}: {
  navigate: (target: NavTarget) => void;
  onSelectAccount: (accountId: string) => void;
  onSelectEntry: (entryId: string) => void;
}) {
  const { selectedCompanyId, selectedCompany } = useCompany();
  const [overview, setOverview] = useState<OverviewResponse | 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<OverviewResponse>("/api/c/bank/overview", selectedCompanyId)
      .then((body) => {
        if (!cancelled) setOverview(body);
      })
      .catch((err: unknown) => {
        if (!cancelled) setError(err instanceof ApiError ? err.message : "Couldn't load your accounts.");
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, [selectedCompanyId, reloadToken]);

  if (loading && !overview) {
    return (
      <div className="wrap">
        <p className="msg-inline">Loading your accounts&hellip;</p>
      </div>
    );
  }

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

  if (!overview) return null;

  const eligible = (selectedCompany?.entryCount ?? 0) > 0 && overview.accounts.length > 0;
  if (!eligible) {
    return <Dashboard onSelectAccount={onSelectAccount} onSelectEntry={onSelectEntry} navigate={navigate} />;
  }

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

      <header className="top">
        <h1>{selectedCompany?.name ?? "Home"}</h1>
      </header>

      <HomeSummary companyId={selectedCompanyId} />

      <section style={{ marginTop: 8 }}>
        <h2 style={{ marginBottom: 10 }}>Your accounts</h2>
        <div className="account-cards">
          {overview.accounts.map((a) => (
            <AccountCard
              key={a.accountId}
              account={a}
              onImport={() => navigate({ view: "bank-import", params: { accountId: a.accountId } })}
              onReview={(statementId) => navigate({ view: "bank-statement", id: statementId })}
            />
          ))}
        </div>
      </section>
    </div>
  );
}
