import { createFileRoute } from "@tanstack/react-router";
import { useEffect, useMemo, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useServerFn } from "@tanstack/react-start";
import { toast } from "sonner";
import { Check, FileText, Loader2, Plus, Receipt, Send, Trash2, X } from "lucide-react";
import { AppShell } from "@/components/AppShell";
import { supabase } from "@/integrations/supabase/client";
import { useAuth } from "@/lib/use-auth";
import { createQuotation, setInvoiceStatus, setQuotationStatus } from "@/lib/billing.functions";
import { buildBillingPdf } from "@/lib/billing-pdf";
import { downloadBlob, loadLogoDataUrl, shareEmail, shareWhatsApp } from "@/lib/report-actions";
import { COMPANY } from "@/lib/company";
import { COUNTRY_LIST, computeTotals, country, formatDate, formatMoney, type CountryCode } from "@/lib/locale";

export const Route = createFileRoute("/_authenticated/quotes")({
  head: () => ({
    meta: [
      { title: "Quotations & Invoices | Emma Mold Inspection Services" },
      {
        name: "description",
        content:
          "Track mold inspection quotations from draft to accepted, and download branded invoices with totals, VAT and bank details.",
      },
      { property: "og:title", content: "Quotations & Invoices" },
      { property: "og:description", content: "Itemised quotations, automatic invoicing and branded PDF exports." },
      { property: "og:type", content: "website" },
      { name: "twitter:card", content: "summary_large_image" },
    ],
  }),
  component: QuotesPage,
});

const STATUS_TONE: Record<string, string> = {
  draft: "bg-muted text-muted-foreground",
  sent: "bg-accent/15 text-accent-foreground",
  viewed: "bg-primary/10 text-primary",
  accepted: "bg-emerald-500/15 text-emerald-700",
  rejected: "bg-destructive/10 text-destructive",
  expired: "bg-muted text-muted-foreground",
  unpaid: "bg-amber-500/15 text-amber-700",
  partially_paid: "bg-amber-500/15 text-amber-700",
  paid: "bg-emerald-500/15 text-emerald-700",
  overdue: "bg-destructive/10 text-destructive",
  void: "bg-muted text-muted-foreground",
};

function Badge({ status }: { status: string }) {
  return (
    <span className={`rounded-full px-2.5 py-1 text-[11px] font-semibold capitalize ${STATUS_TONE[status] ?? "bg-muted"}`}>
      {status.replace("_", " ")}
    </span>
  );
}

type Item = { description: string; quantity: number; unit_price: number };

function QuotesPage() {
  const { user, companyId, isAdmin, isProvider } = useAuth();
  const qc = useQueryClient();
  const canIssue = isAdmin || isProvider;
  const [logo, setLogo] = useState<string | null>(null);
  useEffect(() => {
    loadLogoDataUrl().then(setLogo);
  }, []);

  const quotes = useQuery({
    queryKey: ["quotations", user?.id],
    enabled: Boolean(user),
    queryFn: async () => {
      const { data, error } = await supabase
        .from("quotations")
        .select("*, quotation_items(description,quantity,unit_price)")
        .order("created_at", { ascending: false });
      if (error) throw error;
      return data ?? [];
    },
  });

  const invoices = useQuery({
    queryKey: ["invoices", user?.id],
    enabled: Boolean(user),
    queryFn: async () => {
      const { data, error } = await supabase
        .from("invoices")
        .select("*, invoice_items(description,quantity,unit_price)")
        .order("created_at", { ascending: false });
      if (error) throw error;
      return data ?? [];
    },
  });

  const changeStatus = useServerFn(setQuotationStatus);
  const changeInvoice = useServerFn(setInvoiceStatus);
  const create = useServerFn(createQuotation);

  const statusMutation = useMutation({
    mutationFn: (vars: { quotationId: string; status: "draft" | "sent" | "viewed" | "accepted" | "rejected" | "expired" }) =>
      changeStatus({ data: vars }),
    onSuccess: async (res) => {
      await qc.invalidateQueries({ queryKey: ["quotations"] });
      await qc.invalidateQueries({ queryKey: ["invoices"] });
      toast.success(res.invoice ? `Accepted — invoice ${res.invoice.invoice_no} created.` : "Quotation updated.");
    },
    onError: (e: Error) => toast.error(e.message || "Could not update this quotation."),
  });

  const invoiceMutation = useMutation({
    mutationFn: (vars: { invoiceId: string; status: "unpaid" | "partially_paid" | "paid" | "overdue" | "void" }) =>
      changeInvoice({ data: vars }),
    onSuccess: async () => {
      await qc.invalidateQueries({ queryKey: ["invoices"] });
      toast.success("Invoice updated.");
    },
    onError: (e: Error) => toast.error(e.message || "Could not update this invoice."),
  });

  async function pdfFor(kind: "Quotation" | "Invoice", record: Record<string, unknown>, items: Item[]) {
    const blob = await buildBillingPdf({
      kind,
      reference: String(record[kind === "Invoice" ? "invoice_no" : "reference"] ?? ""),
      issuedAt: String(record.created_at),
      validUntil: (record.valid_until as string | null) ?? null,
      dueDate: (record.due_date as string | null) ?? null,
      status: String(record.status ?? ""),
      country: (record.country as string) ?? "NG",
      provider: { name: COMPANY.name, email: COMPANY.email, phone: COMPANY.phone, address: COMPANY.address, logoDataUrl: logo },
      customer: {
        name: (record.customer_name as string) ?? null,
        email: (record.customer_email as string) ?? null,
        phone: (record.customer_phone as string) ?? null,
        address: (record.property_address as string) ?? null,
      },
      items,
      subtotal: Number(record.subtotal ?? 0),
      discount: Number(record.discount ?? 0),
      vatRate: Number(record.vat_rate ?? 0),
      vatAmount: Number(record.vat_amount ?? 0),
      total: Number(record.total ?? 0),
      bank:
        kind === "Invoice"
          ? {
              bank: (record.bank_name as string) ?? null,
              accountName: (record.bank_account_name as string) ?? null,
              accountNumber: (record.bank_account_number as string) ?? null,
            }
          : null,
      notes: (record.notes as string) ?? null,
    });
    return blob;
  }

  return (
    <AppShell>
      <h1 className="flex items-center gap-2 text-2xl font-bold">
        <FileText className="h-6 w-6 text-primary" /> Quotations & Invoices
      </h1>
      <p className="mt-1 text-sm text-muted-foreground">
        Itemised quotations move from Draft to Sent, Viewed and Accepted. Accepting one creates a branded invoice
        automatically.
      </p>

      {canIssue ? <NewQuotation companyId={companyId} onCreate={create} /> : null}

      <section className="mt-6">
        <h2 className="text-sm font-semibold uppercase tracking-widest text-muted-foreground">Quotations</h2>
        {quotes.isLoading ? (
          <p className="mt-3 text-sm text-muted-foreground">Loading quotations…</p>
        ) : !quotes.data?.length ? (
          <p className="mt-3 rounded-2xl bg-muted p-4 text-sm text-muted-foreground">No quotations yet.</p>
        ) : (
          <ul className="mt-3 space-y-3">
            {quotes.data.map((q) => {
              const items = (q.quotation_items ?? []) as Item[];
              const mine = q.user_id === user?.id;
              return (
                <li key={q.id} className="rounded-3xl border border-border/60 bg-card p-4 shadow-card">
                  <div className="flex items-start justify-between gap-3">
                    <div>
                      <p className="text-sm font-semibold">{q.reference}</p>
                      <p className="text-xs text-muted-foreground">
                        {formatDate(q.created_at, q.country)} · {q.customer_name ?? "Customer"}
                        {q.valid_until ? ` · valid until ${formatDate(q.valid_until, q.country)}` : ""}
                      </p>
                    </div>
                    <Badge status={q.status} />
                  </div>
                  <ul className="mt-3 divide-y divide-border rounded-2xl border border-border/60 text-sm">
                    {items.map((i, idx) => (
                      <li key={`${q.id}-${idx}`} className="flex justify-between gap-3 px-3 py-2">
                        <span className="text-muted-foreground">
                          {i.description} × {i.quantity}
                        </span>
                        <span className="font-semibold">{formatMoney(i.quantity * i.unit_price, q.country)}</span>
                      </li>
                    ))}
                  </ul>
                  <div className="mt-2 space-y-1 text-xs text-muted-foreground">
                    <p className="flex justify-between">
                      <span>Subtotal</span> <span>{formatMoney(Number(q.subtotal), q.country)}</span>
                    </p>
                    {Number(q.discount) ? (
                      <p className="flex justify-between">
                        <span>Discount</span> <span>- {formatMoney(Number(q.discount), q.country)}</span>
                      </p>
                    ) : null}
                    <p className="flex justify-between">
                      <span>VAT ({q.vat_rate}%)</span> <span>{formatMoney(Number(q.vat_amount), q.country)}</span>
                    </p>
                    <p className="flex justify-between text-sm font-bold text-foreground">
                      <span>Total</span> <span>{formatMoney(Number(q.total), q.country)}</span>
                    </p>
                  </div>

                  <div className="mt-3 flex flex-wrap gap-2">
                    <button
                      onClick={async () => downloadBlob(await pdfFor("Quotation", q, items), `${q.reference}.pdf`)}
                      className="rounded-xl border border-border px-3 py-2 text-xs font-semibold"
                    >
                      Download PDF
                    </button>
                    <button
                      onClick={() => shareWhatsApp(`Quotation ${q.reference} — ${formatMoney(Number(q.total), q.country)}`)}
                      className="rounded-xl border border-border px-3 py-2 text-xs font-semibold"
                    >
                      WhatsApp
                    </button>
                    <button
                      onClick={() =>
                        shareEmail(`Quotation ${q.reference}`, `Total: ${formatMoney(Number(q.total), q.country)}`)
                      }
                      className="rounded-xl border border-border px-3 py-2 text-xs font-semibold"
                    >
                      Email
                    </button>
                    {canIssue && q.status === "draft" ? (
                      <button
                        onClick={() => statusMutation.mutate({ quotationId: q.id, status: "sent" })}
                        className="flex items-center gap-1 rounded-xl bg-brand px-3 py-2 text-xs font-semibold text-primary-foreground"
                      >
                        <Send className="h-3.5 w-3.5" /> Send to customer
                      </button>
                    ) : null}
                    {canIssue && ["sent", "viewed"].includes(q.status) ? (
                      <button
                        onClick={() => statusMutation.mutate({ quotationId: q.id, status: "expired" })}
                        className="rounded-xl border border-border px-3 py-2 text-xs font-semibold"
                      >
                        Mark expired
                      </button>
                    ) : null}
                    {mine && ["sent", "viewed"].includes(q.status) ? (
                      <>
                        <button
                          onClick={() => statusMutation.mutate({ quotationId: q.id, status: "accepted" })}
                          className="flex items-center gap-1 rounded-xl bg-brand px-3 py-2 text-xs font-semibold text-primary-foreground"
                        >
                          <Check className="h-3.5 w-3.5" /> Accept
                        </button>
                        <button
                          onClick={() => statusMutation.mutate({ quotationId: q.id, status: "rejected" })}
                          className="flex items-center gap-1 rounded-xl border border-border px-3 py-2 text-xs font-semibold"
                        >
                          <X className="h-3.5 w-3.5" /> Reject
                        </button>
                      </>
                    ) : null}
                  </div>
                </li>
              );
            })}
          </ul>
        )}
      </section>

      <section className="mt-8">
        <h2 className="flex items-center gap-2 text-sm font-semibold uppercase tracking-widest text-muted-foreground">
          <Receipt className="h-4 w-4" /> Invoices
        </h2>
        {!invoices.data?.length ? (
          <p className="mt-3 rounded-2xl bg-muted p-4 text-sm text-muted-foreground">
            Invoices are created automatically when a quotation is accepted.
          </p>
        ) : (
          <ul className="mt-3 space-y-3">
            {invoices.data.map((inv) => (
              <li key={inv.id} className="rounded-3xl border border-border/60 bg-card p-4 shadow-card">
                <div className="flex items-start justify-between gap-3">
                  <div>
                    <p className="text-sm font-semibold">{inv.invoice_no}</p>
                    <p className="text-xs text-muted-foreground">
                      Due {formatDate(inv.due_date, inv.country)} · {formatMoney(Number(inv.total), inv.country)}
                    </p>
                  </div>
                  <Badge status={inv.status} />
                </div>
                <div className="mt-3 flex flex-wrap gap-2">
                  <button
                    onClick={async () =>
                      downloadBlob(
                        await pdfFor("Invoice", inv, (inv.invoice_items ?? []) as Item[]),
                        `${inv.invoice_no}.pdf`,
                      )
                    }
                    className="rounded-xl border border-border px-3 py-2 text-xs font-semibold"
                  >
                    Download invoice PDF
                  </button>
                  {canIssue && inv.status !== "paid" ? (
                    <button
                      onClick={() => invoiceMutation.mutate({ invoiceId: inv.id, status: "paid" })}
                      className="rounded-xl bg-brand px-3 py-2 text-xs font-semibold text-primary-foreground"
                    >
                      Mark as paid
                    </button>
                  ) : null}
                </div>
              </li>
            ))}
          </ul>
        )}
      </section>
    </AppShell>
  );
}

function NewQuotation({
  companyId,
  onCreate,
}: {
  companyId: string | null;
  onCreate: ReturnType<typeof useServerFn<typeof createQuotation>>;
}) {
  const qc = useQueryClient();
  const [open, setOpen] = useState(false);
  const [busy, setBusy] = useState(false);
  const [customerId, setCustomerId] = useState("");
  const [customerName, setCustomerName] = useState("");
  const [address, setAddress] = useState("");
  const [cc, setCc] = useState<CountryCode>("NG");
  const [discount, setDiscount] = useState(0);
  const [validUntil, setValidUntil] = useState("");
  const [items, setItems] = useState<Item[]>([{ description: "Mold inspection visit", quantity: 1, unit_price: 0 }]);

  const config = country(cc);
  const totals = useMemo(() => computeTotals(items, discount, cc), [items, discount, cc]);

  function patch(index: number, next: Partial<Item>) {
    setItems((prev) => prev.map((item, i) => (i === index ? { ...item, ...next } : item)));
  }

  async function submit() {
    const ref = customerId.trim();
    if (!ref) return toast.error("Enter the customer's email address or account ID.");
    const cleanItems = items
      .map((i) => ({
        description: i.description.trim(),
        quantity: Number(i.quantity) || 0,
        unit_price: Number(i.unit_price) || 0,
      }))
      .filter((i) => i.description.length > 0);
    if (!cleanItems.length) return toast.error("Add at least one line item with a description.");
    setBusy(true);
    try {
      await onCreate({
        data: {
          companyId,
          userId: ref,
          country: cc,
          currency: config.currency,
          customerName: customerName || null,
          propertyAddress: address || null,
          discount,
          vatRate: config.vatRate,
          validUntil: validUntil || null,
          items: cleanItems,
        },
      });
      await qc.invalidateQueries({ queryKey: ["quotations"] });
      toast.success("Quotation created as a draft.");
      setOpen(false);
    } catch (error) {
      toast.error(error instanceof Error ? error.message : "Could not create the quotation.");
    } finally {
      setBusy(false);
    }
  }

  if (!open)
    return (
      <button
        onClick={() => setOpen(true)}
        className="mt-4 flex w-full items-center justify-center gap-2 rounded-2xl bg-brand py-3 text-sm font-semibold text-primary-foreground"
      >
        <Plus className="h-4 w-4" /> New quotation
      </button>
    );

  return (
    <section className="mt-4 rounded-3xl border border-border/60 bg-card p-4 shadow-card">
      <h2 className="text-sm font-semibold">New quotation</h2>
      <div className="mt-3 grid gap-2 sm:grid-cols-2">
        <input
          value={customerId}
          onChange={(e) => setCustomerId(e.target.value)}
          placeholder="Customer email or account ID"
          className="rounded-xl border border-input bg-background px-3 py-2.5 text-sm"
        />
        <input
          value={customerName}
          onChange={(e) => setCustomerName(e.target.value)}
          placeholder="Customer name"
          className="rounded-xl border border-input bg-background px-3 py-2.5 text-sm"
        />
        <input
          value={address}
          onChange={(e) => setAddress(e.target.value)}
          placeholder="Property address"
          className="rounded-xl border border-input bg-background px-3 py-2.5 text-sm sm:col-span-2"
        />
        <select
          value={cc}
          onChange={(e) => setCc(e.target.value as CountryCode)}
          className="rounded-xl border border-input bg-background px-3 py-2.5 text-sm"
        >
          {COUNTRY_LIST.map((c) => (
            <option key={c.code} value={c.code}>
              {c.name} ({c.symbol})
            </option>
          ))}
        </select>
        <input
          type="date"
          value={validUntil}
          onChange={(e) => setValidUntil(e.target.value)}
          className="rounded-xl border border-input bg-background px-3 py-2.5 text-sm"
        />
      </div>

      <div className="mt-3 space-y-2">
        {items.map((item, index) => (
          <div key={index} className="grid grid-cols-[1fr_60px_90px_32px] gap-2">
            <input
              value={item.description}
              onChange={(e) => patch(index, { description: e.target.value })}
              placeholder="Service description"
              className="rounded-xl border border-input bg-background px-3 py-2 text-sm"
            />
            <input
              type="number"
              value={item.quantity}
              onChange={(e) => patch(index, { quantity: Number(e.target.value) })}
              className="rounded-xl border border-input bg-background px-2 py-2 text-sm"
            />
            <input
              type="number"
              value={item.unit_price}
              onChange={(e) => patch(index, { unit_price: Number(e.target.value) })}
              className="rounded-xl border border-input bg-background px-2 py-2 text-sm"
            />
            <button
              aria-label="Remove item"
              onClick={() => setItems((prev) => prev.filter((_, i) => i !== index))}
              className="rounded-xl border border-border text-muted-foreground"
            >
              <Trash2 className="mx-auto h-4 w-4" />
            </button>
          </div>
        ))}
        <button
          onClick={() => setItems((prev) => [...prev, { description: "", quantity: 1, unit_price: 0 }])}
          className="rounded-xl border border-border px-3 py-2 text-xs font-semibold"
        >
          Add line item
        </button>
      </div>

      <div className="mt-3 flex items-center gap-2">
        <label className="text-xs text-muted-foreground" htmlFor="quote-discount">
          Discount
        </label>
        <input
          id="quote-discount"
          type="number"
          value={discount}
          onChange={(e) => setDiscount(Number(e.target.value))}
          className="w-28 rounded-xl border border-input bg-background px-3 py-2 text-sm"
        />
      </div>

      <dl className="mt-3 space-y-1 text-xs text-muted-foreground">
        <div className="flex justify-between">
          <dt>Subtotal</dt>
          <dd>{formatMoney(totals.subtotal, cc)}</dd>
        </div>
        <div className="flex justify-between">
          <dt>{config.vatLabel}</dt>
          <dd>{formatMoney(totals.vatAmount, cc)}</dd>
        </div>
        <div className="flex justify-between text-sm font-bold text-foreground">
          <dt>Total</dt>
          <dd>{formatMoney(totals.total, cc)}</dd>
        </div>
      </dl>

      <div className="mt-3 flex gap-2">
        <button onClick={() => setOpen(false)} className="flex-1 rounded-2xl border border-border py-3 text-sm font-semibold">
          Cancel
        </button>
        <button
          onClick={submit}
          disabled={busy}
          className="flex flex-1 items-center justify-center gap-2 rounded-2xl bg-brand py-3 text-sm font-semibold text-primary-foreground disabled:opacity-50"
        >
          {busy ? <Loader2 className="h-4 w-4 animate-spin" /> : null} Save draft
        </button>
      </div>
    </section>
  );
}