"use client";

import * as React from "react";
import { InfoIcon } from "lucide-react";

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select";
import { cn } from "@/lib/utils";

import { FinancialOverviewChart, type FinPeriod } from "./report-charts";
import { TONE_BOX } from "./tones";
import { Surface } from "./surface";

const n2 = (n: number) => n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });

/* -------------------------------- DB-01. Dashboard filters -------------------------------- */

export type DashFilter = { preset: string; from: string; to: string; branch: string };

const PRESETS = [
  { id: "today", label: "Today" },
  { id: "7d", label: "Last 7 days" },
  { id: "mtd", label: "This month" },
  { id: "custom", label: "Custom" },
];

/**
 * Dashboard filters (DB-01, DB-02): a date preset or custom range, and a branch, applied together with one
 * Apply so the panels reload once, not on every change. Apply is enabled only when something changed; the
 * applied line says in words what every figure is for.
 */
export function DashboardFilters({ applied, branches, onApply, describe }: { applied: DashFilter; branches: string[]; onApply: (f: DashFilter) => void; describe: (f: DashFilter) => string }) {
  const [draft, setDraft] = React.useState(applied);
  const changed = JSON.stringify(draft) !== JSON.stringify(applied);
  const bad = draft.preset === "custom" && (!draft.from || !draft.to || draft.to < draft.from);
  return (
    <div className="space-y-2">
      <Surface className="flex flex-wrap items-end gap-2">
        <div role="group" aria-label="Period" className="flex overflow-hidden rounded-md border border-[var(--color-border-panel)] text-sm bg-card">
          {PRESETS.map((p) => (
            <button key={p.id} type="button" aria-pressed={draft.preset === p.id} onClick={() => setDraft({ ...draft, preset: p.id })} className={cn("cursor-pointer border-r border-[var(--color-border-panel)] px-3 py-1.5 last:border-r-0", draft.preset === p.id ? "bg-[var(--color-bg-selected)] font-medium" : "text-muted-foreground hover:bg-muted")}>
              {p.label}
            </button>
          ))}
        </div>
        {draft.preset === "custom" ? (
          <>
            <Input type="date" aria-label="From" className="w-40" value={draft.from} onChange={(e) => setDraft({ ...draft, from: e.target.value })} aria-invalid={bad} />
            <Input type="date" aria-label="To" className="w-40" value={draft.to} onChange={(e) => setDraft({ ...draft, to: e.target.value })} aria-invalid={bad} />
          </>
        ) : null}
        {/* No branches to offer (one branch, or a role kept to its own): no selector rather than a choice that does nothing */}
        {branches.length ? (
          <NativeSelect aria-label="Branch" value={draft.branch} onChange={(e) => setDraft({ ...draft, branch: e.target.value })}>
            <NativeSelectOption value="">All branches</NativeSelectOption>
            {branches.map((b) => (
              <NativeSelectOption key={b}>{b}</NativeSelectOption>
            ))}
          </NativeSelect>
        ) : null}
        <Button onClick={() => onApply(draft)} disabled={!changed || bad}>
          Apply
        </Button>
        {changed ? (
          <Button variant="ghost" onClick={() => setDraft(applied)}>
            Reset
          </Button>
        ) : null}
      </Surface>
      {bad ? <p className="text-xs text-status-error-text">The end date is before the start date.</p> : null}
      <p className="text-xs text-[var(--color-fg-secondary-strong,var(--muted-foreground))]">Showing: {describe(applied)}</p>
    </div>
  );
}

/* --------------------------------- DB-04. Financial overview --------------------------------- */

export type FinMonth = FinPeriod;

/**
 * Financial overview (DB-04): sales, purchases and expenses per month as grouped columns on one axis, with
 * a Table view of the same figures, so the comparison never depends on reading bar lengths or colours.
 */
export function FinancialOverview({ months }: { months: FinMonth[] }) {
  return <FinancialOverviewChart months={months} />;
}

/* ---------------------------------- RP-14. General report ---------------------------------- */

/**
 * General report (RP-14): invoice and till sales by tender, less credit notes; then sales less purchases,
 * labelled plainly as not profit, because stock bought isn't stock sold. Links to Profit & loss for that.
 */
export function GeneralReport({ invoices, byTender, creditNotes, purchases, onOpenPL }: { invoices: number; byTender: { tender: string; amount: number }[]; creditNotes: number; purchases: number; onOpenPL?: () => void }) {
  const pos = byTender.reduce((s, t) => s + t.amount, 0);
  const gross = invoices + pos;
  const net = gross - creditNotes;
  const less = net - purchases;
  const row = (label: string, v: number, opts: { indent?: boolean; strong?: boolean; minus?: boolean } = {}) => (
    <tr key={label} className={cn(opts.strong && "border-t border-[var(--color-border-panel)] font-semibold")}>
      <th scope="row" className={cn("px-3 py-1.5 text-left font-normal", opts.indent && "pl-7 text-muted-foreground", opts.strong && "font-semibold")}>
        {label}
      </th>
      <td className="px-3 py-1.5 text-right tabular-nums">{opts.minus ? `(${n2(v)})` : n2(v)}</td>
    </tr>
  );
  return (
    <div className="space-y-3">
      <div className="overflow-x-auto rounded-lg border border-[var(--color-border-panel)] bg-card">
        <table className="w-full border-collapse text-sm">
          <caption className="sr-only">General report</caption>
          <tbody className="divide-y divide-[var(--color-border-subtle)]">
            {row("Invoice sales (B2B)", invoices)}
            <tr>
              <th scope="row" className="px-3 py-1.5 text-left font-normal">
                Till sales
              </th>
              <td />
            </tr>
            {byTender.map((t) => row(t.tender, t.amount, { indent: true }))}
            {row("Gross sales", gross, { strong: true })}
            {row("Less credit notes", creditNotes, { minus: true })}
            {row("Net sales", net, { strong: true })}
            {row("Less purchases (goods received)", purchases, { minus: true })}
            <tr className="border-t-2 border-[var(--color-border-panel)] bg-muted/30 font-semibold">
              <th scope="row" className="px-3 py-2 text-left">
                Sales less purchases
                <span className="block text-xs font-normal text-status-warning-text">Not profit</span>
              </th>
              <td className="px-3 py-2 text-right tabular-nums">{less < 0 ? `(${n2(-less)})` : n2(less)}</td>
            </tr>
          </tbody>
        </table>
      </div>
      <p className={cn("flex items-start gap-2 rounded-md border px-3 py-2 text-sm", TONE_BOX.info)}>
        <InfoIcon className="mt-0.5 size-4 shrink-0" aria-hidden />
        <span>
          This compares money in from sales with stock bought in the same period. Stock bought this month may sell next month, so it isn&apos;t profit.{" "}
          {onOpenPL ? (
            <button type="button" className="cursor-pointer font-medium underline-offset-2 hover:underline" onClick={onOpenPL}>
              See Profit &amp; loss
            </button>
          ) : null}
        </span>
      </p>
    </div>
  );
}

/* --------------------------------- AC-19. Executive pack --------------------------------- */

export type CategoryPL = { category: string; revenue: number; cost: number };
export type StaffPL = { staff: string; sales: number; returns: number; cost: number };
export type StockingRow = { item: string; bought: number; sold: number; unit: string };

const margin = (rev: number, cost: number) => (rev ? ((rev - cost) / rev) * 100 : 0);

/** P&L by category (AC-19): revenue, cost, gross profit and margin, largest first, with totals. */
export function CategoryPLTable({ rows }: { rows: CategoryPL[] }) {
  const sorted = [...rows].sort((a, b) => b.revenue - a.revenue);
  const t = rows.reduce((s, r) => ({ revenue: s.revenue + r.revenue, cost: s.cost + r.cost }), { revenue: 0, cost: 0 });
  return (
    <table className="w-full border-collapse text-sm tabular-nums">
      <caption className="sr-only">Profit and loss by category</caption>
      <thead className="bg-[var(--color-bg-surface-subtle)] text-left text-xs text-muted-foreground">
        <tr>
          {["Category", "Revenue", "Cost", "Gross profit", "Margin"].map((h) => (
            <th key={h} scope="col" className={cn("px-3 py-2 font-medium", h !== "Category" && "text-right")}>
              {h}
            </th>
          ))}
        </tr>
      </thead>
      <tbody className="divide-y divide-[var(--color-border-subtle)]">
        {sorted.map((r) => (
          <tr key={r.category}>
            <th scope="row" className="px-3 py-1.5 text-left font-medium">
              {r.category}
            </th>
            <td className="px-3 py-1.5 text-right">{n2(r.revenue)}</td>
            <td className="px-3 py-1.5 text-right">{n2(r.cost)}</td>
            <td className="px-3 py-1.5 text-right">{n2(r.revenue - r.cost)}</td>
            <td className={cn("px-3 py-1.5 text-right", margin(r.revenue, r.cost) < 15 && "font-semibold text-status-warning-text")}>{margin(r.revenue, r.cost).toFixed(1)}%</td>
          </tr>
        ))}
      </tbody>
      <tfoot className="border-t-2 border-[var(--color-border-panel)] font-semibold">
        <tr>
          <th scope="row" className="px-3 py-2 text-left">
            All categories
          </th>
          <td className="px-3 py-2 text-right">{n2(t.revenue)}</td>
          <td className="px-3 py-2 text-right">{n2(t.cost)}</td>
          <td className="px-3 py-2 text-right">{n2(t.revenue - t.cost)}</td>
          <td className="px-3 py-2 text-right">{margin(t.revenue, t.cost).toFixed(1)}%</td>
        </tr>
      </tfoot>
    </table>
  );
}

/** P&L by staff member (AC-19): what each person sold, net of returns, and the gross profit on it. */
export function StaffPLTable({ rows }: { rows: StaffPL[] }) {
  return (
    <table className="w-full border-collapse text-sm tabular-nums">
      <caption className="sr-only">Profit and loss by staff member</caption>
      <thead className="bg-[var(--color-bg-surface-subtle)] text-left text-xs text-muted-foreground">
        <tr>
          {["Staff", "Sales", "Returns", "Net", "Gross profit", "Margin"].map((h) => (
            <th key={h} scope="col" className={cn("px-3 py-2 font-medium", h !== "Staff" && "text-right")}>
              {h}
            </th>
          ))}
        </tr>
      </thead>
      <tbody className="divide-y divide-[var(--color-border-subtle)]">
        {rows.map((r) => {
          const net = r.sales - r.returns;
          const retPct = r.sales ? (r.returns / r.sales) * 100 : 0;
          return (
            <tr key={r.staff}>
              <th scope="row" className="px-3 py-1.5 text-left font-medium">
                {r.staff}
              </th>
              <td className="px-3 py-1.5 text-right">{n2(r.sales)}</td>
              <td className="px-3 py-1.5 text-right">
                {n2(r.returns)}
                {retPct > 3 ? <span className="block text-[11px] font-medium text-status-warning-text">{retPct.toFixed(1)}% of sales</span> : null}
              </td>
              <td className="px-3 py-1.5 text-right">{n2(net)}</td>
              <td className="px-3 py-1.5 text-right">{n2(net - r.cost)}</td>
              <td className="px-3 py-1.5 text-right">{margin(net, r.cost).toFixed(1)}%</td>
            </tr>
          );
        })}
      </tbody>
    </table>
  );
}

/**
 * Stocking effectiveness (AC-19): what was bought against what sold over the period. Buying much more than
 * sells ties up cash; selling more than was bought runs stock down. Each ratio is written as a word.
 */
export function StockingTable({ rows }: { rows: StockingRow[] }) {
  const verdict = (b: number, s: number) => (s === 0 ? (b > 0 ? "Bought, none sold" : "–") : b / s > 1.5 ? `Bought ${(b / s).toFixed(1)}× what sold` : b / s < 0.7 ? "Stock running down" : "In step");
  return (
    <table className="w-full border-collapse text-sm tabular-nums">
      <caption className="sr-only">Stocking effectiveness</caption>
      <thead className="bg-[var(--color-bg-surface-subtle)] text-left text-xs text-muted-foreground">
        <tr>
          {["Item", "Bought", "Sold", ""].map((h, i) => (
            <th key={i} scope="col" className={cn("px-3 py-2 font-medium", (h === "Bought" || h === "Sold") && "text-right")}>
              {h || <span className="sr-only">Verdict</span>}
            </th>
          ))}
        </tr>
      </thead>
      <tbody className="divide-y divide-[var(--color-border-subtle)]">
        {rows.map((r) => {
          const v = verdict(r.bought, r.sold);
          return (
            <tr key={r.item}>
              <th scope="row" className="px-3 py-1.5 text-left font-medium">
                {r.item}
              </th>
              <td className="px-3 py-1.5 text-right">
                {r.bought.toLocaleString("en-US")} {r.unit}
              </td>
              <td className="px-3 py-1.5 text-right">
                {r.sold.toLocaleString("en-US")} {r.unit}
              </td>
              <td className={cn("px-3 py-1.5 text-xs font-medium", v === "In step" ? "text-muted-foreground" : "text-status-warning-text")}>{v}</td>
            </tr>
          );
        })}
      </tbody>
    </table>
  );
}
