"use client";

/**
 * Preorders (PRD 2.4, PS-14), on the Medora design system and plan E (DECISIONS.md, 26 Oct 2026): the design's
 * `PreorderForm` and preorder list with `preorderBadge`. A deposit is a payment on the customer's account (Q1), so a
 * customer is found by their mobile number or registered with it. "Turn into a sale" opens the till with the basket
 * and the customer; the deposit covers that much of the total. Telling the customer is by phone until SMS (plan M).
 */

import * as React from "react";
import { useRouter } from "next/navigation";
import { PhoneIcon, PlusIcon, ShoppingCartIcon, XIcon } from "lucide-react";

import { RecordDrawer } from "@/components/medora/drawer";
import { PanelError } from "@/components/medora/errors";
import { MedoraPageHeader } from "@/components/medora/page-header";
import { PreorderForm, preorderBadge } from "@/components/medora/pos-ops";
import { RowActions } from "@/components/medora/row-actions";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Field, FieldDescription, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select";
import { Spinner } from "@/components/ui/spinner";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { toast } from "@/components/ui/toast";
import { PreordersApi, ProductsApi, type PreorderRow } from "@/lib/api";
import { formatPhone, formatKES } from "@/lib/format";
import { useMenuPermissions } from "@/lib/permissions";
import { Loading } from "@/components/medora/loading";

const PAGE = "POS/Preorders";
const METHODS = ["Cash", "M-Pesa", "Card"] as const;

const apiError = (e: unknown, fallback: string): string => {
  const m = (e as { response?: { data?: { message?: string | string[] } } })?.response?.data?.message;
  return Array.isArray(m) ? m.join(" ") : m || fallback;
};
const kes = (n: number) => formatKES(n, { decimals: true });
const when = (v: string | null) => (v ? new Date(v).toLocaleString("en-GB", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" }) : "");

type Item = { id: number; name: string; price: number };

export default function PreordersPage() {
  const router = useRouter();
  const { can, loaded } = useMenuPermissions();
  const may = (a: string) => loaded && can(PAGE, a);
  const [view, setView] = React.useState<"open" | "closed">("open");
  const [rows, setRows] = React.useState<PreorderRow[] | null>(null);
  const [failed, setFailed] = React.useState(false); // R12 (card 037): a failed load says so, with Try again
  const [items, setItems] = React.useState<Item[]>([]);
  const [formKey, setFormKey] = React.useState(0);
  const [taking, setTaking] = React.useState(false);
  const [method, setMethod] = React.useState<(typeof METHODS)[number]>("Cash");
  const [reference, setReference] = React.useState("");
  const [cancelling, setCancelling] = React.useState<PreorderRow | null>(null);
  const [cancel, setCancel] = React.useState({ reason: "", refund: true, method: "Cash" as string });
  const [busy, setBusy] = React.useState(false);

  const load = React.useCallback(async () => {
    setRows(null);
    try {
      setRows(await PreordersApi.list(view));
      setFailed(false);
    } catch (e) {
      setRows([]);
      setFailed(true);
      toast.add({ type: "error", title: "Couldn't load preorders", description: apiError(e, "Try again.") });
    }
  }, [view]);
  React.useEffect(() => {
    void load();
  }, [load]);

  // Items that hold stock (services and products without stock are never waited for)
  React.useEffect(() => {
    ProductsApi.getAll()
      .then((ps: { id: number; name: string; sellPrice: number | string; type?: string; manageStock?: boolean }[]) =>
        setItems(ps.filter((p) => p.type !== "Service" && p.manageStock !== false).map((p) => ({ id: p.id, name: p.name, price: Number(p.sellPrice) || 0 })).sort((a, b) => a.name.localeCompare(b.name))),
      )
      .catch(() => setItems([]));
  }, []);

  const told = async (p: PreorderRow) => {
    try {
      await PreordersApi.told(p.id);
      toast.add({ title: `${p.customer} told`, description: `${p.number}: stock arrived.` });
      await load();
    } catch (e) {
      toast.add({ type: "error", title: "Not recorded", description: apiError(e, "Try again.") });
    }
  };

  const doCancel = async () => {
    if (!cancelling) return;
    setBusy(true);
    try {
      await PreordersApi.cancel(cancelling.id, { reason: cancel.reason.trim(), refund: cancelling.deposit > 0 ? cancel.refund : undefined, method: cancel.refund ? cancel.method : undefined });
      toast.add({ title: `${cancelling.number} cancelled`, description: cancelling.deposit ? (cancel.refund ? `${kes(cancelling.deposit)} refunded by ${cancel.method}.` : `${kes(cancelling.deposit)} kept on ${cancelling.customer}'s account.`) : undefined });
      setCancelling(null);
      await load();
    } catch (e) {
      toast.add({ type: "error", title: "Not cancelled", description: apiError(e, "Try again.") });
    } finally {
      setBusy(false);
    }
  };

  // Names are unique enough for the form's select; the first product with the name is the one ordered
  const idOf = (name: string) => items.find((i) => i.name === name)?.id;

  return (
    <div className="medora mx-auto w-full max-w-6xl space-y-4">
      <MedoraPageHeader
        title="Preorders"
        description="Items a customer wants that aren't in stock, with an optional deposit."
       
        primary={may("Create") ? { label: "Take a preorder", icon: PlusIcon, onSelect: () => setTaking(true) } : undefined}
      />

      {/* R2 (card 037): the list comes first; taking a preorder opens from the header. */}
      <RecordDrawer open={taking && may("Create")} onOpenChange={(o) => !o && setTaking(false)} title="Take a preorder" subtitle="Who, what and how many, with an optional deposit.">
        <div className="space-y-3">
          <div className="grid gap-3">
            <Field>
              <FieldLabel htmlFor="pre-method">Deposit paid by</FieldLabel>
              <NativeSelect id="pre-method" value={method} onChange={(e) => setMethod(e.target.value as (typeof METHODS)[number])}>
                {METHODS.map((m) => (
                  <NativeSelectOption key={m}>{m}</NativeSelectOption>
                ))}
              </NativeSelect>
              <FieldDescription>Only used when there&apos;s a deposit. It goes on the customer&apos;s account.</FieldDescription>
            </Field>
            {method !== "Cash" ? (
              <Field>
                <FieldLabel htmlFor="pre-ref">{method === "M-Pesa" ? "M-Pesa code" : "Approval code"}</FieldLabel>
                <Input id="pre-ref" value={reference} onChange={(e) => setReference(e.target.value.toUpperCase())} />
              </Field>
            ) : null}
          </div>
          <PreorderForm
            key={formKey}
            items={items}
            onSave={async (p) => {
              const productId = idOf(p.item);
              if (!productId) return;
              try {
                const saved: { number: string } = await PreordersApi.create({ customer: p.customer, phone: p.phone, productId, quantity: p.qty, deposit: p.deposit || undefined, method: p.deposit ? method : undefined, reference: p.deposit ? reference.trim() || undefined : undefined });
                toast.add({ title: `Preorder ${saved.number} saved`, description: `Call ${p.customer} on ${formatPhone(p.phone)} when ${p.item} arrives.` });
                setReference("");
                setTaking(false);
                setView("open");
                await load();
              } catch (e) {
                toast.add({ type: "error", title: "Preorder not saved", description: apiError(e, "Enter it again.") });
                setFormKey((k) => k + 1);
              }
            }}
          />
        </div>
      </RecordDrawer>

      <Tabs value={view} onValueChange={(v) => setView(v as "open" | "closed")}>
        {/* Views of the same list: segmented control (tabs spec 7.2, PS-14) */}
        <TabsList>
          <TabsTrigger value="open">
            Open
          </TabsTrigger>
          <TabsTrigger value="closed">
            Collected and cancelled
          </TabsTrigger>
        </TabsList>
      </Tabs>

      {failed ? (
        <PanelError framed what="preorders" onRetry={() => void load()} />
      ) : rows === null ? (
        <Loading what="preorders" columns={5} rows={4} numeric={[3]} />
      ) : (
        <div className="overflow-x-auto rounded-lg border border-[var(--color-border-panel)] bg-card">
          <Table>
            <TableHeader>
              <TableRow>
                <TableHead>Order</TableHead>
                <TableHead>Customer</TableHead>
                <TableHead>Item</TableHead>
                <TableHead className="text-right">Deposit</TableHead>
                <TableHead>Status</TableHead>
                <TableHead className="w-10">
                  <span className="sr-only">Actions</span>
                </TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {rows.map((p) => (
                <TableRow key={p.id}>
                  <TableCell className="font-mono text-xs">
                    {p.number}
                    <span className="block font-sans text-muted-foreground">
                      {when(p.placedAt)}
                      {p.branch ? ` · ${p.branch}` : ""}
                    </span>
                  </TableCell>
                  <TableCell>
                    {p.customer}
                    <span className="block text-xs text-muted-foreground tabular-nums">{formatPhone(p.phone)}</span>
                  </TableCell>
                  <TableCell className="whitespace-normal">
                    {p.product} × {p.quantity}
                    <span className="block text-xs text-muted-foreground">
                      {p.status === "Active" ? `${p.available.toLocaleString("en-US")} in stock · now ${kes(p.price * p.quantity)}` : p.receiptId ? `Sale ${p.receiptId}` : p.cancelReason ?? ""}
                    </span>
                  </TableCell>
                  <TableCell className="text-right tabular-nums">
                    {p.deposit ? kes(p.deposit) : "–"}
                    {p.status === "Cancelled" && p.deposit ? <span className="block text-xs text-muted-foreground">{p.refunded ? "Refunded" : "Kept on account"}</span> : null}
                  </TableCell>
                  <TableCell>
                    {preorderBadge(p.state)}
                    {p.notifiedAt ? <span className="mt-0.5 block text-xs text-muted-foreground">Told {when(p.notifiedAt)}</span> : null}
                  </TableCell>
                  <TableCell>
                    {p.status === "Active" && may("Update") ? (
                      <RowActions
                        label={p.number}
                        actions={[
                          ...(p.state === "Stock arrived" ? [{ label: "Customer told (phone)", icon: PhoneIcon, onSelect: () => void told(p) }] : []),
                          ...(loaded && can("POS/POS sales", "Create") ? [{ label: "Turn into a sale", icon: ShoppingCartIcon, onSelect: () => router.push(`/pos?preorder=${p.id}`) }] : []),
                          { label: p.deposit ? "Cancel (deposit back or kept)" : "Cancel", icon: XIcon, destructive: true, onSelect: () => (setCancel({ reason: "", refund: true, method: "Cash" }), setCancelling(p)) },
                        ]}
                      />
                    ) : null}
                  </TableCell>
                </TableRow>
              ))}
              {!rows.length ? (
                <TableRow>
                  <TableCell colSpan={6} className="py-10 text-center text-muted-foreground">
                    {view === "open" ? "No open preorders." : "Nothing collected or cancelled yet."}
                  </TableCell>
                </TableRow>
              ) : null}
            </TableBody>
          </Table>
        </div>
      )}

      <Dialog open={!!cancelling} onOpenChange={(o) => !o && !busy && setCancelling(null)}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Cancel {cancelling?.number}?</DialogTitle>
            <DialogDescription>
              {cancelling?.product} × {cancelling?.quantity} for {cancelling?.customer}.
            </DialogDescription>
          </DialogHeader>
          <div className="space-y-3">
            <Field>
              <FieldLabel htmlFor="pc-reason">Why</FieldLabel>
              <Input id="pc-reason" value={cancel.reason} onChange={(e) => setCancel({ ...cancel, reason: e.target.value })} />
            </Field>
            {cancelling?.deposit ? (
              <>
                <Field>
                  <FieldLabel htmlFor="pc-dep">The {kes(cancelling.deposit)} deposit</FieldLabel>
                  <NativeSelect id="pc-dep" value={cancel.refund ? "refund" : "keep"} onChange={(e) => setCancel({ ...cancel, refund: e.target.value === "refund" })}>
                    <NativeSelectOption value="refund">Give it back now</NativeSelectOption>
                    <NativeSelectOption value="keep">Keep it on the customer&apos;s account</NativeSelectOption>
                  </NativeSelect>
                </Field>
                {cancel.refund ? (
                  <Field>
                    <FieldLabel htmlFor="pc-method">Given back by</FieldLabel>
                    <NativeSelect id="pc-method" value={cancel.method} onChange={(e) => setCancel({ ...cancel, method: e.target.value })}>
                      {METHODS.map((m) => (
                        <NativeSelectOption key={m}>{m}</NativeSelectOption>
                      ))}
                    </NativeSelect>
                  </Field>
                ) : null}
              </>
            ) : null}
          </div>
          <DialogFooter>
            <Button variant="outline" disabled={busy} onClick={() => setCancelling(null)}>
              Keep the preorder
            </Button>
            <Button variant="destructive" disabled={busy || cancel.reason.trim().length < 3} onClick={() => void doCancel()}>
              {busy ? <Spinner /> : null}
              Cancel preorder
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
