import { useState, useMemo, useEffect, ReactNode } from "react";
import { Head, Link } from '@inertiajs/react';
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import AdminLayout from '@/layouts/AdminLayout';
import { useAuth } from "@/hooks/useAuth";
import { useRolePreview } from "@/contexts/RolePreviewContext";
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 { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
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, DialogFooter,
} from "@/components/ui/dialog";
import {
  AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent,
  AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { Calendar } from "@/components/ui/calendar";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { format, startOfDay, endOfDay, startOfMonth, subDays, isWithinInterval, differenceInDays } from "date-fns";
import {
  Search, Users, MapPin, Building2, CreditCard, Undo2, XCircle,
  ShoppingCart, TrendingUp, AlertTriangle, ChevronDown, ChevronUp, ChevronsUpDown,
  QrCode, CheckCircle2, ClipboardList, Send, Download, Upload, Pencil, Calendar as CalendarIcon,
  ScrollText, ExternalLink,
} from "lucide-react";
import { toast } from "sonner";
import { OrderQRCode } from "@/components/admin/OrderQRCode";
import { exportToCSV } from "@/lib/csv-export";
import OrderInvoiceButton from "@/components/admin/OrderInvoiceButton";
import EditDelegateDialog from "@/components/admin/EditDelegateDialog";
import { RequestDateChange } from "@/components/RequestDateChange";
import { grossCents, vatCents } from "@/lib/vat";

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

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" },
  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" },
};

const paymentMethodLabels: Record<string, string> = {
  stripe: "Card",
  invoice: "Pay on Invoice",
  credit: "Pay on Invoice",
  company_credit: "Pay on Invoice",
  discount: "Discount Code",
};

const INVOICE_METHODS = new Set(["invoice", "credit", "company_credit"]);

const SubmissionView = ({ submission }: { submission: any }) => {
  const data = (() => {
    try {
      return typeof submission.form_data === 'string'
        ? JSON.parse(submission.form_data)
        : submission.form_data || {};
    } catch {
      return {};
    }
  })();

  // Pull signatures from the dedicated columns first, fall back to form_data
  // so older submissions (where assessor_signature wasn't stored on the column)
  // still render correctly.
  const candidateSig = submission.candidate_signature || data.candidate_signature;
  const assessorSig = submission.assessor_signature || data.assessor_signature;

  const SIGNATURE_KEYS = new Set(['candidate_signature', 'assessor_signature']);
  const fieldEntries = Object.entries(data).filter(
    ([k, v]) => !SIGNATURE_KEYS.has(k) && v !== null && v !== undefined && v !== '',
  );

  return (
    <div className="space-y-4">
      <div className="bg-muted/50 rounded-lg p-3 text-sm space-y-1">
        <div className="flex justify-between gap-4">
          <span className="text-muted-foreground text-xs">Delegate email</span>
          <span className="font-medium">{submission.delegate_email}</span>
        </div>
        {submission.submitted_at && (
          <div className="flex justify-between gap-4">
            <span className="text-muted-foreground text-xs">Submitted</span>
            <span className="font-medium">{format(new Date(submission.submitted_at), "dd MMM yyyy 'at' HH:mm")}</span>
          </div>
        )}
        <div className="flex justify-between gap-4">
          <span className="text-muted-foreground text-xs">Form</span>
          <span className="font-medium">{submission.form_type}</span>
        </div>
      </div>

      {fieldEntries.length > 0 && (
        <div className="rounded-lg border border-border divide-y divide-border">
          {fieldEntries.map(([key, value]) => (
            <div key={key} className="px-3 py-2 grid grid-cols-3 gap-3 text-sm">
              <span className="text-muted-foreground text-xs col-span-1 capitalize pt-0.5">
                {key.replace(/_/g, ' ')}
              </span>
              <div className="col-span-2 break-words">
                {Array.isArray(value) ? (
                  <ul className="list-disc list-inside space-y-0.5">
                    {(value as any[]).map((item, i) => <li key={i}>{String(item)}</li>)}
                  </ul>
                ) : typeof value === 'object' ? (
                  <pre className="text-xs whitespace-pre-wrap font-mono">{JSON.stringify(value, null, 2)}</pre>
                ) : (
                  <span className="font-medium whitespace-pre-line">{String(value)}</span>
                )}
              </div>
            </div>
          ))}
        </div>
      )}

      <div className="grid sm:grid-cols-2 gap-4 pt-2">
        <div className="space-y-1.5">
          <p className="text-xs font-semibold text-muted-foreground">Candidate signature</p>
          {candidateSig ? (
            <div className="rounded-md border border-border bg-white p-2">
              <img src={candidateSig} alt="Candidate signature" className="max-h-32 mx-auto" />
            </div>
          ) : (
            <p className="text-xs text-muted-foreground italic">Not signed</p>
          )}
        </div>
        <div className="space-y-1.5">
          <p className="text-xs font-semibold text-muted-foreground">Assessor signature</p>
          {assessorSig ? (
            <div className="rounded-md border border-border bg-white p-2">
              <img src={assessorSig} alt="Assessor signature" className="max-h-32 mx-auto" />
            </div>
          ) : (
            <p className="text-xs text-muted-foreground italic">Not signed</p>
          )}
        </div>
      </div>
    </div>
  );
};

const Orders = () => {
  const queryClient = useQueryClient();
  const { companyId, hasRole, hasAnyRole, isSysLevel, user } = useAuth();
  const { preview } = useRolePreview();
  const isDelegateView = (preview.active && preview.role === "delegate") || (hasRole("delegate") && !isSysLevel() && !preview.active);
  const isCompanyManager = hasRole("company_manager") && !!companyId && !isDelegateView;
  // Settling an invoice is restricted to sys_admin / sys_manager (matches the
  // API gate) — the buyer company must never mark its own invoice paid.
  const canMarkInvoicePaid = hasAnyRole(["sys_admin", "sys_manager"]);
  const isRealDelegate = hasRole("delegate") && !isSysLevel() && !preview.active;
  // For delegate preview OR real delegate, scope by email
  const delegateEmail = preview.active && preview.role === "delegate"
    ? preview.previewEmail
    : isRealDelegate
      ? user?.email ?? null
      : null;
  const [search, setSearch] = useState("");
  const [statusFilter, setStatusFilter] = useState("all");
  const [unassignedOnly, setUnassignedOnly] = useState(() =>
    typeof window !== 'undefined'
      && new URLSearchParams(window.location.search).get('unassigned') === '1'
  );
  const [courseIdFilter, setCourseIdFilter] = useState<string | null>(() =>
    typeof window !== 'undefined'
      ? new URLSearchParams(window.location.search).get('course_id')
      : null
  );
  // Optional company filter — set when deep-linked from /admin/companies with
  // `?company_id=…` (e.g. "view orders blocking this delete"). Sys-level only;
  // company managers are already scoped server-side to their own company.
  const [companyIdFilter, setCompanyIdFilter] = useState<string | null>(() =>
    typeof window !== 'undefined'
      ? new URLSearchParams(window.location.search).get('company_id')
      : null
  );
  // Date filter. Default is no filter (show all). `dateField` controls whether
  // the range applies to the course start_date (operational view) or the order
  // created_at (financial view).
  const [dateRange, setDateRange] = useState<{ from: Date; to: Date } | null>(null);
  const [dateField, setDateField] = useState<"start_date" | "created_at">("start_date");
  const [selectedOrder, setSelectedOrder] = useState<any | null>(null);
  const [refundDialogOpen, setRefundDialogOpen] = useState(false);
  const [cancelDialogOpen, setCancelDialogOpen] = useState(false);
  const [editDelegate, setEditDelegate] = useState<any | null>(null);
  const [refundAmount, setRefundAmount] = useState("");
  const [refundReason, setRefundReason] = useState("");
  const [cancelReason, setCancelReason] = useState("");
  const [sortField, setSortField] = useState<string>("created_at");
  const [sortDir, setSortDir] = useState<"asc" | "desc">("desc");
  const [qrOrderId, setQrOrderId] = useState<string | null>(null);
  const [sendingPreCourseOrderId, setSendingPreCourseOrderId] = useState<string | null>(null);
  // Pending orders are treated as "abandoned" and hidden from the list by
  // default; this toggle (or selecting the Abandoned status) reveals them.
  const [showAbandoned, setShowAbandoned] = useState(false);

  // Fetch orders (scoped to company if company_manager, or delegate's orders)
  const { data: orders, isLoading } = useQuery({
    queryKey: ["admin-orders", statusFilter, companyId, delegateEmail, unassignedOnly, courseIdFilter, companyIdFilter],
    queryFn: async () => {
      const params = new URLSearchParams();
      if (statusFilter !== "all") params.set('status', statusFilter);
      if (isCompanyManager && companyId) params.set('company_id', companyId);
      else if (companyIdFilter) params.set('company_id', companyIdFilter);
      if (delegateEmail) params.set('delegate_email', delegateEmail);
      if (unassignedOnly) params.set('unassigned', '1');
      if (courseIdFilter) params.set('course_id', courseIdFilter);
      const res = await fetch(`/api/admin/orders?${params.toString()}`);
      if (!res.ok) return [];
      return res.json();
    },
  });

  // Auto-open the order from a `?id=...` deep link (used by credit-note links,
  // refund-history pages, etc.). Strip the param after consuming it so closing
  // the dialog (which sets selectedOrder=null and re-fires this effect) doesn't
  // immediately re-open the same order.
  useEffect(() => {
    if (!orders || selectedOrder) return;
    if (typeof window === 'undefined') return;
    const url = new URL(window.location.href);
    const wantedId = url.searchParams.get('id');
    if (!wantedId) return;
    const match = orders.find((o: any) => o.id === wantedId);
    if (match) {
      setSelectedOrder(match);
      url.searchParams.delete('id');
      window.history.replaceState(null, '', url.toString());
    }
  }, [orders, selectedOrder]);

  // Fetch delegates for selected order
  const { data: delegates } = useQuery({
    queryKey: ["order-delegates", selectedOrder?.id],
    enabled: !!selectedOrder,
    queryFn: async () => {
      const res = await fetch(`/api/admin/orders/${selectedOrder!.id}/delegates`);
      if (!res.ok) return [];
      return res.json();
    },
  });

  // Certificates already issued for this order — drives the per-delegate
  // upload buttons in the Delegates tab.
  const { data: orderCerts, refetch: refetchOrderCerts } = useQuery({
    queryKey: ["order-certificates", selectedOrder?.id],
    enabled: !!selectedOrder,
    queryFn: async () => {
      const res = await fetch(`/api/admin/certificates?order_id=${encodeURIComponent(selectedOrder!.id)}`);
      if (!res.ok) return [];
      const all = await res.json();
      // The certificates index doesn't currently filter server-side on
      // order_id, so narrow it here.
      return (all as any[]).filter((c) => c.order_id === selectedOrder!.id);
    },
  });

  const findCertForDelegate = (d: any): any | undefined => {
    if (!orderCerts) return undefined;
    if (d.email) {
      return (orderCerts as any[]).find(
        (c) => (c.delegate_email || "").toLowerCase() === d.email.toLowerCase(),
      );
    }
    const name = `${d.first_name ?? ""} ${d.last_name ?? ""}`.trim();
    return (orderCerts as any[]).find(
      (c) => !c.delegate_email && (c.delegate_name || "").trim() === name,
    );
  };

  // Upload (or issue + upload) a certificate for a single delegate.
  const uploadCertForDelegate = async (delegate: any, file: File) => {
    if (!selectedOrder) return;
    let cert = findCertForDelegate(delegate);
    try {
      if (!cert) {
        // No cert row yet — create one (pending) so the upload has a target.
        const fd = new FormData();
        if (selectedOrder.course_id) fd.append("course_id", selectedOrder.course_id);
        fd.append("order_id", selectedOrder.id);
        if (selectedOrder.company_id) fd.append("company_id", selectedOrder.company_id);
        if (delegate.email) fd.append("delegate_email", delegate.email);
        fd.append("delegate_name", `${delegate.first_name ?? ""} ${delegate.last_name ?? ""}`.trim());
        fd.append("qualification_name", selectedOrder.courses?.title || "");
        fd.append("status", "active");
        fd.append("certificate_file", file);
        const res = await fetch("/api/admin/certificates", {
          method: "POST",
          headers: { Accept: "application/json", "X-Requested-With": "XMLHttpRequest", "X-CSRF-TOKEN": csrfToken() },
          body: fd,
        });
        if (!res.ok) {
          const d = await res.json().catch(() => null);
          throw new Error(d?.error || d?.message || "Upload failed");
        }
      } else {
        const fd = new FormData();
        fd.append("certificate_file", file);
        const res = await fetch(`/api/admin/certificates/${cert.id}/upload`, {
          method: "POST",
          headers: { Accept: "application/json", "X-Requested-With": "XMLHttpRequest", "X-CSRF-TOKEN": csrfToken() },
          body: fd,
        });
        if (!res.ok) {
          const d = await res.json().catch(() => null);
          throw new Error(d?.error || d?.message || "Upload failed");
        }
      }
      toast.success("Certificate uploaded");
      await refetchOrderCerts();
      queryClient.invalidateQueries({ queryKey: ["admin-certificates"] });
    } catch (e: any) {
      toast.error(e.message || "Upload failed");
    }
  };

  // Trainers list — sys-level only, used to assign/reassign on the order dialog
  const canAssignTrainer = isSysLevel() && !isDelegateView;
  const canViewSubmissions = isSysLevel() && !isDelegateView;
  const [viewingSubmission, setViewingSubmission] = useState<any | null>(null);
  const { data: trainersList } = useQuery({
    queryKey: ['admin-trainers-for-orders'],
    enabled: canAssignTrainer,
    queryFn: async () => {
      const res = await fetch('/api/admin/trainers');
      if (!res.ok) return [];
      return res.json();
    },
  });

  const assignTrainerMutation = useMutation({
    mutationFn: async ({ orderId, trainerId }: { orderId: string; trainerId: string | null }) => {
      const res = await fetch(`/api/admin/orders/${orderId}`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken() },
        body: JSON.stringify({ trainer_id: trainerId }),
      });
      if (!res.ok) {
        const err = await res.json().catch(() => ({ error: 'Failed' }));
        throw new Error(err.error || 'Failed to assign trainer');
      }
      return res.json();
    },
    onSuccess: (_, vars) => {
      toast.success(vars.trainerId ? 'Trainer assigned' : 'Trainer cleared');
      queryClient.invalidateQueries({ queryKey: ['admin-orders'] });
      // Refresh the local selectedOrder so the dialog reflects the new trainer
      // without forcing a close-and-reopen.
      if (selectedOrder) {
        const trainer = (trainersList || []).find((t: any) => t.id === vars.trainerId);
        setSelectedOrder({
          ...selectedOrder,
          trainer_id: vars.trainerId,
          trainers: trainer ? { first_name: trainer.first_name, last_name: trainer.last_name } : null,
        });
      }
    },
    onError: (e: Error) => toast.error(e.message || 'Failed to assign trainer'),
  });

  // Fetch onboarding form submissions for selected order
  const { data: formSubmissions } = useQuery({
    queryKey: ["order-form-submissions", selectedOrder?.id],
    enabled: !!selectedOrder,
    queryFn: async () => {
      const res = await fetch(`/api/admin/orders/${selectedOrder!.id}/form-submissions`);
      if (!res.ok) return [];
      return res.json();
    },
  });

  // Credit note(s) generated for this order (issued on cancellation/refund).
  // Drives the "View Credit Note" link in the Payment section so an admin can
  // jump straight to the note that was created when the booking was cancelled.
  const { data: orderCreditNotes } = useQuery({
    queryKey: ["order-credit-notes", selectedOrder?.id],
    enabled: !!selectedOrder,
    queryFn: async () => {
      const res = await fetch(`/api/admin/credit-notes?source_order_id=${encodeURIComponent(selectedOrder!.id)}`);
      if (!res.ok) return [];
      const data = await res.json();
      return (data.credit_notes ?? []) as any[];
    },
  });

  // Refund mutation
  const refundMutation = useMutation({
    mutationFn: async ({ orderId, amount, reason }: { orderId: string; amount: number; reason: string }) => {
      const res = await fetch('/api/admin/functions/process-refund', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken() },
        body: JSON.stringify({ order_id: orderId, refund_amount_cents: amount, reason, action: "refund" }),
      });
      if (!res.ok) {
        const err = await res.json().catch(() => ({ error: 'Failed' }));
        throw new Error(err.error || 'Failed to process refund');
      }
      const data = await res.json();
      if (data.error) throw new Error(data.error);
      return data;
    },
    onSuccess: (data: any) => {
      toast.success(data.message || "Refund processed successfully");
      queryClient.invalidateQueries({ queryKey: ["admin-orders"] });
      setRefundDialogOpen(false);
      setSelectedOrder(null);
      setRefundAmount("");
      setRefundReason("");
    },
    onError: (err: Error) => {
      toast.error(err.message || "Failed to process refund");
    },
  });

  // Mark invoice payment received - releases the credit reservation
  const markPaidMutation = useMutation({
    mutationFn: async (order: any) => {
      const res = await fetch(`/api/admin/orders/${order.id}/mark-paid`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken() },
        body: JSON.stringify({}),
      });
      if (!res.ok) {
        const err = await res.json().catch(() => ({ error: 'Failed' }));
        throw new Error(err.error || 'Failed to mark paid');
      }
      return res.json();
    },
    onSuccess: () => {
      toast.success("Payment received — invoice settled");
      queryClient.invalidateQueries({ queryKey: ["admin-orders"] });
      queryClient.invalidateQueries({ queryKey: ["finance-overview"] });
      queryClient.invalidateQueries({ queryKey: ["company-credit-orders"] });
      setSelectedOrder(null);
    },
    onError: (err: Error) => toast.error(err.message || "Failed to mark paid"),
  });

  // Mark Complete mutation - creates pending certificate records
  const markCompleteMutation = useMutation({
    mutationFn: async (order: any) => {
      const res = await fetch(`/api/admin/orders/${order.id}/mark-complete`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken() },
        body: JSON.stringify({}),
      });
      if (!res.ok) {
        const err = await res.json().catch(() => ({ error: 'Failed' }));
        throw new Error(err.error || 'Failed to mark complete');
      }
      return res.json();
    },
    onSuccess: (data: any) => {
      toast.success(`Course marked complete. ${data.delegateCount || 0} certificate(s) pending upload.`);
      queryClient.invalidateQueries({ queryKey: ["admin-orders"] });
      queryClient.invalidateQueries({ queryKey: ["admin-certificates"] });
      setSelectedOrder(null);
    },
    onError: (err: Error) => toast.error(err.message),
  });

  // Cancel mutation
  const cancelMutation = useMutation({
    mutationFn: async ({ orderId, reason }: { orderId: string; reason: string }) => {
      const res = await fetch('/api/admin/functions/process-refund', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken() },
        body: JSON.stringify({ order_id: orderId, reason, action: "cancel" }),
      });
      if (!res.ok) {
        const err = await res.json().catch(() => ({ error: 'Failed' }));
        throw new Error(err.error || 'Failed to cancel order');
      }
      const data = await res.json();
      if (data.error) throw new Error(data.error);
      return data;
    },
    onSuccess: () => {
      toast.success("Order cancelled successfully");
      queryClient.invalidateQueries({ queryKey: ["admin-orders"] });
      setCancelDialogOpen(false);
      setSelectedOrder(null);
      setCancelReason("");
    },
    onError: (err: Error) => {
      toast.error(err.message || "Failed to cancel order");
    },
  });

  // Apply the date filter (if any) up-front so stats and the table see the
  // same subset. Orders without a value for the active date field (e.g.
  // e-learning orders have no start_date) are excluded while a range is set.
  const dateFiltered = useMemo(() => {
    if (!orders) return [] as any[];
    if (!dateRange) return orders as any[];
    const start = startOfDay(dateRange.from);
    const end = endOfDay(dateRange.to);
    return (orders as any[]).filter((o: any) => {
      const raw = dateField === "start_date" ? o.start_date : o.created_at;
      if (!raw) return false;
      const d = dateField === "start_date" ? new Date(raw + "T00:00:00") : new Date(raw);
      return isWithinInterval(d, { start, end });
    });
  }, [orders, dateRange, dateField]);

  // Stats — revenue/refunded shown in gross (incl-VAT) terms, matching what
  // customers actually paid/were refunded.
  const stats = useMemo(() => {
    if (!dateFiltered.length && !orders) return { total: 0, revenue: 0, refunded: 0, pending: 0, confirmed: 0 };
    const src = dateFiltered;
    // Match Revenue Analytics: include "completed" alongside paid/confirmed,
    // and subtract refunds so the figure represents net cash received.
    const REVENUE_STATUSES = ["paid", "confirmed", "completed"];
    return {
      total: src.length,
      revenue: src.filter((o: any) => REVENUE_STATUSES.includes(o.status))
        .reduce((s: number, o: any) => s + grossCents(o.price_cents) - grossCents(o.refund_cents || 0), 0),
      refunded: src.filter((o: any) => o.status === "refunded").reduce((s: number, o: any) => s + grossCents((o as any).refund_cents || 0), 0),
      pending: src.filter((o: any) => o.status === "pending").length,
      confirmed: src.filter((o: any) => REVENUE_STATUSES.includes(o.status)).length,
    };
  }, [dateFiltered, orders]);

  // Filter & sort
  const filtered = useMemo(() => {
    let result = dateFiltered?.filter((o: any) => {
      // Abandoned (pending) bookings are hidden unless revealed via the toggle
      // or the user explicitly filters to that status.
      if (o.status === "pending" && !showAbandoned && statusFilter === "all") return false;
      if (!search) return true;
      const s = search.toLowerCase();
      return (
        o.customer_name?.toLowerCase().includes(s) ||
        o.customer_email?.toLowerCase().includes(s) ||
        (o.courses as any)?.title?.toLowerCase().includes(s) ||
        (o.training_companies as any)?.name?.toLowerCase().includes(s) ||
        o.id.toLowerCase().includes(s)
      );
    }) || [];

    const sortVal = (o: any): any => {
      switch (sortField) {
        case "course": return (o.courses as any)?.title;
        case "customer": return o.customer_name;
        case "company": return (o.training_companies as any)?.name;
        case "venue": return (o.venues as any)?.name;
        // Sort by the displayed label so e.g. invoice/credit/company_credit
        // (all shown as "Pay on Invoice") group together.
        case "payment": return paymentMethodLabels[o.payment_method] || "Card";
        default: return o[sortField];
      }
    };
    result.sort((a: any, b: any) => {
      let aVal = sortVal(a);
      let bVal = sortVal(b);
      if (typeof aVal === "string") aVal = aVal.toLowerCase();
      if (typeof bVal === "string") bVal = bVal.toLowerCase();
      // Missing values always sink to the bottom (numeric 0 is a real value).
      if (aVal == null || aVal === "") return 1;
      if (bVal == null || bVal === "") return -1;
      const cmp = aVal > bVal ? 1 : aVal < bVal ? -1 : 0;
      return sortDir === "asc" ? cmp : -cmp;
    });

    return result;
  }, [dateFiltered, search, sortField, sortDir, showAbandoned, statusFilter]);

  const toggleSort = (field: string) => {
    if (sortField === field) setSortDir(sortDir === "asc" ? "desc" : "asc");
    else { setSortField(field); setSortDir("desc"); }
  };

  const SortIcon = ({ field }: { field: string }) => {
    if (sortField !== field) return <ChevronsUpDown className="w-3 h-3 inline ml-0.5 opacity-40" />;
    return sortDir === "asc" ? <ChevronUp className="w-3 h-3 inline ml-0.5" /> : <ChevronDown className="w-3 h-3 inline ml-0.5" />;
  };

  const canRefund = (order: any) =>
    ["paid", "confirmed"].includes(order.status) &&
    order.price_cents > ((order as any).refund_cents || 0);

  const canCancel = (order: any) =>
    ["pending", "paid", "confirmed"].includes(order.status);

  // Money/lifecycle actions (settle invoice, cancel, refund, request date
  // change) belong to the buyer company or sys. A company that only PROVIDES
  // the order (its course / trainer) can manage delivery — delegates,
  // completion — but must not touch the buyer's payment or schedule. The
  // backend enforces this; we hide the buttons so the UI matches.
  const isBuyerOrSys = (order: any) =>
    isSysLevel() || (!!order?.company_id && order.company_id === companyId);

  const handleExportOrders = () => {
    if (!filtered.length) return;
    exportToCSV(
      filtered.map((o: any) => ({
        order_id: o.id,
        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 || "",
        course_date: o.start_date,
        venue: o.venues?.name || "",
        delegates: o.num_delegates,
        payment_method: o.payment_method,
        amount_gbp: (grossCents(o.price_cents) / 100).toFixed(2),
        refund_gbp: (grossCents(o.refund_cents || 0) / 100).toFixed(2),
        status: o.status,
      })),
      `orders-${format(new Date(), "yyyy-MM-dd")}`
    );
  };

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

        {/* Stats - hide revenue details from delegates */}
        {!delegateEmail ? (
          <div className="grid grid-cols-2 md:grid-cols-4 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">
                <ShoppingCart className="w-3.5 h-3.5" /> Total Bookings
              </div>
              <p className="text-2xl font-bold text-foreground">{stats.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">
                <TrendingUp className="w-3.5 h-3.5" /> Revenue
              </div>
              <p className="text-2xl font-bold text-foreground">£{(stats.revenue / 100).toLocaleString("en-GB", { minimumFractionDigits: 2 })}</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">
                <Undo2 className="w-3.5 h-3.5" /> Refunded
              </div>
              <p className="text-2xl font-bold text-foreground">£{(stats.refunded / 100).toLocaleString("en-GB", { minimumFractionDigits: 2 })}</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" /> Confirmed
              </div>
              <p className="text-2xl font-bold text-foreground">{stats.confirmed}</p>
            </div>
          </div>
        ) : (
          <div className="grid grid-cols-2 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">
                <ShoppingCart className="w-3.5 h-3.5" /> My Bookings
              </div>
              <p className="text-2xl font-bold text-foreground">{stats.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" /> Confirmed
              </div>
              <p className="text-2xl font-bold text-foreground">{stats.confirmed}</p>
            </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 orders by name, email, course, company or ID..." value={search} onChange={(e) => setSearch(e.target.value)} className="pl-9" />
          </div>
          <Select value={statusFilter} onValueChange={setStatusFilter}>
            <SelectTrigger className="w-[180px]">
              <SelectValue placeholder="Status" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="all">All Statuses</SelectItem>
              <SelectItem value="pending">Abandoned</SelectItem>
              <SelectItem value="paid">Paid</SelectItem>
              <SelectItem value="confirmed">Confirmed</SelectItem>
              <SelectItem value="completed">Completed</SelectItem>
              <SelectItem value="cancelled">Cancelled</SelectItem>
              <SelectItem value="refunded">Refunded</SelectItem>
            </SelectContent>
          </Select>

          {/* Abandoned (pending) bookings are hidden by default — reveal on demand. */}
          {statusFilter === "all" && stats.pending > 0 && (
            <Button
              type="button"
              variant={showAbandoned ? "secondary" : "outline"}
              size="sm"
              className="whitespace-nowrap"
              onClick={() => setShowAbandoned((v) => !v)}
            >
              {showAbandoned ? "Hide" : "Show"} abandoned ({stats.pending})
            </Button>
          )}

          {/* Date filter — defaults to "no filter". Switch field (course date vs
              order date) using the small select; preset buttons apply common
              ranges. */}
          <Select value={dateField} onValueChange={(v) => setDateField(v as any)}>
            <SelectTrigger className="w-[160px]">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="start_date">Course date</SelectItem>
              <SelectItem value="created_at">Order date</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) => {
                  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>
          )}
          {unassignedOnly && (
            <Button
              variant="outline"
              size="sm"
              className="gap-1.5 border-amber-500/40 text-amber-700 hover:bg-amber-50"
              onClick={() => setUnassignedOnly(false)}
            >
              <AlertTriangle className="w-3.5 h-3.5" />
              Unassigned trainer · clear
              <XCircle className="w-3.5 h-3.5 ml-1" />
            </Button>
          )}
          {courseIdFilter && (() => {
            const title = (orders || []).find((o: any) => o.course_id === courseIdFilter)?.courses?.title;
            return (
              <Button
                variant="outline"
                size="sm"
                className="gap-1.5 border-primary/40 text-primary hover:bg-primary/5"
                onClick={() => {
                  setCourseIdFilter(null);
                  if (typeof window !== 'undefined') {
                    const url = new URL(window.location.href);
                    url.searchParams.delete('course_id');
                    window.history.replaceState(null, '', url.toString());
                  }
                }}
              >
                Course: {title || courseIdFilter.slice(0, 8)} · clear
                <XCircle className="w-3.5 h-3.5 ml-1" />
              </Button>
            );
          })()}
          {companyIdFilter && !isCompanyManager && (() => {
            const name = (orders || []).find((o: any) => o.company_id === companyIdFilter)?.training_companies?.name;
            return (
              <Button
                variant="outline"
                size="sm"
                className="gap-1.5 border-primary/40 text-primary hover:bg-primary/5"
                onClick={() => {
                  setCompanyIdFilter(null);
                  if (typeof window !== 'undefined') {
                    const url = new URL(window.location.href);
                    url.searchParams.delete('company_id');
                    window.history.replaceState(null, '', url.toString());
                  }
                }}
              >
                Company: {name || companyIdFilter.slice(0, 8)} · clear
                <XCircle className="w-3.5 h-3.5 ml-1" />
              </Button>
            );
          })()}
        </div>

        {/* Orders Table */}
        <div className="bg-card border border-border rounded-xl overflow-x-auto">
          <Table className="text-xs">
            <TableHeader>
              <TableRow>
                <TableHead className="cursor-pointer select-none whitespace-nowrap" onClick={() => toggleSort("created_at")}>
                  Order Date <SortIcon field="created_at" />
                </TableHead>
                <TableHead className="cursor-pointer select-none" onClick={() => toggleSort("customer")}>
                  Customer <SortIcon field="customer" />
                </TableHead>
                <TableHead className="cursor-pointer select-none" onClick={() => toggleSort("company")}>
                  Company <SortIcon field="company" />
                </TableHead>
                <TableHead className="cursor-pointer select-none" onClick={() => toggleSort("course")}>
                  Course <SortIcon field="course" />
                </TableHead>
                <TableHead className="cursor-pointer select-none whitespace-nowrap" onClick={() => toggleSort("start_date")}>
                  Course Date <SortIcon field="start_date" />
                </TableHead>
                <TableHead className="cursor-pointer select-none" onClick={() => toggleSort("venue")}>
                  Venue <SortIcon field="venue" />
                </TableHead>
                <TableHead className="cursor-pointer select-none text-center whitespace-nowrap" onClick={() => toggleSort("num_delegates")}>
                  Delegates <SortIcon field="num_delegates" />
                </TableHead>
                <TableHead className="cursor-pointer select-none whitespace-nowrap" onClick={() => toggleSort("payment")}>
                  Payment <SortIcon field="payment" />
                </TableHead>
                <TableHead className="cursor-pointer select-none text-right whitespace-nowrap" onClick={() => toggleSort("price_cents")}>
                  Amount <SortIcon field="price_cents" />
                </TableHead>
                <TableHead className="cursor-pointer select-none whitespace-nowrap" onClick={() => toggleSort("status")}>
                  Status <SortIcon field="status" />
                </TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {isLoading ? (
                <TableRow>
                  <TableCell colSpan={10} className="text-center text-muted-foreground py-12">Loading orders...</TableCell>
                </TableRow>
              ) : !filtered.length ? (
                <TableRow>
                  <TableCell colSpan={10} className="text-center text-muted-foreground py-12">No orders found</TableCell>
                </TableRow>
              ) : (
                filtered.map((order: any) => (
                  <TableRow key={order.id} className="cursor-pointer hover:bg-muted/30" onClick={() => setSelectedOrder(order)}>
                    <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="text-muted-foreground">
                      {order.training_companies?.name || "—"}
                    </TableCell>
                    <TableCell className="max-w-[180px] truncate">{order.courses?.title || "—"}</TableCell>
                    <TableCell className="whitespace-nowrap">{order.start_date ? format(new Date(order.start_date + "T00:00:00"), "dd MMM yy") : "—"}</TableCell>
                    <TableCell className="text-muted-foreground">
                      {order.venues?.name || "—"}
                    </TableCell>
                    <TableCell className="text-center">{order.num_delegates}</TableCell>
                    <TableCell className="whitespace-nowrap">
                      {paymentMethodLabels[order.payment_method] || "Card"}
                    </TableCell>
                    <TableCell className="font-semibold text-right whitespace-nowrap">
                      £{(grossCents(order.price_cents) / 100).toFixed(2)}
                    </TableCell>
                    <TableCell className="whitespace-nowrap">
                      <Badge variant="outline" className={statusConfig[order.status]?.class || ""}>
                        {statusConfig[order.status]?.label || order.status}
                      </Badge>
                    </TableCell>
                  </TableRow>
                ))
              )}
            </TableBody>
          </Table>
        </div>

        {/* Order Detail Dialog */}
        <Dialog open={!!selectedOrder} onOpenChange={() => setSelectedOrder(null)}>
          <DialogContent className="sm:max-w-2xl max-h-[85vh] overflow-y-auto">
            <DialogHeader>
              <DialogTitle className="flex items-center gap-2">
                <ShoppingCart className="w-5 h-5 text-primary" />
                Order Details
              </DialogTitle>
            </DialogHeader>

            {selectedOrder && (
              <Tabs defaultValue="details">
                <TabsList className="w-full">
                  <TabsTrigger value="details" className="flex-1">Details</TabsTrigger>
                  <TabsTrigger value="delegates" className="flex-1">Delegates</TabsTrigger>
                  {/* E-learning bookings have no joining instructions / onboarding questionnaire. */}
                  {!selectedOrder?.is_elearning && (
                    <TabsTrigger value="onboarding" className="flex-1">Onboarding</TabsTrigger>
                  )}
                </TabsList>

                {/* Details tab */}
                <TabsContent value="details" className="space-y-5 mt-4">
                  <div className="flex items-start justify-between">
                    <div>
                      <p className="text-xs text-muted-foreground font-mono">Order #{selectedOrder.id.slice(0, 8)}</p>
                      <p className="text-xs text-muted-foreground">
                        Placed {format(new Date(selectedOrder.created_at), "dd MMM yyyy 'at' HH:mm")}
                      </p>
                    </div>
                    <div className="flex items-center gap-2">
                      <Button variant="outline" size="sm" onClick={() => setQrOrderId(selectedOrder.id)}>
                        <QrCode className="w-3.5 h-3.5 mr-1.5" /> QR Code
                      </Button>
                      <OrderInvoiceButton
                        variant="button"
                        order={selectedOrder}
                        courseTitle={selectedOrder.courses?.title}
                        companyName={selectedOrder.training_companies?.name}
                      />
                      <Badge variant="outline" className={`text-sm ${statusConfig[selectedOrder.status]?.class || ""}`}>
                        {statusConfig[selectedOrder.status]?.label || selectedOrder.status}
                      </Badge>
                    </div>
                  </div>

                  {/* Course & booking info */}
                  <div className="bg-muted/50 rounded-lg p-4 space-y-3">
                    <h3 className="font-semibold text-foreground">{selectedOrder.courses?.title}</h3>
                  <div className="grid grid-cols-2 gap-3 text-sm">
                    <div>
                      <span className="text-muted-foreground text-xs">Course Date</span>
                      <p className="font-medium">{selectedOrder.start_date ? format(new Date(selectedOrder.start_date + "T00:00:00"), "EEE, d MMM yyyy") : "Online – start anytime"}</p>
                    </div>
                    <div>
                      <span className="text-muted-foreground text-xs">Duration</span>
                      <p className="font-medium">{selectedOrder.courses?.days} day{selectedOrder.courses?.days > 1 ? "s" : ""}</p>
                    </div>
                    {selectedOrder.venues && (
                      <div>
                        <span className="text-muted-foreground text-xs flex items-center gap-1"><MapPin className="w-3 h-3" /> Venue</span>
                        <p className="font-medium">{selectedOrder.venues.name}{selectedOrder.venues.city ? `, ${selectedOrder.venues.city}` : ""}</p>
                      </div>
                    )}
                    {canAssignTrainer ? (
                      <div className="col-span-2">
                        <span className="text-muted-foreground text-xs">Trainer</span>
                        <div className="mt-1 flex items-center gap-2" onClick={(e) => e.stopPropagation()}>
                          <Select
                            value={selectedOrder.trainer_id ?? "__unassigned__"}
                            onValueChange={(val) => {
                              const next = val === "__unassigned__" ? null : val;
                              if (next === (selectedOrder.trainer_id ?? null)) return;
                              assignTrainerMutation.mutate({ orderId: selectedOrder.id, trainerId: next });
                            }}
                            disabled={assignTrainerMutation.isPending}
                          >
                            <SelectTrigger className="h-8 text-xs flex-1">
                              <SelectValue placeholder="Assign a trainer…" />
                            </SelectTrigger>
                            <SelectContent>
                              <SelectItem value="__unassigned__">— Not assigned —</SelectItem>
                              {(trainersList || []).map((t: any) => (
                                <SelectItem key={t.id} value={t.id}>
                                  {t.first_name} {t.last_name}
                                </SelectItem>
                              ))}
                            </SelectContent>
                          </Select>
                          {!selectedOrder.trainer_id && (
                            <Badge variant="outline" className="border-amber-500/40 text-amber-700">
                              <AlertTriangle className="w-3 h-3 mr-1" /> Unassigned
                            </Badge>
                          )}
                        </div>
                      </div>
                    ) : selectedOrder.trainers ? (
                      <div>
                        <span className="text-muted-foreground text-xs">Trainer</span>
                        <p className="font-medium">{selectedOrder.trainers.first_name} {selectedOrder.trainers.last_name}</p>
                      </div>
                    ) : null}
                  </div>
                </div>

                {/* Customer info */}
                <div className="bg-secondary/30 rounded-lg p-4 space-y-2">
                  <h4 className="text-sm font-semibold flex items-center gap-2">
                    <Users className="w-4 h-4" /> Customer
                  </h4>
                  <div className="grid grid-cols-2 gap-3 text-sm">
                    <div>
                      <span className="text-muted-foreground text-xs">Name</span>
                      <p className="font-medium">{selectedOrder.customer_name}</p>
                    </div>
                    <div>
                      <span className="text-muted-foreground text-xs">Email</span>
                      <p className="font-medium">{selectedOrder.customer_email}</p>
                    </div>
                    {selectedOrder.customer_phone && (
                      <div>
                        <span className="text-muted-foreground text-xs">Phone</span>
                        <p className="font-medium">{selectedOrder.customer_phone}</p>
                      </div>
                    )}
                    {selectedOrder.training_companies && (
                      <div>
                        <span className="text-muted-foreground text-xs flex items-center gap-1"><Building2 className="w-3 h-3" /> Company</span>
                        <p className="font-medium">{selectedOrder.training_companies.name}</p>
                      </div>
                    )}
                  </div>
                </div>

                {/* Payment summary */}
                <div className="bg-secondary/30 rounded-lg p-4 space-y-2">
                  <h4 className="text-sm font-semibold flex items-center gap-2">
                    <CreditCard className="w-4 h-4" /> Payment
                  </h4>
                  <div className="space-y-1.5 text-sm">
                    <div className="flex justify-between">
                      <span className="text-muted-foreground">Payment Method</span>
                      <span className="font-medium">{paymentMethodLabels[selectedOrder.payment_method] || "Card"}</span>
                    </div>
                    <div className="flex justify-between">
                      <span className="text-muted-foreground">{selectedOrder.num_delegates} delegate(s) (ex VAT)</span>
                      <span className="font-medium">£{(selectedOrder.price_cents / 100).toFixed(2)}</span>
                    </div>
                    <div className="flex justify-between">
                      <span className="text-muted-foreground">VAT (20%)</span>
                      <span className="font-medium">£{(vatCents(selectedOrder.price_cents) / 100).toFixed(2)}</span>
                    </div>
                    <div className="flex justify-between">
                      <span className="text-muted-foreground">Total (incl. VAT)</span>
                      <span className="font-medium">£{(grossCents(selectedOrder.price_cents) / 100).toFixed(2)}</span>
                    </div>
                    {selectedOrder.refund_cents > 0 && (
                      <>
                        <div className="flex justify-between text-destructive">
                          <span>Refunded ({selectedOrder.refund_status === "full" ? "Full" : "Partial"})</span>
                          <span>-£{(grossCents(selectedOrder.refund_cents) / 100).toFixed(2)}</span>
                        </div>
                        {selectedOrder.refund_reason && (
                          <p className="text-xs text-muted-foreground italic">Reason: {selectedOrder.refund_reason}</p>
                        )}
                      </>
                    )}
                    <div className="border-t border-border pt-1.5 flex justify-between font-semibold">
                      <span>Net Amount (incl. VAT)</span>
                      <span>£{((grossCents(selectedOrder.price_cents) - grossCents(selectedOrder.refund_cents || 0)) / 100).toFixed(2)}</span>
                    </div>
                    {selectedOrder.stripe_payment_intent_id && (
                      <p className="text-[10px] text-muted-foreground font-mono mt-1">
                        PI: {selectedOrder.stripe_payment_intent_id}
                      </p>
                    )}
                    {INVOICE_METHODS.has(selectedOrder.payment_method) && selectedOrder.payment_received_at && (
                      <p className="text-[11px] text-emerald-600 mt-1 flex items-center gap-1">
                        <CheckCircle2 className="w-3 h-3" />
                        Payment received {format(new Date(selectedOrder.payment_received_at), "dd MMM yyyy 'at' HH:mm")}
                      </p>
                    )}
                    {INVOICE_METHODS.has(selectedOrder.payment_method)
                      && ["confirmed", "pending"].includes(selectedOrder.status) && (
                        <p className="text-[11px] text-amber-600 mt-1 flex items-center gap-1">
                          <AlertTriangle className="w-3 h-3" />
                          Awaiting invoice payment
                        </p>
                    )}
                  </div>

                  {/* Credit note(s) issued when this booking was cancelled or
                      refunded — link straight to the note on the Credit Notes
                      page (deep-linked via ?id=, which auto-opens it there). */}
                  {(orderCreditNotes?.length ?? 0) > 0 && (
                    <div className="border-t border-border pt-2 space-y-1.5">
                      {orderCreditNotes!.map((note: any) => (
                        <Link
                          key={note.id}
                          href={`/admin/credit-notes?id=${encodeURIComponent(note.id)}`}
                          className="flex items-center justify-between text-sm text-primary hover:underline"
                        >
                          <span className="inline-flex items-center gap-1.5">
                            <ScrollText className="w-3.5 h-3.5" />
                            Credit note {note.reference}
                          </span>
                          <span className="inline-flex items-center gap-1 font-medium">
                            £{(note.amount_cents / 100).toFixed(2)}
                            <ExternalLink className="w-3 h-3" />
                          </span>
                        </Link>
                      ))}
                    </div>
                  )}
                  {!delegateEmail
                    && canMarkInvoicePaid
                    && INVOICE_METHODS.has(selectedOrder.payment_method)
                    && ["confirmed", "pending"].includes(selectedOrder.status) && (
                      <Button
                        variant="default"
                        className="bg-blue-600 hover:bg-blue-700 text-white w-full mt-2"
                        disabled={markPaidMutation.isPending}
                        onClick={() => markPaidMutation.mutate(selectedOrder)}
                      >
                        <CreditCard className="w-4 h-4 mr-2" />
                        {markPaidMutation.isPending ? "Processing..." : "Mark Payment Received"}
                      </Button>
                  )}
                </div>

                {/* Order-level actions (Mark Complete / Cancel / Refund) live
                    on the Details tab since they apply to the whole order,
                    not to individual delegates. */}
                {(canRefund(selectedOrder) || canCancel(selectedOrder) || ["paid", "confirmed"].includes(selectedOrder.status)) && (
                  <div className="border-t border-border pt-4 flex gap-3 justify-end flex-wrap">
                    {["paid", "confirmed"].includes(selectedOrder.status) && !delegateEmail && (
                      <Button
                        variant="default"
                        className="bg-emerald-600 hover:bg-emerald-700 text-white"
                        disabled={markCompleteMutation.isPending}
                        onClick={() => markCompleteMutation.mutate(selectedOrder)}
                      >
                        <CheckCircle2 className="w-4 h-4 mr-2" />
                        {markCompleteMutation.isPending ? "Processing..." : "Mark Complete"}
                      </Button>
                    )}
                    {canCancel(selectedOrder) && isBuyerOrSys(selectedOrder) && selectedOrder.status !== "cancelled" && selectedOrder.status !== "refunded" && (
                      <Button variant="outline" onClick={() => setCancelDialogOpen(true)}>
                        <XCircle className="w-4 h-4 mr-2" /> Cancel Order
                      </Button>
                    )}
                    {canRefund(selectedOrder) && isBuyerOrSys(selectedOrder) && (
                      <Button variant="destructive" onClick={() => {
                        // Default to the gross outstanding amount — that's what the
                        // customer actually paid and what Stripe expects to refund.
                        const grossOutstanding = grossCents(selectedOrder.price_cents - (selectedOrder.refund_cents || 0));
                        setRefundAmount((grossOutstanding / 100).toFixed(2));
                        setRefundDialogOpen(true);
                      }}>
                        <Undo2 className="w-4 h-4 mr-2" /> Refund
                      </Button>
                    )}
                  </div>
                )}

                {/* Company managers can request a date change on their own
                    bookings here — the same availability-aware picker the
                    company portal uses. An admin still has to approve it. The
                    guard mirrors RequestDateChange's own visibility so the row
                    never renders empty. */}
                {isCompanyManager && selectedOrder.company_id === companyId && selectedOrder.start_date
                  && (
                    (["pending", "paid", "confirmed"].includes(selectedOrder.status)
                      && differenceInDays(new Date(selectedOrder.start_date + "T00:00:00"), new Date()) >= 1
                      && !selectedOrder.pending_date_change)
                    || !!selectedOrder.pending_date_change
                  ) && (
                  <div className="border-t border-border pt-4 flex gap-3 justify-end flex-wrap items-center">
                    <RequestDateChange
                      order={selectedOrder}
                      onSubmitted={() => {
                        queryClient.invalidateQueries({ queryKey: ["admin-orders"] });
                        setSelectedOrder(null);
                      }}
                    />
                  </div>
                )}

                </TabsContent>

                {/* Delegates tab */}
                <TabsContent value="delegates" className="space-y-3 mt-4">
                  <h4 className="text-sm font-semibold flex items-center gap-2">
                    <Users className="w-4 h-4" /> Delegates ({selectedOrder.num_delegates})
                  </h4>
                  {delegates && delegates.length > 0 ? (
                    <div className="grid gap-2">
                      {(() => {
                        // Bookings can only be edited on the day or later.
                        // E-learning has no start_date so it's always editable.
                        const todayIso = format(new Date(), "yyyy-MM-dd");
                        const canEditDelegate = !selectedOrder.start_date || selectedOrder.start_date >= todayIso;
                        return delegates.map((d: any) => {
                          const cert = findCertForDelegate(d);
                          const hasFile = !!cert?.certificate_url;
                          return (
                            <div key={d.id} className="flex items-center gap-3 bg-muted/30 rounded-lg p-3">
                              <div className="w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center shrink-0">
                                <span className="text-xs font-bold text-primary">{(d.first_name || "?")[0]}{(d.last_name || "?")[0]}</span>
                              </div>
                              <div className="flex-1 min-w-0">
                                <p className="text-sm font-medium truncate">{d.first_name} {d.last_name}</p>
                                {d.email
                                  ? <p className="text-xs text-muted-foreground truncate">{d.email}</p>
                                  : <p className="text-xs text-muted-foreground italic">no email</p>}
                              </div>
                              {d.phone && <p className="text-xs text-muted-foreground hidden md:block">{d.phone}</p>}
                              <div className="flex items-center gap-2 shrink-0">
                                {canEditDelegate && (
                                  <Button
                                    variant="ghost"
                                    size="sm"
                                    className="h-7 text-[11px] px-2"
                                    title="Edit / swap delegate"
                                    onClick={() => setEditDelegate(d)}
                                  >
                                    <Pencil className="w-3 h-3 mr-1" /> Edit
                                  </Button>
                                )}
                                {cert && (
                                  hasFile ? (
                                    <a
                                      href={cert.certificate_url}
                                      target="_blank"
                                      rel="noopener noreferrer"
                                      className="text-[11px] text-primary hover:underline inline-flex items-center gap-1"
                                    >
                                      <Download className="w-3 h-3" /> Cert
                                    </a>
                                  ) : (
                                    <Badge variant="outline" className="text-[10px] text-amber-600 border-amber-500/40">Pending</Badge>
                                  )
                                )}
                                <label className="text-[11px] inline-flex items-center gap-1 cursor-pointer rounded-md border border-input bg-background px-2 py-1 hover:bg-accent hover:text-accent-foreground">
                                  <Upload className="w-3 h-3" /> {hasFile ? "Replace" : "Upload"}
                                  <input
                                    type="file"
                                    accept=".pdf,image/png,image/jpeg,image/webp"
                                    className="hidden"
                                    onChange={(e) => {
                                      const file = e.target.files?.[0];
                                      if (file) uploadCertForDelegate(d, file);
                                      e.target.value = "";
                                    }}
                                  />
                                </label>
                              </div>
                            </div>
                          );
                        });
                      })()}
                    </div>
                  ) : (
                    <p className="text-sm text-muted-foreground italic">No delegates recorded</p>
                  )}
                  {selectedOrder.cancelled_at && (
                    <div className="bg-destructive/5 border border-destructive/20 rounded-lg p-3 text-sm mt-3">
                      <p className="font-medium text-destructive flex items-center gap-1">
                        <AlertTriangle className="w-4 h-4" /> Cancelled
                      </p>
                      <p className="text-xs text-muted-foreground mt-1">
                        {format(new Date(selectedOrder.cancelled_at), "dd MMM yyyy 'at' HH:mm")}
                      </p>
                    </div>
                  )}
                  {selectedOrder.completed_at && (
                    <div className="bg-emerald-500/5 border border-emerald-500/20 rounded-lg p-3 text-sm mt-3">
                      <p className="font-medium text-emerald-600 flex items-center gap-1">
                        <CheckCircle2 className="w-4 h-4" /> Course Completed
                      </p>
                      <p className="text-xs text-muted-foreground mt-1">
                        {format(new Date(selectedOrder.completed_at), "dd MMM yyyy 'at' HH:mm")}
                      </p>
                    </div>
                  )}
                </TabsContent>

                {/* Onboarding tab */}
                <TabsContent value="onboarding" className="space-y-4 mt-4">
                  <div className="flex items-center justify-between gap-2 flex-wrap">
                    <h4 className="text-sm font-semibold flex items-center gap-2">
                      <ClipboardList className="w-4 h-4" /> Onboarding Forms Status
                    </h4>
                    <div className="flex gap-2">
                      <Button
                        variant="outline"
                        size="sm"
                        disabled={sendingPreCourseOrderId === selectedOrder.id}
                        onClick={async () => {
                          setSendingPreCourseOrderId(selectedOrder.id);
                          try {
                            const res = await fetch('/api/admin/functions/send-pre-course-form', {
                              method: 'POST',
                              headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken() },
                              body: JSON.stringify({ action: "send_link", order_id: selectedOrder.id }),
                            });
                            if (!res.ok) {
                              const err = await res.json().catch(() => ({ error: 'Failed' }));
                              throw new Error(err.error || 'Failed');
                            }
                            const data = await res.json();
                            if (data?.error) throw new Error(data.error);
                            toast.success(`Pre-course form sent to ${data?.sent || 0} delegate(s)`);
                          } catch (err: any) {
                            toast.error(err.message || "Failed to send pre-course form links");
                          } finally {
                            setSendingPreCourseOrderId(null);
                          }
                        }}
                      >
                        <Send className="w-3.5 h-3.5 mr-1.5" />
                        {sendingPreCourseOrderId === selectedOrder.id ? "Sending…" : "Send Pre-Course Form"}
                      </Button>
                      <Button variant="outline" size="sm" onClick={() => setQrOrderId(selectedOrder.id)}>
                        <QrCode className="w-3.5 h-3.5 mr-1.5" /> QR Code
                      </Button>
                    </div>
                  </div>
                  <p className="text-xs text-muted-foreground -mt-2">
                    <strong>TD-02</strong> is sent to delegates before the course. <strong>TD-07 &amp; TD-29</strong> are completed on the day via QR code.
                  </p>
                  {delegates && delegates.length > 0 ? (() => {
                    // Match priority: exact email match. Fallback for single-delegate
                    // orders (or single-emailless-delegate orders) — orphan submissions
                    // that don't match any delegate by email get attributed to the only
                    // delegate that has no email. Multi-delegate orders without emails
                    // can't be disambiguated, so those land in "Other submissions" below.
                    const findSubFor = (d: any, type: string) => {
                      const subs = formSubmissions || [];
                      const exact = subs.find(
                        (s: any) => s.form_type === type
                          && d.email
                          && s.delegate_email?.toLowerCase() === d.email.toLowerCase(),
                      );
                      if (exact) return exact;

                      const emaillessDelegates = delegates.filter((dx: any) => !dx.email);
                      if (!d.email && emaillessDelegates.length === 1) {
                        const matchedEmails = new Set(
                          delegates.filter((dx: any) => dx.email).map((dx: any) => dx.email.toLowerCase()),
                        );
                        return subs.find(
                          (s: any) => s.form_type === type
                            && !matchedEmails.has((s.delegate_email || '').toLowerCase()),
                        );
                      }
                      return undefined;
                    };

                    const matchedSubIds = new Set<string>();
                    delegates.forEach((d: any) => {
                      ['TD-02', 'TD-07', 'TD-29'].forEach((t) => {
                        const sub = findSubFor(d, t);
                        if (sub) matchedSubIds.add(sub.id);
                      });
                    });
                    const orphans = (formSubmissions || []).filter((s: any) => !matchedSubIds.has(s.id));

                    const cell = (sub: any) => {
                      if (!sub) return <span className="text-muted-foreground text-xs">—</span>;
                      const tick = <CheckCircle2 className="w-4 h-4 text-green-600 mx-auto" />;
                      if (!canViewSubmissions) return tick;
                      return (
                        <button
                          type="button"
                          onClick={(e) => { e.stopPropagation(); setViewingSubmission(sub); }}
                          className="rounded-md p-1 hover:bg-green-500/10 transition-colors"
                          title="View submission"
                        >
                          {tick}
                        </button>
                      );
                    };

                    return (
                      <>
                        <div className="rounded-xl border border-border overflow-hidden">
                          <table className="w-full text-sm">
                            <thead>
                              <tr className="bg-muted/50 border-b border-border">
                                <th className="text-left px-3 py-2 text-xs font-semibold text-muted-foreground">Delegate</th>
                                <th className="text-center px-3 py-2 text-xs font-semibold text-muted-foreground">TD-02</th>
                                <th className="text-center px-3 py-2 text-xs font-semibold text-muted-foreground">TD-07</th>
                                <th className="text-center px-3 py-2 text-xs font-semibold text-muted-foreground">TD-29</th>
                              </tr>
                            </thead>
                            <tbody className="divide-y divide-border">
                              {delegates.map((d: any) => (
                                <tr key={d.id} className="bg-background">
                                  <td className="px-3 py-2.5">
                                    <p className="font-medium">{d.first_name} {d.last_name}</p>
                                    {d.email
                                      ? <p className="text-xs text-muted-foreground">{d.email}</p>
                                      : <p className="text-xs text-muted-foreground italic">no email on record</p>}
                                  </td>
                                  <td className="text-center px-3 py-2.5">{cell(findSubFor(d, 'TD-02'))}</td>
                                  <td className="text-center px-3 py-2.5">{cell(findSubFor(d, 'TD-07'))}</td>
                                  <td className="text-center px-3 py-2.5">{cell(findSubFor(d, 'TD-29'))}</td>
                                </tr>
                              ))}
                            </tbody>
                          </table>
                        </div>

                        {orphans.length > 0 && (
                          <div className="mt-3 rounded-xl border border-amber-500/30 bg-amber-500/5 p-3">
                            <p className="text-xs font-medium text-amber-700 mb-2">
                              Submissions on this order that couldn't be matched to a specific delegate:
                            </p>
                            <div className="space-y-1.5">
                              {orphans.map((s: any) => (
                                <div key={s.id} className="flex items-center justify-between gap-2 text-xs">
                                  <span className="truncate">
                                    <strong>{s.form_type}</strong> · {s.delegate_email}
                                    {s.submitted_at && (
                                      <span className="text-muted-foreground ml-2">
                                        {format(new Date(s.submitted_at), "dd MMM yyyy HH:mm")}
                                      </span>
                                    )}
                                  </span>
                                  {canViewSubmissions && (
                                    <Button
                                      variant="ghost"
                                      size="sm"
                                      className="h-6 px-2 text-xs"
                                      onClick={() => setViewingSubmission(s)}
                                    >
                                      View
                                    </Button>
                                  )}
                                </div>
                              ))}
                            </div>
                          </div>
                        )}
                      </>
                    );
                  })() : (
                    <p className="text-sm text-muted-foreground italic">No delegates on this order.</p>
                  )}
                  <p className="text-xs text-muted-foreground">
                    Generate a QR code for delegates to scan on the day of the course to complete their TD-07 &amp; TD-29 induction forms.
                  </p>
                </TabsContent>
              </Tabs>
            )}
          </DialogContent>
        </Dialog>

        {/* Refund Dialog */}
        <Dialog open={refundDialogOpen} onOpenChange={setRefundDialogOpen}>
          <DialogContent className="sm:max-w-md">
            <DialogHeader>
              <DialogTitle className="flex items-center gap-2">
                <Undo2 className="w-5 h-5 text-destructive" /> Process Refund
              </DialogTitle>
            </DialogHeader>
            {selectedOrder && (
              <div className="space-y-4">
                <div className="bg-muted/50 rounded-lg p-3 text-sm">
                  <p className="font-medium">{selectedOrder.courses?.title}</p>
                  <p className="text-muted-foreground">{selectedOrder.customer_name}</p>
                  <p className="text-muted-foreground">
                    Order total (incl. VAT): £{(grossCents(selectedOrder.price_cents) / 100).toFixed(2)}
                    {selectedOrder.refund_cents > 0 && ` (£${(grossCents(selectedOrder.refund_cents) / 100).toFixed(2)} already refunded)`}
                  </p>
                </div>
                <div>
                  <Label>Refund Amount (£, incl. VAT)</Label>
                  <Input
                    type="number"
                    step="0.01"
                    min="0.01"
                    max={(grossCents(selectedOrder.price_cents - (selectedOrder.refund_cents || 0)) / 100).toFixed(2)}
                    value={refundAmount}
                    onChange={(e) => setRefundAmount(e.target.value)}
                  />
                  <p className="text-xs text-muted-foreground mt-1">
                    Max: £{(grossCents(selectedOrder.price_cents - (selectedOrder.refund_cents || 0)) / 100).toFixed(2)}
                  </p>
                </div>
                <div>
                  <Label>Reason</Label>
                  <Textarea
                    value={refundReason}
                    onChange={(e) => setRefundReason(e.target.value)}
                    placeholder="Reason for refund..."
                    rows={2}
                  />
                </div>
                <DialogFooter>
                  <Button variant="outline" onClick={() => setRefundDialogOpen(false)}>Cancel</Button>
                  <Button
                    variant="destructive"
                    disabled={refundMutation.isPending || !refundAmount || parseFloat(refundAmount) <= 0}
                    onClick={() => {
                      refundMutation.mutate({
                        orderId: selectedOrder.id,
                        amount: Math.round(parseFloat(refundAmount) * 100),
                        reason: refundReason,
                      });
                    }}
                  >
                    {refundMutation.isPending ? "Processing..." : `Refund £${parseFloat(refundAmount || "0").toFixed(2)}`}
                  </Button>
                </DialogFooter>
              </div>
            )}
          </DialogContent>
        </Dialog>

        {/* Cancel Confirmation */}
        <AlertDialog open={cancelDialogOpen} onOpenChange={setCancelDialogOpen}>
          <AlertDialogContent>
            <AlertDialogHeader>
              <AlertDialogTitle>Cancel Order?</AlertDialogTitle>
              <AlertDialogDescription>
                This will cancel the order and free up the training slot. The customer will not be automatically refunded — process a refund separately if needed.
              </AlertDialogDescription>
            </AlertDialogHeader>
            <div className="py-2">
              <Label>Reason (optional)</Label>
              <Textarea
                value={cancelReason}
                onChange={(e) => setCancelReason(e.target.value)}
                placeholder="Reason for cancellation..."
                rows={2}
              />
            </div>
            <AlertDialogFooter>
              <AlertDialogCancel>Keep Order</AlertDialogCancel>
              <AlertDialogAction
                className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
                disabled={cancelMutation.isPending}
                onClick={() => {
                  if (selectedOrder) {
                    cancelMutation.mutate({ orderId: selectedOrder.id, reason: cancelReason });
                  }
                }}
              >
                {cancelMutation.isPending ? "Cancelling..." : "Cancel Order"}
              </AlertDialogAction>
            </AlertDialogFooter>
          </AlertDialogContent>
        </AlertDialog>

        {/* QR Code Modal */}
        {qrOrderId && (
          <OrderQRCode
            orderId={qrOrderId}
            courseTitle={orders?.find((o: any) => o.id === qrOrderId)?.courses?.title}
            open={!!qrOrderId}
            onClose={() => setQrOrderId(null)}
          />
        )}

        {/* Edit / swap delegate */}
        <EditDelegateDialog
          open={!!editDelegate}
          onOpenChange={(o) => { if (!o) setEditDelegate(null); }}
          orderId={selectedOrder?.id ?? ""}
          delegate={editDelegate}
          onSaved={() => {
            queryClient.invalidateQueries({ queryKey: ["order-delegates", selectedOrder?.id] });
            queryClient.invalidateQueries({ queryKey: ["order-certificates", selectedOrder?.id] });
            queryClient.invalidateQueries({ queryKey: ["admin-certificates"] });
          }}
        />

        {/* Submission viewer (sys-level only) */}
        <Dialog open={!!viewingSubmission} onOpenChange={(open) => { if (!open) setViewingSubmission(null); }}>
          <DialogContent className="sm:max-w-2xl max-h-[85vh] overflow-y-auto">
            <DialogHeader>
              <DialogTitle className="flex items-center gap-2">
                <ClipboardList className="w-5 h-5 text-primary" />
                {viewingSubmission?.form_type} submission
              </DialogTitle>
            </DialogHeader>
            {viewingSubmission && <SubmissionView submission={viewingSubmission} />}
          </DialogContent>
        </Dialog>
      </div>
    </>
  );
};

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

export default Orders;
