// Item profitability tab — Task 5 of docs/superpowers/plans/2026-08-03-inventory.md.
// GET /api/c/reports/item-profitability?from=&to= (server/src/reports.ts) does
// every sum in SQL; this formats them.
//
// WHAT THIS REPORT IS AS OF. It reads the books as they stand TODAY, not as
// they stood at the end of the period — which is correct for a margin report
// and has to be said on its face (Task 3's review). item_profitability() counts
// invoice lines on invoices that are 'open' right now, so a sale that has since
// been voided drops out of the period entirely rather than appearing with a
// countervailing entry. That is what you want when you are asking "did this
// product make money" — a sale that was cancelled never made any — but it means
// two printouts of the same period, taken either side of a void, will
// legitimately differ. The P&L does NOT behave this way (a void is a reversing
// entry sitting in whichever period it was recorded in), so the two reports can
// disagree for a period containing a void, and both are right.
//
// COST comes from the sale movements the invoice lines actually produced —
// the number the ledger was posted, at the average cost on the day — never a
// re-multiplication of today's average against yesterday's quantity.

import { useMemo, useState } from "react";
import { useCompany } from "../lib/company";
import { useApiGet } from "../lib/useApiGet";
import { fmtMoney, isZeroMoney } from "../lib/money";
import { yearRange } from "../lib/date";
import { ErrorBanner } from "../components/ErrorBanner";
import { fmtQuantity, kindLabel } from "../items/itemTypes";
import type { NavTarget } from "../lib/useHashView";
import { marginPercent } from "./itemProfitabilityMath";

interface ProfitabilityRow {
  itemId: string;
  sku: string | null;
  name: string;
  kind: string;
  unitsSold: string;
  revenue: string;
  cogs: string;
  margin: string;
}

interface ProfitabilityData {
  from: string | null;
  to: string | null;
  items: ProfitabilityRow[];
  revenueTotal: string;
  cogsTotal: string;
  marginTotal: string;
}

type Preset = "this-year" | "last-year" | "all-time" | "custom";

function buildPath(from: string, to: string): string {
  const params = new URLSearchParams();
  if (from) params.set("from", from);
  if (to) params.set("to", to);
  const qs = params.toString();
  return `/api/c/reports/item-profitability${qs ? `?${qs}` : ""}`;
}

export function ItemProfitabilityReport({
  navigate,
}: {
  navigate: (target: NavTarget) => void;
}) {
  const { selectedCompanyId } = useCompany();
  const currentYear = new Date().getFullYear(); // a calendar label, not money
  const defaultRange = useMemo(() => yearRange(currentYear), [currentYear]);

  const [from, setFrom] = useState(defaultRange.from);
  const [to, setTo] = useState(defaultRange.to);
  const [preset, setPreset] = useState<Preset>("this-year");

  const { data, loading, error, retry } = useApiGet<ProfitabilityData>(
    buildPath(from, to), selectedCompanyId,
  );

  function applyPreset(next: Preset) {
    setPreset(next);
    if (next === "this-year") {
      const r = yearRange(currentYear);
      setFrom(r.from);
      setTo(r.to);
    } else if (next === "last-year") {
      const r = yearRange(currentYear - 1);
      setFrom(r.from);
      setTo(r.to);
    } else if (next === "all-time") {
      setFrom("");
      setTo("");
    }
  }

  return (
    <div>
      <div className="report-toolbar">
        <div className="presets">
          <button type="button" aria-pressed={preset === "this-year"} onClick={() => applyPreset("this-year")}>
            This year
          </button>
          <button type="button" aria-pressed={preset === "last-year"} onClick={() => applyPreset("last-year")}>
            Last year
          </button>
          <button type="button" aria-pressed={preset === "all-time"} onClick={() => applyPreset("all-time")}>
            All time
          </button>
        </div>
        <div className="date-inputs">
          <label>
            From
            <input
              type="date"
              value={from}
              onChange={(ev) => {
                setFrom(ev.target.value);
                setPreset("custom");
              }}
            />
          </label>
          <label>
            To
            <input
              type="date"
              value={to}
              onChange={(ev) => {
                setTo(ev.target.value);
                setPreset("custom");
              }}
            />
          </label>
        </div>
      </div>

      {error && <ErrorBanner message={error} onRetry={retry} />}
      {loading && !data && <p className="msg-inline">Loading&hellip;</p>}
      {!loading && !error && data && data.items.length === 0 && (
        <div className="empty-state">
          Nothing was sold by item in this period. Only invoice lines that name an item appear
          here — a line typed as a plain description has nothing to attribute.
        </div>
      )}

      {data && data.items.length > 0 && (
        <>
          <div className="card">
            <table>
              <thead>
                <tr>
                  <th>Item</th>
                  <th className="num">Units sold</th>
                  <th className="num">Brought in</th>
                  <th className="num">Cost of what you sold</th>
                  <th className="num">Kept</th>
                  <th className="num">Margin</th>
                </tr>
              </thead>
              <tbody>
                {data.items.map((row) => {
                  const pct = marginPercent(row.margin, row.revenue);
                  return (
                    <tr
                      key={row.itemId}
                      style={{ cursor: "pointer" }}
                      onClick={() => navigate({ view: "item", id: row.itemId })}
                    >
                      <td>
                        {row.name}
                        <div className="register-memo-sub">
                          {row.sku ? `SKU ${row.sku} · ` : ""}
                          {kindLabel(row.kind)}
                        </div>
                      </td>
                      <td className="num">{fmtQuantity(row.unitsSold)}</td>
                      <td className="num">{fmtMoney(row.revenue)}</td>
                      <td className="num">
                        {isZeroMoney(row.cogs) && row.kind === "service" ? "—" : fmtMoney(row.cogs)}
                      </td>
                      <td className="num">{fmtMoney(row.margin)}</td>
                      <td className="num">{pct ?? "—"}</td>
                    </tr>
                  );
                })}
                <tr className="total-row">
                  <td>Total</td>
                  <td className="num" />
                  <td className="num">{fmtMoney(data.revenueTotal)}</td>
                  <td className="num">{fmtMoney(data.cogsTotal)}</td>
                  <td className="num">{fmtMoney(data.marginTotal)}</td>
                  <td className="num">
                    {marginPercent(data.marginTotal, data.revenueTotal) ?? "—"}
                  </td>
                </tr>
              </tbody>
            </table>
          </div>

          <p className="sub" style={{ marginTop: 10 }}>
            <strong>As things stand today.</strong> This counts invoices that are still live right
            now. If you void a sale later, it drops out of this period altogether rather than
            showing up as a cancelling line — which is what you want when you&rsquo;re asking
            whether a product makes money, but it does mean this report and your profit &amp; loss
            can differ for a period containing a voided sale. Both are right; they&rsquo;re
            answering different questions.
          </p>
          <p className="sub">
            &ldquo;Cost of what you sold&rdquo; is what those units actually cost you, taken from
            the stock that left the shelf at the average cost on the day — not today&rsquo;s
            average applied backwards. Services and non-stocked items carry no such cost, so they
            show their full revenue as kept.
          </p>
          {/* CLAUDE.md §9 as amended 2026-08-02: standard accounting stays
              visible rather than being replaced by the plain wording. The
              column headers keep the P&L's vocabulary (this screen sits beside
              it); the standard names sit underneath, once, for the reader who
              wants them — an accountant reading this report, or an owner about
              to email it to one. */}
          <p className="sub">
            In accountants&rsquo; terms: &ldquo;Brought in&rdquo; is revenue, &ldquo;Cost of what
            you sold&rdquo; is cost of goods sold, and &ldquo;Kept&rdquo; is gross margin.
          </p>
        </>
      )}
    </div>
  );
}
