"use client";

/**
 * Quotations (AC-15; plan H): the design's `QuotationsList`, `QuotationForm` for a new one and `QuoteCheck` when
 * converting, against today's prices and stock. A quotation becomes an invoice here (registered customers) or a sale
 * at the till (`/pos?quote=<id>`). It reserves no stock and takes no payment.
 */

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

import { QuoteCheck } from "@/components/medora/accounts-ops";
import { DocumentSheet, PrintButton, VAT_CLASS, type VatClass } from "@/components/medora/print";
import { QuotationsList } from "@/components/medora/record-lists";
import { QuotationForm, quoteProblems, type QuoteDraft } from "@/components/medora/registers";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Field, FieldLabel } from "@/components/ui/field";
import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select";
import { Spinner } from "@/components/ui/spinner";
import { Switch } from "@/components/ui/switch";
import { toast } from "@/components/ui/toast";
import { QuotationsApi, type QuotationCheck, type QuotationDetail, type QuotationRow } from "@/lib/api";
import { useSettings } from "@/lib/SettingsContext";

import type { InvoiceDraft } from "./invoices-view";
import { apiError, kes, localStamp, today, type Customer, type Item } from "./shared";
import { Loading } from "@/components/medora/loading";

export function QuotationsView({ rows, reload, items, customers, may, canInvoice, canSell, onInvoice, printedBy, newRef }: {
  rows: QuotationRow[] | null;
  reload: () => void;
  items: Item[];
  customers: Customer[];
  may: (a: string) => boolean;
  canInvoice: boolean;
  canSell: boolean;
  onInvoice: (d: InvoiceDraft) => void;
  printedBy: string;
  /** R2 (card 037): the page header's "New quotation" opens the form through it. */
  newRef?: React.RefObject<(() => void) | null>;
}) {
  const router = useRouter();
  const [draft, setDraft] = React.useState<QuoteDraft | null>(null);
  React.useEffect(() => {
    if (!newRef) return;
    newRef.current = () => (setTried(false), setDraft({ customer: "", date: today(), validDays: "14", lines: [{ id: 1, product: "", qty: "1", price: "", vat: 0 }], note: "" }));
    return () => {
      newRef.current = null;
    };
  });
  const [tried, setTried] = React.useState(false);
  const [busy, setBusy] = React.useState(false);
  const [printing, setPrinting] = React.useState<QuotationDetail | null>(null);
  const [checking, setChecking] = React.useState<QuotationCheck | null>(null);
  const [honour, setHonour] = React.useState(true);
  const [customerFor, setCustomerFor] = React.useState("");

  const prices = React.useMemo(() => Object.fromEntries(items.map((i) => [i.name, { price: i.price, vat: i.vat }])), [items]);
  const byNo = (no: string) => rows?.find((r) => r.number === no);

  const save = async () => {
    if (!draft) return;
    setTried(true);
    const byName = new Map(items.map((i) => [i.name, i]));
    const unknown = draft.lines.filter((l) => l.product.trim() && !byName.has(l.product.trim()));
    if (quoteProblems(draft).length || unknown.length) return;
    setBusy(true);
    try {
      const cust = customers.find((c) => c.name.toLowerCase() === draft.customer.trim().toLowerCase());
      const q = await QuotationsApi.create({
        customerId: cust?.id, customerName: draft.customer.trim(), validDays: Number(draft.validDays), note: draft.note.trim() || undefined,
        items: draft.lines.map((l) => ({ productId: byName.get(l.product.trim())!.id, quantity: Number(l.qty), unitPrice: Number(l.price.replace(/,/g, "")) })),
      });
      toast.add({ title: `Quotation ${q.number} saved`, description: `${kes(q.total)} for ${q.customer}, valid to ${q.validUntil}.` });
      setDraft(null);
      setPrinting(q);
      reload();
    } catch (e) {
      toast.add({ type: "error", title: "Quotation not saved", description: apiError(e, "Try again.") });
    } finally {
      setBusy(false);
    }
  };

  const convert = async (no: string) => {
    const q = byNo(no);
    if (!q) return;
    try {
      const c = await QuotationsApi.check(q.id);
      setHonour(!c.expired);
      setCustomerFor(c.quotation.customerId ? String(c.quotation.customerId) : "");
      setChecking(c);
    } catch (e) {
      toast.add({ type: "error", title: "Couldn't check the quotation", description: apiError(e, "Try again.") });
    }
  };

  const toInvoice = () => {
    if (!checking) return;
    const byId = new Map(items.map((i) => [i.id, i]));
    onInvoice({
      customerId: customerFor,
      quotationId: checking.quotation.id,
      quotationNo: checking.quotation.number,
      lines: checking.lines.filter((l) => !l.missing).map((l, k) => ({ id: k + 1, product: byId.get(l.productId)?.name ?? l.name, qty: String(l.qty), price: String(honour ? l.quoted : l.current), vat: byId.get(l.productId)?.vat ?? 0 })),
    });
    setChecking(null);
  };

  if (!rows)
    return (
      <Loading what="quotations" columns={6} rows={5} toolbar={1} numeric={[4]} />
    );

  const quoteSheet = printing;
  return (
    <div className="space-y-4">
      <QuotationsList
        today={today()}
        rows={rows.map((r) => ({ no: r.number, date: r.date, customer: r.customer, total: r.total, validDays: r.validDays, status: r.status === "Expired" ? "Open" : r.status, convertedTo: r.convertedTo ?? undefined, cancelReason: r.cancelReason ?? undefined }))}
        onConvert={(no) => (may("Update") || canSell ? void convert(no) : toast.add({ type: "error", title: "You can't convert quotations" }))}
        onCancel={(no, reason) => {
          const q = byNo(no);
          if (!q) return;
          if (!may("Delete")) return toast.add({ type: "error", title: "You can't cancel quotations" });
          QuotationsApi.cancel(q.id, reason)
            .then(() => (toast.add({ title: `${no} cancelled` }), reload()))
            .catch((e) => toast.add({ type: "error", title: "Not cancelled", description: apiError(e, "Try again.") }));
        }}
      />

      <Dialog open={!!draft} onOpenChange={(o) => !o && !busy && setDraft(null)}>
        <DialogContent className="sm:max-w-3xl">
          <DialogHeader>
            <DialogTitle>New quotation</DialogTitle>
            <DialogDescription>It reserves no stock and takes no payment. Prices start from today&apos;s and can be changed.</DialogDescription>
          </DialogHeader>
          {draft ? (
            <>
              <QuotationForm d={draft} onChange={setDraft} customers={customers.map((c) => c.name)} prices={prices} />
              {tried ? (
                <ul className="list-disc space-y-0.5 pl-5 text-sm text-status-error-text">
                  {[...quoteProblems(draft), ...draft.lines.filter((l) => l.product.trim() && !prices[l.product.trim()]).map((l) => `${l.product}: choose an item from the list.`)].map((p) => (
                    <li key={p}>{p}</li>
                  ))}
                </ul>
              ) : null}
            </>
          ) : null}
          <DialogFooter>
            <Button variant="outline" disabled={busy} onClick={() => setDraft(null)}>
              Cancel
            </Button>
            <Button disabled={busy} onClick={() => void save()}>
              {busy ? <Spinner /> : null}
              Save quotation
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog open={!!checking} onOpenChange={(o) => !o && setChecking(null)}>
        <DialogContent className="sm:max-w-3xl">
          <DialogHeader>
            <DialogTitle>Convert {checking?.quotation.number}</DialogTitle>
            <DialogDescription>{checking?.expired ? "This quotation has expired: check the prices before honouring them." : "Each line against today's price and the stock there is."}</DialogDescription>
          </DialogHeader>
          {checking ? (
            <div className="space-y-3">
              <label className="flex items-center gap-2 text-sm">
                <Switch checked={honour} onCheckedChange={setHonour} /> Honour the quoted prices
              </label>
              <QuoteCheck honour={honour} lines={checking.lines.map((l) => ({ id: l.id, name: l.missing ? `${l.name} (no longer sold)` : l.name, qty: l.qty, quoted: l.quoted, current: l.current, inStock: l.inStock }))} />
              {canInvoice ? (
                <Field>
                  <FieldLabel htmlFor="qc-cust">Invoice to</FieldLabel>
                  <NativeSelect id="qc-cust" value={customerFor} onChange={(e) => setCustomerFor(e.target.value)}>
                    <NativeSelectOption value="">Choose a registered customer</NativeSelectOption>
                    {customers.map((c) => (
                      <NativeSelectOption key={c.id} value={String(c.id)}>
                        {c.name}
                      </NativeSelectOption>
                    ))}
                  </NativeSelect>
                </Field>
              ) : null}
            </div>
          ) : null}
          <DialogFooter>
            {canSell && checking ? (
              <Button variant="outline" onClick={() => router.push(`/pos?quote=${checking.quotation.id}`)}>
                <ShoppingCartIcon data-icon="inline-start" />
                Sell at the till
              </Button>
            ) : null}
            {canInvoice ? (
              <Button disabled={!customerFor} onClick={toInvoice}>
                Raise invoice…
              </Button>
            ) : null}
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <QuotePrint q={quoteSheet} printedBy={printedBy} onClose={() => setPrinting(null)} />
    </div>
  );
}

function QuotePrint({ q, printedBy, onClose }: { q: QuotationDetail | null; printedBy: string; onClose: () => void }) {
  const { settings } = useSettings();
  const ref = React.useRef<HTMLDivElement>(null);
  return (
    <Dialog open={!!q} onOpenChange={(o) => !o && onClose()}>
      <DialogContent className="sm:max-w-4xl">
        <DialogHeader>
          <DialogTitle>Quotation {q?.number}</DialogTitle>
          <DialogDescription>Saved. Print it for the customer.</DialogDescription>
        </DialogHeader>
        {q ? (
          <div className="max-h-[65svh] overflow-auto rounded-md bg-muted/40 p-3">
            <DocumentSheet
              ref={ref}
              kind="quotation"
              issuer={{ name: settings.store_name || "Pharmacy", branch: q.branch ?? "", address: settings.store_address ? [settings.store_address] : [], phone: settings.store_phone || undefined, email: settings.store_email || undefined }}
              party={{ name: q.customer }}
              reference={q.number}
              date={q.date}
              validUntil={q.validUntil}
              lines={q.lines.map((l) => ({ code: l.code, name: l.name, unit: l.unit ?? undefined, qty: l.qty, price: l.price, discount: l.discount || undefined, vat: (q.isEtims ? (l.taxCode && l.taxCode in VAT_CLASS ? l.taxCode : "B") : "D") as VatClass }))}
              printedBy={printedBy}
              printedAt={localStamp(new Date())}
              notes={q.note ? [q.note] : []}
            />
          </div>
        ) : null}
        <DialogFooter>
          <Button variant="outline" onClick={onClose}>
            Close
          </Button>
          <PrintButton target={ref} paper="a4" label="Print quotation" variant="default" />
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
