"use client";

/**
 * Accounts → Receivables (PRD 6.9; plan H, approved 26 Oct 2026): invoices with their delivery notes (AC-07),
 * quotations (AC-15), scheme claims (AC-13), and the receivable reports (AC-09): payment records with what each
 * settled (`PaymentRecords`) and what customers and schemes owe by age (`AgeingChart`). Customer statements stay on
 * each customer's profile. Each tab shows only with Read on its page.
 */

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

import { PanelError } from "@/components/medora/errors";
import { MedoraPageHeader } from "@/components/medora/page-header";
import { PaymentRecords } from "@/components/medora/record-lists";
import { AgeingChart } from "@/components/medora/report-charts";
import { Field, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { toast } from "@/components/ui/toast";
import { ClaimsApi, CustomersApi, InvoicesApi, ProductsApi, QuotationsApi, ReceivablesApi, TaxCodesApi, type ClaimRow, type InvoiceRow, type QuotationRow, type ReceivablePayment } from "@/lib/api";
import { useTabParam } from "@/lib/use-tab-param";
import { useMenuPermissions } from "@/lib/permissions";

import { ClaimsView } from "./claims-view";
import { InvoicesView, type InvoiceDraft } from "./invoices-view";
import { QuotationsView } from "./quotations-view";
import { apiError, kes, monthStart, today, type Customer, type Item } from "./shared";
import { ChartCard } from "@/components/medora/records/reports";
import { Surface } from "@/components/medora/surface";
import { Loading } from "@/components/medora/loading";

type Tab = "invoices" | "quotations" | "claims" | "payments" | "ageing";
const PAGES: Record<Tab, string> = { invoices: "Accounts/Invoices", quotations: "Accounts/Quotations", claims: "Accounts/Claims", payments: "Accounts/Receivables", ageing: "Accounts/Receivables" };
const LABEL: Record<Tab, string> = { invoices: "Invoices", quotations: "Quotations", claims: "Scheme claims", payments: "Payments received", ageing: "Ageing" };

type ApiProduct = { id: number; code?: string | null; name: string; unit?: string | null; sellPrice: string | number; taxCodeId?: number | null; deletedAt?: string | null };

export default function ReceivablesPage() {
  const { can, loaded } = useMenuPermissions();
  const tabs = (Object.keys(PAGES) as Tab[]).filter((t) => loaded && can(PAGES[t], "Read"));
  const [tabParam, setTab] = useTabParam(); // page tabs change the URL (tabs spec 7.1)
  const tab = tabParam as Tab | null;
  const current = tab && tabs.includes(tab) ? tab : (tabs[0] ?? null);
  const [from, setFrom] = React.useState(monthStart());
  const [to, setTo] = React.useState(today());
  const [items, setItems] = React.useState<Item[]>([]);
  const [customers, setCustomers] = React.useState<Customer[]>([]);
  const [invoices, setInvoices] = React.useState<InvoiceRow[] | null>(null);
  const [quotes, setQuotes] = React.useState<QuotationRow[] | null>(null);
  const [claims, setClaims] = React.useState<ClaimRow[] | null>(null);
  const [claimView, setClaimView] = React.useState<"open" | "all">("open");
  const [payments, setPayments] = React.useState<ReceivablePayment[] | null>(null);
  const [ageing, setAgeing] = React.useState<Awaited<ReturnType<typeof ReceivablesApi.ageing>> | null>(null);
  const [draft, setDraft] = React.useState<InvoiceDraft | null>(null);
  const newQuote = React.useRef<(() => void) | null>(null);
  const [printedBy, setPrintedBy] = React.useState("");

  React.useEffect(() => {
    try {
      const u = JSON.parse(localStorage.getItem("user") || "{}");
      setPrintedBy(u.name || u.username || "");
    } catch {
      setPrintedBy("");
    }
  }, []);

  // Items priced for the forms (VAT from each product's tax code), and customers for invoices
  React.useEffect(() => {
    if (!current || !["invoices", "quotations"].includes(current) || items.length) return;
    Promise.all([ProductsApi.getAll() as Promise<ApiProduct[]>, TaxCodesApi.list().catch(() => []) as Promise<{ id: number; code: string; rate: number | string }[]>, CustomersApi.getAll() as Promise<{ id: number; name: string; phone?: string | null }[]>])
      .then(([ps, taxes, cs]) => {
        const tax = new Map(taxes.map((t) => [t.id, t]));
        setItems(
          ps
            .filter((p) => !p.deletedAt)
            .map((p) => {
              const t = p.taxCodeId != null ? tax.get(p.taxCodeId) : undefined;
              return { id: p.id, code: p.code ?? "", name: p.name, unit: p.unit ?? null, price: Number(p.sellPrice) || 0, vat: (t ? (Number(t.rate) > 0 ? 16 : 0) : 16) as 0 | 16, taxCode: t?.code ?? null };
            })
            .sort((a, b) => a.name.localeCompare(b.name)),
        );
        setCustomers(cs.map((c) => ({ id: c.id, name: c.name, phone: c.phone ?? "" })).sort((a, b) => a.name.localeCompare(b.name)));
      })
      .catch((e) => toast.add({ type: "error", title: "Couldn't load items and customers", description: apiError(e, "Try again.") }));
  }, [current, items.length]);

  const [failed, setFailed] = React.useState<string | null>(null); // R12 (card 037): what failed to load, shown with Try again in place of the view
  const shown = failed ? null : current;
  const load = React.useCallback(() => {
    setFailed(null);
    const fail = (what: string) => (e: unknown) => (setFailed(what), toast.add({ type: "error", title: `Couldn't load ${what}`, description: apiError(e, "Try again.") }));
    if (current === "invoices") {
      setInvoices(null);
      InvoicesApi.list({ from, to }).then(setInvoices).catch((e) => (setInvoices([]), fail("invoices")(e)));
    } else if (current === "quotations") {
      setQuotes(null);
      QuotationsApi.list({ from, to }).then(setQuotes).catch((e) => (setQuotes([]), fail("quotations")(e)));
    } else if (current === "claims") {
      setClaims(null);
      ClaimsApi.list(claimView, { from, to }).then(setClaims).catch((e) => (setClaims([]), fail("claims")(e)));
    } else if (current === "payments") {
      setPayments(null);
      ReceivablesApi.payments({ from, to }).then(setPayments).catch((e) => (setPayments([]), fail("payments")(e)));
    } else if (current === "ageing") {
      setAgeing(null);
      ReceivablesApi.ageing().then(setAgeing).catch(fail("ageing"));
    }
  }, [current, from, to, claimView]);
  React.useEffect(() => load(), [load]);

  const may = (t: Tab) => (a: string) => loaded && can(PAGES[t], a);

  if (!loaded)
    return (
      <Loading what="invoices" columns={6} rows={6} toolbar={1} numeric={[3, 4]} footer />
    );

  return (
    <div className="medora mx-auto w-full max-w-6xl space-y-4">
      <MedoraPageHeader
        title="Receivables"
        description="Invoices, quotations, scheme claims and payments received."
        primary={
          current === "invoices" && may("invoices")("Create")
            ? { label: "New invoice", icon: PlusIcon, onSelect: () => setDraft({ customerId: "", lines: [{ id: 1, product: "", qty: "1", price: "", vat: 0 }] }) }
            : current === "quotations" && may("quotations")("Create")
              ? { label: "New quotation", icon: PlusIcon, onSelect: () => newQuote.current?.() }
              : undefined
        }
      />
      {!current ? (
        <p className="text-sm text-muted-foreground">Your role can&apos;t see receivables.</p>
      ) : (
        <>
          <div className="flex flex-wrap items-end justify-between gap-3">
            <Tabs value={current} onValueChange={(v) => (setTab(v as Tab), setDraft(null))}>
              <TabsList variant="line">
                {tabs.map((t) => (
                  <TabsTrigger key={t} value={t} className="flex-none">
                    {LABEL[t]}
                  </TabsTrigger>
                ))}
              </TabsList>
            </Tabs>
            {current !== "ageing" && !(current === "claims" && claimView === "open") ? (
              <Surface className="flex gap-2">
                <Field className="w-40">
                  <FieldLabel htmlFor="rc-from">From</FieldLabel>
                  <Input id="rc-from" type="date" value={from} max={to} onChange={(e) => e.target.value && setFrom(e.target.value)} />
                </Field>
                <Field className="w-40">
                  <FieldLabel htmlFor="rc-to">To</FieldLabel>
                  <Input id="rc-to" type="date" value={to} min={from} onChange={(e) => e.target.value && setTo(e.target.value)} />
                </Field>
              </Surface>
            ) : null}
          </div>

          {failed ? <PanelError framed what={failed} onRetry={load} /> : null}
          {shown === "invoices" ? <InvoicesView rows={invoices} reload={load} items={items} customers={customers} may={may("invoices")} draft={draft} onDraft={setDraft} printedBy={printedBy} /> : null}
          {shown === "quotations" ? (
            <QuotationsView
              rows={quotes}
              reload={load}
              items={items}
              customers={customers}
              may={may("quotations")}
              canInvoice={can("Accounts/Invoices", "Create")}
              canSell={can("POS/POS sales", "Create")}
              onInvoice={(d) => (setTab("invoices"), setDraft(d))}
              newRef={newQuote}
              printedBy={printedBy}
            />
          ) : null}
          {shown === "claims" ? <ClaimsView rows={claims} view={claimView} onView={setClaimView} reload={load} may={may("claims")} /> : null}
          {shown === "payments" ? (
            payments ? (
              <PaymentRecords rows={payments} partyLabel="Customer" cumulative />
            ) : (
              <Loading what="payments" columns={5} rows={6} numeric={[4]} />
            )
          ) : null}
          {shown === "ageing" ? (
            ageing ? (
              <div className="space-y-3">
                {/* The design's chart container (chart spec: one white surface per chart) */}
                <ChartCard title="Ageing by customer" height="">
                  <AgeingChart rows={ageing.rows} />
                </ChartCard>
                <p className="text-sm text-muted-foreground">
                  {ageing.note}
                  {ageing.draftClaims ? ` Draft claims not yet submitted: ${kes(ageing.draftClaims)}.` : ""}
                </p>
              </div>
            ) : (
              <Loading what="ageing" shape="chart" />
            )
          ) : null}
        </>
      )}
    </div>
  );
}
