import { useMemo, useState, ReactNode } from "react";
import { Head } from "@inertiajs/react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import AdminLayout from "@/layouts/AdminLayout";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import {
  Table, TableBody, TableCell, TableHead, TableHeader, TableRow,
} from "@/components/ui/table";
import {
  Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
} from "@/components/ui/select";
import {
  Dialog, DialogContent, DialogHeader, DialogTitle,
} from "@/components/ui/dialog";
import { Calendar } from "@/components/ui/calendar";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { format, subDays, startOfMonth } from "date-fns";
import {
  Search, Scale, ExternalLink, RefreshCw, CheckCircle2, AlertTriangle,
  XCircle, Copy, CreditCard, Calendar as CalendarIcon, Loader2, ClipboardCheck, Download,
} from "lucide-react";
import { toast } from "sonner";
import { grossCents } from "@/lib/vat";
import { exportToCSV } from "@/lib/csv-export";

const csrfToken = () =>
  (document.querySelector('meta[name="csrf-token"]') as HTMLMetaElement | null)?.content ?? "";

const jsonHeaders = () => ({
  "Content-Type": "application/json",
  Accept: "application/json",
  "X-Requested-With": "XMLHttpRequest",
  "X-CSRF-TOKEN": csrfToken(),
});

const gbp = (cents: number) => `£${(cents / 100).toFixed(2)}`;

const statusConfig: Record<string, { class: string; label: string }> = {
  pending: { class: "bg-yellow-500/10 text-yellow-600 border-yellow-500/30", label: "Pending" },
  paid: { class: "bg-green-500/10 text-green-600 border-green-500/30", label: "Paid" },
  confirmed: { class: "bg-blue-500/10 text-blue-600 border-blue-500/30", label: "Confirmed" },
  complete: { class: "bg-emerald-500/10 text-emerald-600 border-emerald-500/30", label: "Complete" },
  completed: { class: "bg-emerald-500/10 text-emerald-600 border-emerald-500/30", label: "Completed" },
  cancelled: { class: "bg-red-500/10 text-red-600 border-red-500/30", label: "Cancelled" },
  refunded: { class: "bg-purple-500/10 text-purple-600 border-purple-500/30", label: "Refunded" },
  payment_failed: { class: "bg-red-500/10 text-red-600 border-red-500/30", label: "Payment failed" },
};

const stripeStatusClass = (status?: string) => {
  switch (status) {
    case "succeeded": return "bg-green-500/10 text-green-600 border-green-500/30";
    case "processing": return "bg-blue-500/10 text-blue-600 border-blue-500/30";
    case "canceled": return "bg-red-500/10 text-red-600 border-red-500/30";
    default: return "bg-amber-500/10 text-amber-600 border-amber-500/30";
  }
};

const copyToClipboard = (value: string) => {
  navigator.clipboard?.writeText(value).then(
    () => toast.success("Copied"),
    () => toast.error("Could not copy"),
  );
};

// Live Stripe panel — fetches the PaymentIntent and renders the DB-vs-Stripe
// comparison. Reused by both the order detail dialog and the PI lookup dialog.
function StripePanel({ orderId, paymentIntent }: { orderId?: string; paymentIntent?: string }) {
  const params = new URLSearchParams();
  if (orderId) params.set("order_id", orderId);
  if (paymentIntent) params.set("payment_intent", paymentIntent);

  const { data, isLoading, isError, error, refetch, isFetching } = useQuery({
    queryKey: ["recon-stripe", orderId, paymentIntent],
    enabled: !!(orderId || paymentIntent),
    retry: false,
    queryFn: async () => {
      const res = await fetch(`/api/admin/reconciliation/stripe?${params.toString()}`);
      const body = await res.json().catch(() => null);
      if (!res.ok) throw new Error(body?.error || "Failed to load Stripe data");
      return body;
    },
  });

  if (isLoading) {
    return (
      <div className="flex items-center justify-center gap-2 py-8 text-muted-foreground text-sm">
        <Loader2 className="w-4 h-4 animate-spin" /> Loading from Stripe…
      </div>
    );
  }

  if (isError) {
    return (
      <div className="rounded-lg border border-amber-500/40 bg-amber-500/5 p-4 text-sm">
        <div className="flex items-center gap-2 text-amber-700 font-medium">
          <AlertTriangle className="w-4 h-4" /> Stripe lookup failed
        </div>
        <p className="text-muted-foreground mt-1">{(error as Error)?.message}</p>
        <Button variant="outline" size="sm" className="mt-3" onClick={() => refetch()}>
          <RefreshCw className="w-3.5 h-3.5 mr-1.5" /> Retry
        </Button>
      </div>
    );
  }

  if (!data) return null;

  return (
    <div className="space-y-4">
      {/* Discrepancy banner */}
      <div className="space-y-1.5">
        {(data.discrepancies ?? []).map((d: any, i: number) => {
          const Icon = d.level === "ok" ? CheckCircle2 : d.level === "error" ? XCircle : AlertTriangle;
          const cls =
            d.level === "ok" ? "border-green-500/40 bg-green-500/5 text-green-700"
              : d.level === "error" ? "border-red-500/40 bg-red-500/5 text-red-700"
                : "border-amber-500/40 bg-amber-500/5 text-amber-700";
          return (
            <div key={i} className={`flex items-start gap-2 rounded-md border px-3 py-2 text-sm ${cls}`}>
              <Icon className="w-4 h-4 mt-0.5 shrink-0" />
              <span>{d.message}</span>
            </div>
          );
        })}
      </div>

      {/* Stripe facts */}
      <div className="rounded-lg border border-border divide-y divide-border text-sm">
        <Row label="Stripe status">
          <Badge variant="outline" className={stripeStatusClass(data.status)}>{data.status}</Badge>
          {!data.livemode && <span className="ml-2 text-[10px] uppercase tracking-wide text-muted-foreground">test mode</span>}
        </Row>
        <Row label="Amount charged"><span className="font-medium">{gbp(data.amount)} {data.currency?.toUpperCase()}</span></Row>
        <Row label="Expected (orders incl. VAT)"><span className="font-medium">{gbp(data.expected_gross_cents)}</span></Row>
        {data.amount_refunded > 0 && <Row label="Refunded on Stripe"><span className="font-medium text-destructive">-{gbp(data.amount_refunded)}</span></Row>}
        {data.application_fee_amount > 0 && <Row label="Platform fee"><span className="font-medium">{gbp(data.application_fee_amount)}</span></Row>}
        {(data.card_brand || data.card_last4) && (
          <Row label="Card"><span className="font-medium capitalize">{data.card_brand} •••• {data.card_last4}</span></Row>
        )}
        {data.account_id && <Row label="Connected account"><span className="font-mono text-xs">{data.account_id}</span></Row>}
        <Row label="Payment intent">
          <span className="font-mono text-xs break-all">{data.payment_intent}</span>
          <button onClick={() => copyToClipboard(data.payment_intent)} className="ml-1.5 text-muted-foreground hover:text-foreground">
            <Copy className="w-3 h-3 inline" />
          </button>
        </Row>
        {data.created && <Row label="Created"><span className="text-muted-foreground">{format(new Date(data.created), "dd MMM yyyy 'at' HH:mm")}</span></Row>}
      </div>

      <div className="flex flex-wrap gap-2">
        {data.dashboard_url && (
          <a href={data.dashboard_url} target="_blank" rel="noopener noreferrer">
            <Button size="sm" className="gap-1.5">
              Open in Stripe <ExternalLink className="w-3.5 h-3.5" />
            </Button>
          </a>
        )}
        {data.receipt_url && (
          <a href={data.receipt_url} target="_blank" rel="noopener noreferrer">
            <Button size="sm" variant="outline" className="gap-1.5">
              Receipt <ExternalLink className="w-3.5 h-3.5" />
            </Button>
          </a>
        )}
        <Button size="sm" variant="outline" onClick={() => refetch()} disabled={isFetching} className="gap-1.5">
          <RefreshCw className={`w-3.5 h-3.5 ${isFetching ? "animate-spin" : ""}`} /> Refresh
        </Button>
      </div>

      {/* Orders sharing this payment intent (multi-item carts) */}
      {(data.matched_orders?.length ?? 0) > 0 && (
        <div className="rounded-lg border border-border">
          <div className="px-3 py-2 text-xs font-semibold text-muted-foreground border-b border-border">
            Linked order(s) on this payment ({data.matched_orders.length})
          </div>
          <div className="divide-y divide-border">
            {data.matched_orders.map((o: any) => (
              <div key={o.id} className="px-3 py-2 flex items-center justify-between text-sm">
                <div>
                  <div className="font-medium">{o.customer_name || "—"}</div>
                  <div className="text-muted-foreground text-xs font-mono">#{o.id.slice(0, 8)}</div>
                </div>
                <div className="flex items-center gap-2">
                  <span className="font-medium">{gbp(grossCents(o.price_cents))}</span>
                  <Badge variant="outline" className={statusConfig[o.status]?.class || ""}>
                    {statusConfig[o.status]?.label || o.status}
                  </Badge>
                </div>
              </div>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

const Row = ({ label, children }: { label: string; children: ReactNode }) => (
  <div className="flex items-center justify-between gap-4 px-3 py-2">
    <span className="text-muted-foreground text-xs">{label}</span>
    <span className="text-right">{children}</span>
  </div>
);

const Reconciliation = () => {
  const queryClient = useQueryClient();
  const [search, setSearch] = useState("");
  const [methodFilter, setMethodFilter] = useState("stripe");
  const [statusFilter, setStatusFilter] = useState("all");
  const [reconciledFilter, setReconciledFilter] = useState("all");
  const [dateRange, setDateRange] = useState<{ from: Date; to: Date } | null>(null);
  const [selectedOrder, setSelectedOrder] = useState<any | null>(null);
  const [note, setNote] = useState("");
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
  const [piLookup, setPiLookup] = useState("");
  const [activeLookup, setActiveLookup] = useState<string | null>(null);

  const { data, isLoading } = useQuery({
    queryKey: ["recon-list", methodFilter, statusFilter, reconciledFilter, dateRange],
    queryFn: async () => {
      const params = new URLSearchParams();
      params.set("payment_method", methodFilter);
      if (statusFilter !== "all") params.set("status", statusFilter);
      if (reconciledFilter !== "all") params.set("reconciled", reconciledFilter);
      if (dateRange) {
        params.set("from", format(dateRange.from, "yyyy-MM-dd"));
        params.set("to", format(dateRange.to, "yyyy-MM-dd"));
      }
      const res = await fetch(`/api/admin/reconciliation?${params.toString()}`);
      if (!res.ok) return { orders: [], summary: { total: 0, reconciled: 0, unreconciled: 0 } };
      return res.json();
    },
  });

  const orders: any[] = data?.orders ?? [];
  const summary = data?.summary ?? { total: 0, reconciled: 0, unreconciled: 0 };

  const filtered = useMemo(() => {
    if (!search) return orders;
    const s = search.toLowerCase();
    return orders.filter((o) =>
      o.stripe_payment_intent_id?.toLowerCase().includes(s) ||
      o.customer_name?.toLowerCase().includes(s) ||
      o.customer_email?.toLowerCase().includes(s) ||
      o.courses?.title?.toLowerCase().includes(s) ||
      o.id?.toLowerCase().includes(s),
    );
  }, [orders, search]);

  const reconcileMutation = useMutation({
    mutationFn: async ({ id, note }: { id: string; note?: string }) => {
      const res = await fetch(`/api/admin/reconciliation/${id}/reconcile`, {
        method: "POST", headers: jsonHeaders(), body: JSON.stringify({ note: note || null }),
      });
      if (!res.ok) throw new Error("Failed");
      return res.json();
    },
    onSuccess: () => {
      toast.success("Marked reconciled");
      queryClient.invalidateQueries({ queryKey: ["recon-list"] });
      setSelectedOrder(null);
      setNote("");
    },
    onError: () => toast.error("Could not mark reconciled"),
  });

  const unreconcileMutation = useMutation({
    mutationFn: async (id: string) => {
      const res = await fetch(`/api/admin/reconciliation/${id}/unreconcile`, {
        method: "POST", headers: jsonHeaders(),
      });
      if (!res.ok) throw new Error("Failed");
      return res.json();
    },
    onSuccess: () => {
      toast.success("Reconciliation cleared");
      queryClient.invalidateQueries({ queryKey: ["recon-list"] });
      setSelectedOrder(null);
    },
    onError: () => toast.error("Could not clear reconciliation"),
  });

  const bulkMutation = useMutation({
    mutationFn: async (ids: string[]) => {
      const res = await fetch(`/api/admin/reconciliation/bulk-reconcile`, {
        method: "POST", headers: jsonHeaders(), body: JSON.stringify({ ids }),
      });
      if (!res.ok) throw new Error("Failed");
      return res.json();
    },
    onSuccess: (r: any) => {
      toast.success(`Marked ${r.count ?? 0} reconciled`);
      queryClient.invalidateQueries({ queryKey: ["recon-list"] });
      setSelectedIds(new Set());
    },
    onError: () => toast.error("Bulk reconcile failed"),
  });

  const toggleId = (id: string) => {
    setSelectedIds((prev) => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });
  };

  const allVisibleSelected = filtered.length > 0 && filtered.every((o) => selectedIds.has(o.id));
  const toggleAll = () => {
    setSelectedIds(allVisibleSelected ? new Set() : new Set(filtered.map((o) => o.id)));
  };

  const openOrder = (order: any) => {
    setSelectedOrder(order);
    setNote(order.reconciliation_note || "");
  };

  // Export the current filtered view. CSV opens natively in Excel (matches the
  // Orders page export); amounts are gross (incl-VAT) to mirror what Stripe shows.
  const handleExport = () => {
    if (!filtered.length) return;
    exportToCSV(
      filtered.map((o: any) => ({
        order_id: o.id,
        order_date: format(new Date(o.created_at), "yyyy-MM-dd HH:mm"),
        customer_name: o.customer_name || "",
        customer_email: o.customer_email || "",
        company: o.training_companies?.name || "",
        course: o.courses?.title || "",
        payment_method: o.payment_method || "",
        amount_incl_vat_gbp: (grossCents(o.price_cents) / 100).toFixed(2),
        refund_incl_vat_gbp: (grossCents(o.refund_cents || 0) / 100).toFixed(2),
        net_incl_vat_gbp: (o.expected_gross_cents / 100).toFixed(2),
        status: o.status,
        payment_intent: o.stripe_payment_intent_id || "",
        reconciled: o.reconciled_at ? "Yes" : "No",
        reconciled_at: o.reconciled_at ? format(new Date(o.reconciled_at), "yyyy-MM-dd HH:mm") : "",
        reconciliation_note: o.reconciliation_note || "",
        stripe_dashboard_url: o.dashboard_url || "",
      })),
      `reconciliation-${format(new Date(), "yyyy-MM-dd")}`,
    );
  };

  return (
    <>
      <Head title="Reconciliation" />
      <div>
        <div className="flex items-center justify-between mb-6">
          <div className="flex items-center gap-2">
            <Scale className="w-6 h-6 text-primary" />
            <h1 className="text-2xl font-bold text-foreground">Payment Reconciliation</h1>
          </div>
          <Button variant="outline" size="sm" onClick={handleExport} disabled={!filtered.length}>
            <Download className="h-4 w-4 mr-1.5" /> Export to Excel
          </Button>
        </div>

        {/* Summary */}
        <div className="grid grid-cols-3 gap-4 mb-6">
          <div className="bg-card border border-border rounded-xl p-4">
            <div className="flex items-center gap-2 text-muted-foreground text-xs mb-1">
              <CreditCard className="w-3.5 h-3.5" /> In view
            </div>
            <p className="text-2xl font-bold text-foreground">{summary.total}</p>
          </div>
          <div className="bg-card border border-border rounded-xl p-4">
            <div className="flex items-center gap-2 text-muted-foreground text-xs mb-1">
              <CheckCircle2 className="w-3.5 h-3.5" /> Reconciled
            </div>
            <p className="text-2xl font-bold text-green-600">{summary.reconciled}</p>
          </div>
          <div className="bg-card border border-border rounded-xl p-4">
            <div className="flex items-center gap-2 text-muted-foreground text-xs mb-1">
              <AlertTriangle className="w-3.5 h-3.5" /> Unreconciled
            </div>
            <p className="text-2xl font-bold text-amber-600">{summary.unreconciled}</p>
          </div>
        </div>

        {/* Payment-intent lookup */}
        <div className="bg-card border border-border rounded-xl p-4 mb-6">
          <Label className="text-xs text-muted-foreground">Look up a Stripe payment intent</Label>
          <div className="flex gap-2 mt-1.5">
            <div className="relative flex-1 max-w-md">
              <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
              <Input
                placeholder="pi_..."
                value={piLookup}
                onChange={(e) => setPiLookup(e.target.value)}
                onKeyDown={(e) => { if (e.key === "Enter" && piLookup.trim()) setActiveLookup(piLookup.trim()); }}
                className="pl-9 font-mono"
              />
            </div>
            <Button disabled={!piLookup.trim()} onClick={() => setActiveLookup(piLookup.trim())}>
              Look up
            </Button>
          </div>
        </div>

        {/* Filters */}
        <div className="flex flex-col sm:flex-row sm:flex-wrap gap-3 mb-6">
          <div className="relative flex-1 min-w-[240px] max-w-md">
            <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
            <Input placeholder="Search payment intent, order id, email, course…" value={search} onChange={(e) => setSearch(e.target.value)} className="pl-9" />
          </div>
          <Select value={methodFilter} onValueChange={setMethodFilter}>
            <SelectTrigger className="w-[160px]"><SelectValue /></SelectTrigger>
            <SelectContent>
              <SelectItem value="stripe">Card (Stripe)</SelectItem>
              <SelectItem value="all">All methods</SelectItem>
            </SelectContent>
          </Select>
          <Select value={statusFilter} onValueChange={setStatusFilter}>
            <SelectTrigger className="w-[160px]"><SelectValue placeholder="Status" /></SelectTrigger>
            <SelectContent>
              <SelectItem value="all">All statuses</SelectItem>
              <SelectItem value="paid">Paid</SelectItem>
              <SelectItem value="complete">Complete</SelectItem>
              <SelectItem value="refunded">Refunded</SelectItem>
              <SelectItem value="cancelled">Cancelled</SelectItem>
              <SelectItem value="payment_failed">Payment failed</SelectItem>
              <SelectItem value="pending">Pending</SelectItem>
            </SelectContent>
          </Select>
          <Select value={reconciledFilter} onValueChange={setReconciledFilter}>
            <SelectTrigger className="w-[170px]"><SelectValue /></SelectTrigger>
            <SelectContent>
              <SelectItem value="all">All</SelectItem>
              <SelectItem value="no">Unreconciled only</SelectItem>
              <SelectItem value="yes">Reconciled only</SelectItem>
            </SelectContent>
          </Select>
          <Popover>
            <PopoverTrigger asChild>
              <Button variant="outline" size="sm" className="gap-1.5">
                <CalendarIcon className="h-4 w-4" />
                {dateRange ? `${format(dateRange.from, "dd MMM")} – ${format(dateRange.to, "dd MMM yyyy")}` : "All dates"}
              </Button>
            </PopoverTrigger>
            <PopoverContent className="w-auto p-3" align="end">
              <div className="flex flex-wrap gap-1.5 mb-3">
                <Button size="sm" variant="outline" onClick={() => setDateRange({ from: subDays(new Date(), 6), to: new Date() })}>Last 7 days</Button>
                <Button size="sm" variant="outline" onClick={() => setDateRange({ from: subDays(new Date(), 29), to: new Date() })}>Last 30 days</Button>
                <Button size="sm" variant="outline" onClick={() => setDateRange({ from: subDays(new Date(), 89), to: new Date() })}>Last 90 days</Button>
                <Button size="sm" variant="outline" onClick={() => setDateRange({ from: startOfMonth(new Date()), to: new Date() })}>This month</Button>
              </div>
              <Calendar
                mode="range"
                selected={dateRange ? { from: dateRange.from, to: dateRange.to } : undefined}
                onSelect={(range: any) => { if (range?.from) setDateRange({ from: range.from, to: range.to || range.from }); }}
                numberOfMonths={2}
                className="p-0 pointer-events-auto"
              />
            </PopoverContent>
          </Popover>
          {dateRange && (
            <Button variant="outline" size="sm" className="gap-1.5" onClick={() => setDateRange(null)}>
              Clear dates <XCircle className="w-3.5 h-3.5" />
            </Button>
          )}
        </div>

        {/* Bulk bar */}
        {selectedIds.size > 0 && (
          <div className="flex items-center justify-between bg-primary/5 border border-primary/20 rounded-lg px-4 py-2.5 mb-3">
            <span className="text-sm font-medium">{selectedIds.size} selected</span>
            <div className="flex gap-2">
              <Button size="sm" variant="ghost" onClick={() => setSelectedIds(new Set())}>Clear</Button>
              <Button size="sm" disabled={bulkMutation.isPending} onClick={() => bulkMutation.mutate([...selectedIds])}>
                <ClipboardCheck className="w-3.5 h-3.5 mr-1.5" /> Mark {selectedIds.size} reconciled
              </Button>
            </div>
          </div>
        )}

        {/* Table */}
        <div className="bg-card border border-border rounded-xl overflow-x-auto">
          <Table className="text-xs">
            <TableHeader>
              <TableRow>
                <TableHead className="w-8">
                  <input type="checkbox" checked={allVisibleSelected} onChange={toggleAll} className="cursor-pointer" />
                </TableHead>
                <TableHead className="whitespace-nowrap">Order Date</TableHead>
                <TableHead>Customer</TableHead>
                <TableHead>Course</TableHead>
                <TableHead className="text-right whitespace-nowrap">Amount</TableHead>
                <TableHead>Status</TableHead>
                <TableHead>Payment Intent</TableHead>
                <TableHead>Reconciled</TableHead>
                <TableHead className="text-right">Stripe</TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {isLoading ? (
                <TableRow><TableCell colSpan={9} className="text-center text-muted-foreground py-12">Loading…</TableCell></TableRow>
              ) : !filtered.length ? (
                <TableRow><TableCell colSpan={9} className="text-center text-muted-foreground py-12">No payments found</TableCell></TableRow>
              ) : (
                filtered.map((order) => (
                  <TableRow key={order.id} className="cursor-pointer hover:bg-muted/30" onClick={() => openOrder(order)}>
                    <TableCell onClick={(e) => e.stopPropagation()}>
                      <input type="checkbox" checked={selectedIds.has(order.id)} onChange={() => toggleId(order.id)} className="cursor-pointer" />
                    </TableCell>
                    <TableCell className="text-muted-foreground whitespace-nowrap">
                      {format(new Date(order.created_at), "dd MMM yy")}
                    </TableCell>
                    <TableCell>
                      <div className="font-medium text-foreground">{order.customer_name}</div>
                      <div className="text-muted-foreground" style={{ fontSize: "10px" }}>{order.customer_email}</div>
                    </TableCell>
                    <TableCell className="max-w-[180px] truncate">{order.courses?.title || "—"}</TableCell>
                    <TableCell className="font-semibold text-right whitespace-nowrap">{gbp(order.expected_gross_cents)}</TableCell>
                    <TableCell className="whitespace-nowrap">
                      <Badge variant="outline" className={statusConfig[order.status]?.class || ""}>
                        {statusConfig[order.status]?.label || order.status}
                      </Badge>
                    </TableCell>
                    <TableCell onClick={(e) => e.stopPropagation()}>
                      {order.stripe_payment_intent_id ? (
                        <span className="inline-flex items-center gap-1">
                          <span className="font-mono text-[10px] text-muted-foreground">{order.stripe_payment_intent_id.slice(0, 14)}…</span>
                          <button onClick={() => copyToClipboard(order.stripe_payment_intent_id)} className="text-muted-foreground hover:text-foreground">
                            <Copy className="w-3 h-3" />
                          </button>
                        </span>
                      ) : <span className="text-muted-foreground">—</span>}
                    </TableCell>
                    <TableCell className="whitespace-nowrap">
                      {order.reconciled_at ? (
                        <Badge variant="outline" className="bg-green-500/10 text-green-600 border-green-500/30">
                          <CheckCircle2 className="w-3 h-3 mr-1" /> {format(new Date(order.reconciled_at), "dd MMM yy")}
                        </Badge>
                      ) : <span className="text-muted-foreground">—</span>}
                    </TableCell>
                    <TableCell className="text-right" onClick={(e) => e.stopPropagation()}>
                      {order.dashboard_url ? (
                        <a href={order.dashboard_url} target="_blank" rel="noopener noreferrer">
                          <Button size="sm" variant="outline" className="gap-1 h-7">
                            View <ExternalLink className="w-3 h-3" />
                          </Button>
                        </a>
                      ) : <span className="text-muted-foreground">—</span>}
                    </TableCell>
                  </TableRow>
                ))
              )}
            </TableBody>
          </Table>
        </div>

        {/* Order detail dialog */}
        <Dialog open={!!selectedOrder} onOpenChange={(open) => { if (!open) setSelectedOrder(null); }}>
          <DialogContent className="sm:max-w-2xl max-h-[85vh] overflow-y-auto">
            <DialogHeader>
              <DialogTitle className="flex items-center gap-2">
                <Scale className="w-5 h-5 text-primary" /> Reconcile payment
              </DialogTitle>
            </DialogHeader>
            {selectedOrder && (
              <div className="space-y-5">
                {/* Order summary */}
                <div className="rounded-lg border border-border divide-y divide-border text-sm">
                  <Row label="Order"><span className="font-mono text-xs">#{selectedOrder.id.slice(0, 8)}</span></Row>
                  <Row label="Placed"><span className="text-muted-foreground">{format(new Date(selectedOrder.created_at), "dd MMM yyyy 'at' HH:mm")}</span></Row>
                  <Row label="Customer"><span className="font-medium">{selectedOrder.customer_name}</span></Row>
                  <Row label="Course"><span className="font-medium">{selectedOrder.courses?.title || "—"}</span></Row>
                  <Row label="Order status">
                    <Badge variant="outline" className={statusConfig[selectedOrder.status]?.class || ""}>
                      {statusConfig[selectedOrder.status]?.label || selectedOrder.status}
                    </Badge>
                  </Row>
                  <Row label="Order total (incl. VAT)"><span className="font-medium">{gbp(selectedOrder.expected_gross_cents)}</span></Row>
                  {selectedOrder.refund_cents > 0 && (
                    <Row label="Refund recorded"><span className="font-medium text-destructive">-{gbp(grossCents(selectedOrder.refund_cents))}</span></Row>
                  )}
                </div>

                {/* Live Stripe comparison */}
                <div>
                  <h4 className="text-sm font-semibold flex items-center gap-2 mb-2">
                    <CreditCard className="w-4 h-4" /> Live Stripe data
                  </h4>
                  <StripePanel orderId={selectedOrder.id} />
                </div>

                {/* Reconcile actions */}
                <div className="border-t border-border pt-4 space-y-3">
                  {selectedOrder.reconciled_at ? (
                    <div className="flex items-center justify-between gap-3">
                      <p className="text-sm text-green-700 flex items-center gap-1.5">
                        <CheckCircle2 className="w-4 h-4" />
                        Reconciled {format(new Date(selectedOrder.reconciled_at), "dd MMM yyyy 'at' HH:mm")}
                        {selectedOrder.reconciliation_note ? ` — ${selectedOrder.reconciliation_note}` : ""}
                      </p>
                      <Button variant="outline" size="sm" disabled={unreconcileMutation.isPending}
                        onClick={() => unreconcileMutation.mutate(selectedOrder.id)}>
                        Unreconcile
                      </Button>
                    </div>
                  ) : (
                    <>
                      <div>
                        <Label className="text-xs text-muted-foreground">Note (optional)</Label>
                        <Textarea value={note} onChange={(e) => setNote(e.target.value)} placeholder="e.g. matched to Stripe payout 12 Jun" className="mt-1" rows={2} />
                      </div>
                      <Button className="w-full" disabled={reconcileMutation.isPending}
                        onClick={() => reconcileMutation.mutate({ id: selectedOrder.id, note })}>
                        <ClipboardCheck className="w-4 h-4 mr-2" />
                        {reconcileMutation.isPending ? "Saving…" : "Mark reconciled"}
                      </Button>
                    </>
                  )}
                </div>
              </div>
            )}
          </DialogContent>
        </Dialog>

        {/* PI lookup dialog */}
        <Dialog open={!!activeLookup} onOpenChange={(open) => { if (!open) setActiveLookup(null); }}>
          <DialogContent className="sm:max-w-2xl max-h-[85vh] overflow-y-auto">
            <DialogHeader>
              <DialogTitle className="flex items-center gap-2">
                <Search className="w-5 h-5 text-primary" /> Payment intent lookup
              </DialogTitle>
            </DialogHeader>
            {activeLookup && <StripePanel paymentIntent={activeLookup} />}
          </DialogContent>
        </Dialog>
      </div>
    </>
  );
};

Reconciliation.layout = (page: ReactNode) => <AdminLayout>{page}</AdminLayout>;

export default Reconciliation;
