// Sales tax report tab — Task 3 of docs/superpowers/plans/2026-08-02-sales-tax.md.
// GET /api/c/reports/sales-tax?from=&to= (server/src/salesTax.ts) already does
// all the summing in SQL (sales_tax_summary() + the payable account's
// trial-balance-derived balance as of `to` — CLAUDE.md §3.4, never stored);
// this component formats, totals the columns for display, and offers the
// remittance helper: plain-English guidance plus a "Record a tax payment"
// button per agency that lands on #bills with the New-bill form prefilled
// (vendor + one line categorized to the payable account + the amount) via
// the sessionStorage handoff in bills/newBillPrefillHandoff.ts.
//
// The tab itself only exists for enabled companies (Reports.tsx gates it),
// so this component can assume the enabled shape once data arrives.

import { useState } from "react";
import { useCompany } from "../lib/company";
import { useApiGet } from "../lib/useApiGet";
import { fmtMoney, isZeroMoney, absMoney } from "../lib/money";
import { trimPercent } from "../lib/percent";
import { todayIso, quarterRange, prevQuarterRange, yearRange, fmtDate } from "../lib/date";
import { ErrorBanner } from "../components/ErrorBanner";
import { sumMoney } from "../invoices/lineAmount";
import { setPendingNewBillPrefill } from "../bills/newBillPrefillHandoff";
import type { NavTarget } from "../lib/useHashView";

interface SalesTaxRow {
  taxRateId: string;
  rateName: string;
  ratePercent: string;
  agencyVendorId: string | null;
  agencyName: string | null;
  taxableSales: string;
  nonTaxableSales: string;
  taxCollected: string;
}

interface SalesTaxReportData {
  enabled: boolean;
  from?: string;
  to?: string;
  rows: SalesTaxRow[];
  payableAccountId?: string | null;
  payableAccountName?: string | null;
  payableBalance?: string;
}

type Preset = "this-quarter" | "last-quarter" | "this-year" | "custom";

/** "123.4500" (always whole cents by construction — tax is rounded to the
 * cent) -> "123.45", the bill form's unit-price shape. String surgery only,
 * never a parsed float (CLAUDE.md §2). */
function toUnitPrice(amount: string): string {
  const match = /^(\d+)\.(\d{2})\d*$/.exec(amount.trim());
  if (!match) return amount;
  return `${match[1]}.${match[2]}`;
}

/** True when a NUMERIC(19,4) string is negative and not zero — same
 * leading-"-" string check money.ts's own helpers use. */
function isNegativeMoney(amount: string): boolean {
  return amount.trim().startsWith("-") && !isZeroMoney(amount);
}

/** min of two non-negative NUMERIC(19,4) strings, via BigInt (never a parsed
 * float, CLAUDE.md §2). Used to cap the remittance prefill at what's actually
 * still owed. */
function minMoney(a: string, b: string): string {
  const toScaled = (v: string): bigint | null => {
    const m = /^(\d+)\.(\d{4})$/.exec(v.trim());
    return m ? BigInt(m[1]! + m[2]!) : null;
  };
  const sa = toScaled(a);
  const sb = toScaled(b);
  if (sa === null || sb === null) return a;
  return sa <= sb ? a : b;
}

interface AgencyGroup {
  vendorId: string;
  name: string;
  collected: string;
}

/** Groups the report's rows by their agency vendor: one remittance button per
 * agency, its amount = that agency's tax collected in the period. Rates with
 * no agency are collected separately for the "add one in Settings" note. */
function groupByAgency(rows: SalesTaxRow[]): { agencies: AgencyGroup[]; noAgency: SalesTaxRow[] } {
  const byId = new Map<string, { name: string; amounts: string[] }>();
  const noAgency: SalesTaxRow[] = [];
  for (const row of rows) {
    if (row.agencyVendorId === null) {
      noAgency.push(row);
      continue;
    }
    const existing = byId.get(row.agencyVendorId);
    if (existing) {
      existing.amounts.push(row.taxCollected);
    } else {
      byId.set(row.agencyVendorId, { name: row.agencyName ?? "the agency", amounts: [row.taxCollected] });
    }
  }
  const agencies = Array.from(byId.entries()).map(([vendorId, g]) => ({
    vendorId,
    name: g.name,
    collected: sumMoney(g.amounts),
  }));
  return { agencies, noAgency };
}

export function SalesTaxReport({ navigate }: { navigate: (target: NavTarget) => void }) {
  const { selectedCompanyId } = useCompany();
  // Default period: the current calendar quarter — sales tax is typically
  // remitted quarterly.
  const [range, setRange] = useState(() => quarterRange(todayIso()));
  const [preset, setPreset] = useState<Preset>("this-quarter");

  const path = `/api/c/reports/sales-tax?from=${range.from}&to=${range.to}`;
  const { data, loading, error, retry } = useApiGet<SalesTaxReportData>(
    range.from && range.to ? path : null, selectedCompanyId,
  );

  function applyPreset(next: Preset) {
    setPreset(next);
    if (next === "this-quarter") setRange(quarterRange(todayIso()));
    else if (next === "last-quarter") setRange(prevQuarterRange(todayIso()));
    else if (next === "this-year") setRange(yearRange(new Date().getFullYear()));
  }

  function recordTaxPayment(agency: AgencyGroup) {
    if (!data?.payableAccountId || data.payableBalance === undefined) return;
    if (isZeroMoney(data.payableBalance) || isNegativeMoney(data.payableBalance)) return;
    // Cap the prefill at what's actually still owed: after a partial or
    // earlier remittance the period's collected figure can exceed the
    // remaining payable balance, and prefilling the full period amount would
    // invite paying twice.
    const amount = minMoney(agency.collected, data.payableBalance);
    setPendingNewBillPrefill({
      vendorId: agency.vendorId,
      description: `Sales tax collected ${fmtDate(range.from)} – ${fmtDate(range.to)}`,
      unitPrice: toUnitPrice(amount),
      categoryAccountId: data.payableAccountId,
    });
    navigate("bills");
  }

  const rows = data?.rows ?? [];
  const totals = {
    taxable: sumMoney(rows.map((r) => r.taxableSales)),
    nonTaxable: sumMoney(rows.map((r) => r.nonTaxableSales)),
    collected: sumMoney(rows.map((r) => r.taxCollected)),
  };
  const { agencies, noAgency } = groupByAgency(rows);

  return (
    <div>
      <div className="report-toolbar">
        <div className="presets">
          <button
            type="button"
            aria-pressed={preset === "this-quarter"}
            onClick={() => applyPreset("this-quarter")}
          >
            This quarter
          </button>
          <button
            type="button"
            aria-pressed={preset === "last-quarter"}
            onClick={() => applyPreset("last-quarter")}
          >
            Last quarter
          </button>
          <button type="button" aria-pressed={preset === "this-year"} onClick={() => applyPreset("this-year")}>
            This year
          </button>
        </div>
        <div className="date-inputs">
          <label>
            From
            <input
              type="date"
              value={range.from}
              onChange={(ev) => {
                setRange((r) => ({ ...r, from: ev.target.value }));
                setPreset("custom");
              }}
            />
          </label>
          <label>
            To
            <input
              type="date"
              value={range.to}
              onChange={(ev) => {
                setRange((r) => ({ ...r, to: 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 && rows.length === 0 && (
        <div className="empty-state">No sales tax charged on invoices in this period.</div>
      )}

      {data && rows.length > 0 && (
        <div className="card">
          <table>
            <thead>
              <tr>
                <th>Rate</th>
                <th className="num">Percent</th>
                <th className="num">Taxable sales</th>
                <th className="num">Non-taxable sales</th>
                <th className="num">Tax collected</th>
              </tr>
            </thead>
            <tbody>
              {rows.map((r) => (
                <tr key={r.taxRateId}>
                  <td>{r.rateName}</td>
                  <td className="num">{trimPercent(r.ratePercent)}%</td>
                  <td className="num">{fmtMoney(r.taxableSales)}</td>
                  <td className="num">{fmtMoney(r.nonTaxableSales)}</td>
                  <td className="num">{fmtMoney(r.taxCollected)}</td>
                </tr>
              ))}
              <tr className="total-row">
                <td>Total</td>
                <td className="num" />
                <td className="num">{fmtMoney(totals.taxable)}</td>
                <td className="num">{fmtMoney(totals.nonTaxable)}</td>
                <td className="num">{fmtMoney(totals.collected)}</td>
              </tr>
            </tbody>
          </table>
        </div>
      )}

      {data && data.payableAccountName && data.payableBalance !== undefined && (
        <div className="card" style={{ marginTop: 18 }}>
          {isNegativeMoney(data.payableBalance) ? (
            // A negative payable means more was remitted than collected —
            // never show "-$3.00 owed" (CLAUDE.md §9: errors in English,
            // plain words over signed numbers).
            <p className="sub" style={{ margin: 0 }}>
              You&rsquo;ve overpaid by {fmtMoney(absMoney(data.payableBalance))} — it will offset
              what you collect next.
            </p>
          ) : (
            <div className="rows">
              <div className="row total">
                <span className="n">
                  Sales tax you owe (in {data.payableAccountName}, as of {fmtDate(range.to)})
                </span>
                <span className="a">{fmtMoney(data.payableBalance)}</span>
              </div>
            </div>
          )}
        </div>
      )}

      {data && (agencies.length > 0 || noAgency.length > 0) && (
        <div className="card" style={{ marginTop: 18 }}>
          <h2>Paying the tax agency</h2>
          {agencies.map((agency) => (
            <div key={agency.vendorId} style={{ marginBottom: 14 }}>
              <p className="sub" style={{ marginBottom: 8 }}>
                When you pay {agency.name}, enter a bill to them for the amount you owe and pay it
                like any other bill — the amount you owe goes back to zero.
              </p>
              {/* Disabled once nothing is owed at all — zero OR negative
                  (over-remitted) payable balance — an enabled button would
                  invite paying the same period twice. */}
              <button
                type="button"
                className="btn"
                disabled={
                  isZeroMoney(agency.collected) ||
                  !data.payableAccountId ||
                  data.payableBalance === undefined ||
                  isZeroMoney(data.payableBalance) ||
                  isNegativeMoney(data.payableBalance)
                }
                onClick={() => recordTaxPayment(agency)}
              >
                Record a tax payment to {agency.name} ({fmtMoney(agency.collected)})
              </button>
            </div>
          ))}
          {noAgency.map((row) => (
            <div key={row.taxRateId} style={{ marginBottom: 8 }}>
              <p className="sub" style={{ marginBottom: 8 }}>
                {row.rateName} doesn&rsquo;t have a tax agency yet — pick who you pay it to in
                Settings (under Sales tax) to record payments from here.
              </p>
              <button type="button" className="btn" disabled>
                Record a tax payment
              </button>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}
