"use client";
import React, { useEffect, useMemo, useState } from "react";
import { useAuth } from "@/hooks/useAuth";
import { apiFetch } from "@/lib/api";
import { useRouter } from "next/navigation";
import { formatDate } from "@/lib/date";
import { QrImage } from "@/components/shared/QrImage";

// Helper formatters
const formatRand = (n: number) => `R ${n.toFixed(2)}`;
const isFuture = (d: string | Date) => new Date(d).getTime() > Date.now();
const isEventOver = (ev: any) =>
  !!ev && ((ev.endDate && new Date(ev.endDate).getTime() < Date.now()) || ev.cashupStatus === 'closed');

// Effective unit price for an event option (or one of its variants), early-bird aware.
// Used by the registration editor, which works off raw /api/events/:id data rather than
// a registration's priceSnapshot — mirrors the pricing logic in register/[eventId]/RegisterForm.tsx.
function effectiveEventOptionUnitPrice(eo: any, variantId: string | null): number {
  const variant = variantId ? (eo?.variants || []).find((v: any) => v.id === variantId) : null;
  const base = (variant && variant.price !== null && variant.price !== undefined)
    ? Number(variant.price)
    : Number(eo?.price || 0);
  const allTiers = Array.isArray(eo?.earlyBirdTiers) ? eo.earlyBirdTiers : [];
  const tiers = variantId ? allTiers.filter((t: any) => t.variantId === variantId) : allTiers.filter((t: any) => !t.variantId);
  if (tiers.length === 0) return base;
  const now = new Date();
  const applicable = tiers
    .map((t: any) => ({ ...t, _d: new Date(t.deadline) }))
    .filter((t: any) => now < t._d)
    .sort((a: any, b: any) => a.price - b.price || a._d.getTime() - b._d.getTime());
  return applicable.length > 0 ? applicable[0].price : base;
}

export default function UserDashboardPage() {
  const { token, user } = useAuth();
  const [registrations, setRegistrations] = useState<any[]>([]);
  const [tickets, setTickets] = useState<any[]>([]);
  const [error, setError] = useState<string | null>(null);
  const [info, setInfo] = useState<string | null>(null);
  const [loading, setLoading] = useState<boolean>(false);

  // Filters
  const [showPast, setShowPast] = useState<boolean>(false);

  // Billing map: regId -> { totalDue, totalPaid, outstanding, payments }
  const [billing, setBilling] = useState<Record<string, { totalDue: number; totalPaid: number; outstanding: number; payments: any[] }>>({});

  // Forms status cache for registrations
  // regId -> { hasForm: boolean; isRequired?: boolean; submittedCount?: number; requiredCount?: number; complete?: boolean }
  const [formStatuses, setFormStatuses] = useState<Record<string, { hasForm: boolean; isRequired?: boolean; submittedCount?: number; requiredCount?: number; complete?: boolean }>>({});

  // Ticket selection
  const [selected, setSelected] = useState<Record<string, boolean>>({});

  // Registration details modal
  const [activeRegId, setActiveRegId] = useState<string | null>(null);
  const [dialog, setDialog] = useState<{ open: boolean; message: string; loading?: boolean }>({ open: false, message: "", loading: false });

  // Track whether the active registration's event has attendee forms
  const [activeEventHasForm, setActiveEventHasForm] = useState<boolean | null>(null);

  // Compute effective unit price for a registration option.
  // Uses priceSnapshot when available (authoritative backend price, variant-aware).
  // Falls back to deadline-only early-bird calculation for legacy rows without a snapshot.
  const optionUnitPrice = (opt: any, referenceTime: any, atTime: Date): number => {
    if (opt.priceSnapshot !== null && opt.priceSnapshot !== undefined) {
      return Number(opt.priceSnapshot);
    }
    const eo = opt.eventOption;
    const variantId: string | null = opt.variantId || null;
    // Use variant price as base if available, otherwise option base
    const base = (opt.variant?.price !== null && opt.variant?.price !== undefined)
      ? Number(opt.variant.price)
      : Number(eo?.price || 0);
    const allTiers = Array.isArray(eo?.earlyBirdTiers) ? eo.earlyBirdTiers.slice() : [];
    // Filter: variant options use only their variant-specific tiers; plain options use option-level tiers
    const tiers = variantId
      ? allTiers.filter((t: any) => t.variantId === variantId)
      : allTiers.filter((t: any) => !t.variantId);
    if (tiers.length === 0) return base;
    const t = atTime ? new Date(atTime) : new Date();
    const ref = referenceTime ? new Date(referenceTime) : t;
    const applicable = tiers
      .map((x: any) => ({ ...x, deadline: new Date(x.deadline) }))
      .filter((x: any) => (ref < x.deadline) && (t < x.deadline))
      .sort((a: any, b: any) => a.deadline.getTime() - b.deadline.getTime() || (a.order||0) - (b.order||0) || a.price - b.price);
    if (applicable.length === 0) return base;
    const price = Number(applicable[0].price);
    return (price >= 0) ? price : base;
  };

  useEffect(() => {
    (async () => {
      if (!token) return;
      setLoading(true);
      setError(null);
      try {
        // Tickets don't depend on registrations, so fetch both at once instead of
        // waterfalling — this was previously fetched only after registrations + all
        // their payments had already resolved.
        const [myRegs, myTicks] = await Promise.all([
          apiFetch<any[]>(`/api/registrations/myregistrations?showPast=${showPast ? '1' : '0'}`, { authToken: token }),
          apiFetch<any[]>("/api/tickets/mytickets", { authToken: token }),
        ]);
        setRegistrations(myRegs);
        setTickets(myTicks);

        // Compute totalDue from priceSnapshot (authoritative backend price, variant-aware).
        // priceSnapshot is set at registration time and refreshed before each payment.
        const now = new Date();
        const totals: Record<string, { totalDue: number; totalPaid: number; outstanding: number; payments: any[] }> = {};
        for (const r of myRegs) {
          const totalDue = (r.registrationOptions || []).reduce((sum: number, opt: any) => sum + optionUnitPrice(opt, null, now) * (opt.quantity || 0), 0);
          totals[r.id] = { totalDue, totalPaid: 0, outstanding: totalDue, payments: [] };
        }
        setBilling(totals);

        // Fetch payments per registration to compute outstanding
        await Promise.all(
          myRegs.map(async (r: any) => {
            try {
              const pays = await apiFetch<any[]>(`/api/payments/registration/${encodeURIComponent(r.id)}`, { authToken: token });
              const totalPaid = pays.reduce((s, p) => s + (p.amount || 0), 0);
              // totalDue uses priceSnapshot — not time-dependent, no need to recompute per payment time
              const totalDue = (r.registrationOptions || []).reduce((sum: number, opt: any) => sum + optionUnitPrice(opt, null, now) * (opt.quantity || 0), 0);
              const outstanding = Math.max(0, totalDue - totalPaid);
              setBilling(prev => ({
                ...prev,
                [r.id]: {
                  totalDue,
                  totalPaid,
                  outstanding,
                  payments: pays,
                },
              }));
            } catch (e) {
              // Ignore per-reg payment errors but log
              console.warn("Failed to load payments for", r.id, e);
            }
          })
        );
      } catch (e: any) {
        setError(e?.message || "Failed to load data");
      } finally {
        setLoading(false);
      }
    })();
  }, [token, showPast]);

  // After registrations load, compute forms status for each registration.
  // `myregistrations` now embeds event.form (with fields) directly, so this no longer
  // needs a GET /api/events/:id per registration — only the registration-detail fetch
  // (to get submittedCount) remains, and only for registrations that actually have a form.
  useEffect(() => {
    (async () => {
      if (!token || registrations.length === 0) return;
      const next: Record<string, { hasForm: boolean; isRequired?: boolean; submittedCount?: number; requiredCount?: number; complete?: boolean }> = {};
      await Promise.all(
        registrations.map(async (r: any) => {
          try {
            const ev = r.event;
            const hasForm = !!(ev?.form && Array.isArray(ev.form.fields) && ev.form.fields.length > 0);
            if (!hasForm) {
              next[r.id] = { hasForm: false };
              return;
            }
            // Load registration to get number of submitted responses
            const regFull = await apiFetch<any>(`/api/registrations/${encodeURIComponent(r.id)}`, { authToken: token });
            const submittedCount = (regFull?.formResponses || []).length;
            // Required count equals the number of main tickets purchased
            const requiredCount = (r.registrationOptions || [])
              .filter((ro: any) => ro.eventOption?.isMainTicket)
              .reduce((s: number, ro: any) => s + (ro.quantity || 0), 0);
            const complete = submittedCount >= requiredCount && requiredCount > 0 ? true : (submittedCount >= requiredCount);
            next[r.id] = {
              hasForm: true,
              isRequired: !!ev?.form?.isRequired,
              submittedCount,
              requiredCount,
              complete,
            };
          } catch (e) {
            // On any error, do not show forms status to avoid noisy UI
            next[r.id] = { hasForm: false };
          }
        })
      );
      setFormStatuses(next);
    })();
  }, [token, registrations]);

  const toggleSelect = (id: string, checked?: boolean) => {
    setSelected(prev => ({ ...prev, [id]: checked ?? !prev[id] }));
  };
  const selectAll = (on: boolean) => {
    const next: Record<string, boolean> = {};
    tickets.forEach(t => (next[t.id] = on));
    setSelected(next);
  };
  const selectedIds = useMemo(() => Object.entries(selected).filter(([, v]) => v).map(([k]) => k), [selected]);

  const emailTickets = async (ticketIds: string[]) => {
    if (!token || ticketIds.length === 0) return;
    setError(null);
    setInfo(null);
    // Open loading dialog immediately
    setDialog({ open: true, message: "Sending tickets…", loading: true });
    try {
      const res: any = await apiFetch("/api/tickets/email", {
        method: "POST",
        body: { ticketIds },
        authToken: token,
      });
      const msg = (res && res.message) ? res.message : `${ticketIds.length} ticket(s) emailed successfully.`;
      setDialog({ open: true, message: msg, loading: false });
    } catch (e: any) {
      setDialog({ open: false, message: "", loading: false });
      setError(e?.message || "Failed to email tickets");
    }
  };

  const emailRegistration = async (registrationId: string) => {
    if (!token) return;
    setError(null);
    setInfo(null);
    // Show loading dialog while sending
    setDialog({ open: true, message: "Sending tickets…", loading: true });
    try {
      const res: any = await apiFetch("/api/tickets/email", {
        method: "POST",
        body: { registrationId },
        authToken: token,
      });
      const msg = (res && res.message) ? res.message : `Tickets for registration emailed successfully.`;
      setDialog({ open: true, message: msg, loading: false });
    } catch (e: any) {
      setDialog({ open: false, message: "", loading: false });
      setError(e?.message || "Failed to email registration tickets");
    }
  };

  const whatsappTickets = async (ticketIds: string[]) => {
    if (!token || ticketIds.length === 0) return;
    if (!user?.phoneNumber) { setError("No phone number on your account. Add one in your profile."); return; }
    setError(null);
    setInfo(null);
    setDialog({ open: true, message: "Sending to WhatsApp…", loading: true });
    try {
      const res: any = await apiFetch("/api/tickets/email", {
        method: "POST",
        body: { ticketIds, channel: "whatsapp" },
        authToken: token,
      });
      const msg = (res && res.message) ? res.message : `${ticketIds.length} ticket(s) sent to WhatsApp.`;
      setDialog({ open: true, message: msg, loading: false });
    } catch (e: any) {
      setDialog({ open: false, message: "", loading: false });
      setError(e?.message || "Failed to send tickets to WhatsApp");
    }
  };

  const whatsappRegistration = async (registrationId: string) => {
    if (!token) return;
    if (!user?.phoneNumber) { setError("No phone number on your account. Add one in your profile."); return; }
    setError(null);
    setInfo(null);
    setDialog({ open: true, message: "Sending to WhatsApp…", loading: true });
    try {
      const res: any = await apiFetch("/api/tickets/email", {
        method: "POST",
        body: { registrationId, channel: "whatsapp" },
        authToken: token,
      });
      const msg = (res && res.message) ? res.message : `Tickets sent to WhatsApp.`;
      setDialog({ open: true, message: msg, loading: false });
    } catch (e: any) {
      setDialog({ open: false, message: "", loading: false });
      setError(e?.message || "Failed to send tickets to WhatsApp");
    }
  };

  // Print helpers
  const buildTicketHtmlCard = (t: any, buyerName?: string) => {
    const eventTitle = t.event?.title || t.eventId || "Event";
    const eventDate = t.event?.startDate ? new Date(t.event.startDate) : null;
    const optionName = t.registrationOption?.eventOption?.name || "Ticket";
    const variantName = t.registrationOption?.variant?.name;
    const type = variantName ? `${optionName} — ${variantName}` : optionName;
    const qty = t.quantity || 1;
    const qrSrc = `https://api.qrserver.com/v1/create-qr-code/?size=160x160&data=${encodeURIComponent(t.qrCode || t.id)}`;
    const dateStr = eventDate ? formatDate(eventDate) : '';
    return `
      <div class="ticket">
        <div class="row between">
          <div class="evt">${eventTitle}</div>
          ${dateStr ? `<div class="date">${dateStr}</div>` : ''}
        </div>
        <div class="type">${type}</div>
        <div class="qty">Qty: <strong>${qty}</strong></div>
        <div class="qrwrap"><img src="${qrSrc}" alt="QR" /></div>
        <div class="meta">Ticket ID: ${t.id}</div>
        ${buyerName ? `<div class="meta">Purchased by: ${buyerName}</div>` : ''}
      </div>
    `;
  };

  const openPrintWindow = (title: string, cardsHtml: string) => {
    const w = window.open("", "_blank");
    if (!w) return;
    w.document.write(`<!doctype html><html><head><title>${title}</title>
      <style>
        *{box-sizing:border-box}
        body{font-family:Arial,Helvetica,sans-serif;margin:0;padding:16px;background:#f7f7f7}
        .grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:16px}
        .ticket{background:#fff;border:1px solid #e5e7eb;border-radius:12px;padding:14px;box-shadow:0 1px 3px rgba(0,0,0,0.06);break-inside:avoid;page-break-inside:avoid}
        .evt{font-weight:700;font-size:14px}
        .type{margin-top:4px;color:#374151}
        .qty{margin-top:2px;font-size:12px;color:#374151}
        .date{color:#6b7280;font-size:12px}
        .row{display:flex;gap:8px;align-items:center}
        .between{justify-content:space-between}
        .qrwrap{display:flex;justify-content:center;align-items:center;margin:10px 0}
        .qrwrap img{width:160px;height:160px}
        .meta{font-size:12px;color:#6b7280;text-align:center;margin-top:6px}
        @media print { body{background:#fff} .print-hidden{display:none !important} }
      </style>
    </head><body>
      <h2 class="print-hidden" style="margin:8px 0 16px 0;font-size:18px">${title}</h2>
      <div class="grid">${cardsHtml}</div>
      <script>
        (function(){
          function printWhenReady(){
            var imgs = Array.prototype.slice.call(document.images);
            if(imgs.length === 0){ window.print(); return; }
            var remaining = imgs.length;
            function done(){ remaining--; if(remaining <= 0){ setTimeout(function(){ window.print(); }, 200); } }
            imgs.forEach(function(img){
              if (img.complete) { done(); }
              else {
                img.addEventListener('load', done, { once: true });
                img.addEventListener('error', done, { once: true });
              }
            });
          }
          if (document.readyState === 'complete') printWhenReady();
          else window.addEventListener('load', printWhenReady);
        })();
      </script>
    </body></html>`);
    w.document.close();
    w.focus();
  };

  const printTickets = (ticketList: any[]) => {
    if (!ticketList || ticketList.length === 0) return;
    const cards = ticketList.map(t => buildTicketHtmlCard(t, user?.name)).join("");
    openPrintWindow(`Tickets (${ticketList.length})`, cards);
  };

  // Upcoming events derived from registrations
  const upcomingEvents = useMemo(() => {
    const map = new Map<string, any>();
    for (const r of registrations) {
      if (r.event && isFuture(r.event.startDate)) {
        if (!map.has(r.event.id)) map.set(r.event.id, r.event);
      }
    }
    return Array.from(map.values()).sort((a, b) => new Date(a.startDate).getTime() - new Date(b.startDate).getTime());
  }, [registrations]);

  // Tickets by grouping
  const ticketsByEvent = useMemo(() => {
    const m: Record<string, any[]> = {};
    for (const t of tickets) {
      const eid = t.eventId;
      if (!m[eid]) m[eid] = [];
      m[eid].push(t);
    }
    return m;
  }, [tickets]);

  // Registration click -> open modal
  const activeReg = useMemo(() => registrations.find(r => r.id === activeRegId) || null, [registrations, activeRegId]);
  const activeBill = activeRegId ? billing[activeRegId] : undefined;

  // When a registration is opened, determine whether its event has attendee forms
  useEffect(() => {
    setActiveEventHasForm(null);
    if (!activeRegId) return;
    const ar = registrations.find(r => r.id === activeRegId);
    if (!ar) return;
    const evForm = ar.event?.form;
    if (evForm && Array.isArray(evForm.fields) && evForm.fields.length > 0) {
      setActiveEventHasForm(true);
      return;
    }
    (async () => {
      try {
        const ev = await apiFetch<any>(`/api/events/${encodeURIComponent(ar.eventId)}`);
        const has = !!(ev?.form && Array.isArray(ev.form.fields) && ev.form.fields.length > 0);
        setActiveEventHasForm(has);
      } catch {
        setActiveEventHasForm(false);
      }
    })();
  }, [activeRegId, registrations]);

  const showFormsButton = useMemo(() => {
    const evForm = activeReg?.event?.form;
    if (evForm && Array.isArray(evForm.fields)) return evForm.fields.length > 0;
    if (activeEventHasForm !== null) return activeEventHasForm;
    return false;
  }, [activeReg, activeEventHasForm]);

  // Cancel registration state
  const [cancelLoading, setCancelLoading] = useState(false);
  const [showCancelConfirm, setShowCancelConfirm] = useState(false);

  const cancelRegistration = async () => {
    if (!token || !activeRegId) return;
    setCancelLoading(true);
    try {
      await apiFetch(`/api/registrations/${encodeURIComponent(activeRegId)}`, {
        method: 'DELETE',
        authToken: token,
      });
      const myRegs = await apiFetch<any[]>(`/api/registrations/myregistrations?showPast=${showPast ? '1' : '0'}`, { authToken: token });
      setRegistrations(myRegs);
      setActiveRegId(null);
      setShowCancelConfirm(false);
      setInfo('Registration cancelled.');
    } catch (e: any) {
      setError(e?.message || 'Failed to cancel registration');
      setShowCancelConfirm(false);
    } finally {
      setCancelLoading(false);
    }
  };

  // Editor state for registration items. Keyed like register/[eventId]/RegisterForm.tsx:
  // "eventOptionId" for plain options, "eventOptionId:variantId" for variant options.
  const [editMode, setEditMode] = useState<boolean>(false);
  const [editLoading, setEditLoading] = useState<boolean>(false);
  const [editEventOptions, setEditEventOptions] = useState<any[]>([]);
  const [editQuantities, setEditQuantities] = useState<Record<string, number>>({});
  const [editBaseQty, setEditBaseQty] = useState<Record<string, number>>({});
  const [editMinQty, setEditMinQty] = useState<Record<string, number>>({});
  const [editError, setEditError] = useState<string | null>(null);

  // Whether the active registration's event still permits self-service changes
  // (edit items, pay, cancel) — false once the event is past or its cashup is closed.
  const canModifyActive = useMemo(() => {
    if (!activeReg) return false;
    return !isEventOver(activeReg.event);
  }, [activeReg]);

  const editTotal = useMemo(() => {
    return editEventOptions.reduce((sum: number, eo: any) => {
      if (Array.isArray(eo.variants) && eo.variants.length > 0) {
        return sum + eo.variants.reduce((vsum: number, v: any) => {
          const qty = editQuantities[`${eo.id}:${v.id}`] || 0;
          return vsum + qty * effectiveEventOptionUnitPrice(eo, v.id);
        }, 0);
      }
      return sum + (editQuantities[eo.id] || 0) * effectiveEventOptionUnitPrice(eo, null);
    }, 0);
  }, [editEventOptions, editQuantities]);

  const beginEdit = async () => {
    if (!activeReg || !token) return;
    setEditError(null);
    setEditLoading(true);
    try {
      // Load event options (with variants) for this event
      const eventData = await apiFetch<any>(`/api/events/${encodeURIComponent(activeReg.eventId)}`);
      const eventOptions = (eventData?.eventOptions || []) as any[];

      const regOptById = new Map<string, any>((activeReg.registrationOptions || []).map((o: any) => [o.id, o]));

      // Prefill quantities from the current registration
      const qtyMap: Record<string, number> = {};
      for (const ro of (activeReg.registrationOptions || [])) {
        const key = ro.variantId ? `${ro.eventOptionId}:${ro.variantId}` : ro.eventOptionId;
        qtyMap[key] = (qtyMap[key] || 0) + (ro.quantity || 0);
      }

      // Already-issued ticket quantity per option/variant — can't reduce below this
      // (tickets are never deleted or shrunk, only ever grown, once paid).
      const minQtyMap: Record<string, number> = {};
      for (const t of tickets) {
        const ro = regOptById.get(t.registrationOptionId);
        if (!ro) continue;
        const key = ro.variantId ? `${ro.eventOptionId}:${ro.variantId}` : ro.eventOptionId;
        minQtyMap[key] = (minQtyMap[key] || 0) + (t.quantity || 0);
      }

      // Ensure every option/variant has a (possibly zero) entry so they all render
      eventOptions.forEach((eo: any) => {
        if (Array.isArray(eo.variants) && eo.variants.length > 0) {
          eo.variants.forEach((v: any) => {
            const key = `${eo.id}:${v.id}`;
            if (!(key in qtyMap)) qtyMap[key] = 0;
          });
        } else if (!(eo.id in qtyMap)) {
          qtyMap[eo.id] = 0;
        }
      });

      setEditEventOptions(eventOptions);
      setEditQuantities(qtyMap);
      setEditBaseQty({ ...qtyMap });
      setEditMinQty(minQtyMap);
      setEditMode(true);
    } catch (e) {
      setEditError((e as any)?.message || 'Failed to load event options');
    } finally {
      setEditLoading(false);
    }
  };

  const saveEdit = async () => {
    if (!activeReg || !token) return;
    setEditError(null);

    for (const [key, minQty] of Object.entries(editMinQty)) {
      if (minQty <= 0) continue;
      if ((editQuantities[key] || 0) < minQty) {
        const [eventOptionId, variantId] = key.includes(':') ? key.split(':') : [key, undefined];
        const eo = editEventOptions.find((o: any) => o.id === eventOptionId);
        const variant = variantId ? (eo?.variants || []).find((v: any) => v.id === variantId) : null;
        const label = variant ? `${eo?.name || 'item'} (${variant.name})` : (eo?.name || 'item');
        setEditError(`Cannot reduce "${label}" below the ${minQty} already issued`);
        return;
      }
    }

    const payloadOptions: { eventOptionId: string; quantity: number; variantId?: string }[] = [];
    for (const [key, qty] of Object.entries(editQuantities)) {
      if (qty <= 0) continue;
      if (key.includes(':')) {
        const [eventOptionId, variantId] = key.split(':');
        payloadOptions.push({ eventOptionId, quantity: qty, variantId });
      } else {
        payloadOptions.push({ eventOptionId: key, quantity: qty });
      }
    }
    if (payloadOptions.length === 0) {
      setEditError('Please select at least one item');
      return;
    }
    // Enforce client-side: do not reduce below paid
    const paid = activeBill?.totalPaid || 0;
    if (editTotal < paid) {
      setEditError('Cannot reduce items below the amount already paid');
      return;
    }
    setLoading(true);
    try {
      await apiFetch(`/api/registrations/${encodeURIComponent(activeReg.id)}/options`, {
        method: 'PUT',
        authToken: token,
        body: { options: payloadOptions },
      });
      // Reload registrations to reflect changes
      const myRegs = await apiFetch<any[]>(`/api/registrations/myregistrations?showPast=${showPast ? '1' : '0'}`, { authToken: token });
      setRegistrations(myRegs);
      try {
        const myTicks = await apiFetch<any[]>("/api/tickets/mytickets", { authToken: token });
        setTickets(myTicks);
      } catch {}
      // Recompute billing totals using priceSnapshot
      const now2 = new Date();
      const totals: Record<string, { totalDue: number; totalPaid: number; outstanding: number; payments: any[] }> = {};
      for (const r of myRegs) {
        const totalDue = (r.registrationOptions || []).reduce((sum: number, opt: any) => sum + optionUnitPrice(opt, null, now2) * (opt.quantity || 0), 0);
        totals[r.id] = { totalDue, totalPaid: 0, outstanding: totalDue, payments: [] };
      }
      setBilling(totals);
      // Payments will be refreshed lazily or on next open; fetch for this one immediately
      try {
        const pays = await apiFetch<any[]>(`/api/payments/registration/${encodeURIComponent(activeReg.id)}`, { authToken: token });
        const totalPaid = pays.reduce((s, p) => s + (p.amount || 0), 0);
        const totalDue = totals[activeReg.id]?.totalDue ?? 0;
        setBilling(prev => ({
          ...prev,
          [activeReg.id]: {
            totalDue,
            totalPaid,
            outstanding: Math.max(0, totalDue - totalPaid),
            payments: pays,
          }
        }));
      } catch {}
      setInfo('Registration updated successfully');
      setEditMode(false);
    } catch (e: any) {
      setEditError(e?.message || 'Failed to update registration');
    } finally {
      setLoading(false);
    }
  };

  const router = useRouter();


  return (
    <div className="max-w-6xl mx-auto w-full px-4 py-6 sm:px-6">
      <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 mb-4">
        <h1 className="text-2xl font-semibold">Welcome{user ? `, ${user.name}` : ""}</h1>
        <div className="flex flex-wrap gap-2">
          <button
            className="px-2.5 py-1 text-xs rounded bg-gray-100 hover:bg-gray-200 text-gray-800 shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1"
            onClick={() => router.push("/dashboard/user/reset-password")}
          >Reset password</button>
          <button
            className="px-3 py-1.5 text-sm rounded bg-blue-600 text-white hover:bg-blue-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1"
            onClick={() => router.push("/dashboard/user/donate")}
          >Make donation</button>
        </div>
      </div>
      {error && <p className="text-red-600 text-sm mb-3">{error}</p>}
      {info && <p className="text-green-700 text-sm mb-3">{info}</p>}
      {loading && <p className="text-gray-500 text-sm mb-3">Loading…</p>}


      <section className="mb-8">
        <div className="flex items-center justify-between mb-3">
          <h2 className="text-xl font-semibold">My Registrations</h2>
          <label className="text-sm flex items-center gap-2">
            <input type="checkbox" checked={showPast} onChange={e => setShowPast(e.target.checked)} />
            <span>Show past events</span>
          </label>
        </div>
        <p className="text-sm text-gray-600 mb-3 italic">
          Click on registration to edit or make payment
        </p>
        {registrations.length === 0 ? (
          <p className="text-gray-600 text-sm">No registrations yet.</p>
        ) : (
          <ul className="space-y-2">
            {registrations
              // Hide cancelled always; hide past unless showPast
              .filter((r: any) => r.status !== 'cancelled')
              .filter((r: any) => showPast || !isEventOver(r.event))
              .map((r: any) => {
                const bill = billing[r.id];
                const isCancelled = r.status === 'cancelled';
                const outstanding = isCancelled ? 0 : (bill?.outstanding ?? 0);
                const totalDue = bill?.totalDue ?? 0;
                return (
                  <li
                    key={r.id}
                    className={"border rounded p-3 cursor-pointer " + (isCancelled ? "opacity-60 bg-gray-50" : "hover:bg-gray-50")}
                    onClick={() => setActiveRegId(r.id)}
                  >
                    <div className="flex items-start justify-between gap-3">
                      <div>
                        <div className="font-medium">{r.event?.title || r.eventId}</div>
                        <div className="text-xs text-gray-600">
                          Status: {r.status}{isCancelled && <span className="ml-2 inline-block text-[10px] px-1.5 py-0.5 rounded bg-gray-200 text-gray-700">cancelled</span>}
                        </div>
                        {(() => {
                          const fs = formStatuses[r.id];
                          if (!fs || !fs.hasForm) return null;
                          const label = fs.complete ? 'Complete' : 'Incomplete';
                          const colorClass = fs.complete
                            ? 'bg-green-100 text-green-800'
                            : (fs.isRequired ? 'bg-red-100 text-red-800' : 'bg-yellow-100 text-yellow-800');
                          return (
                            <div className="mt-1 text-xs">
                              <span className={`inline-block px-1.5 py-0.5 rounded ${colorClass}`}>Forms: {label}</span>
                            </div>
                          );
                        })()}
                        {(() => {
                          if (r.status == 'paid') return null;
                          // Early-bird notice: only for events with tiers that haven't passed
                          const allTiers = (r.registrationOptions || []).flatMap((ro: any) => Array.isArray(ro.eventOption?.earlyBirdTiers) ? ro.eventOption.earlyBirdTiers : []);
                          const upcoming = allTiers
                            .map((t: any) => ({ ...t, deadline: new Date(t.deadline) }))
                            .filter((t: any) => new Date() < t.deadline)
                            .sort((a: any, b: any) => a.deadline.getTime() - b.deadline.getTime());
                          if (upcoming.length === 0) return null;
                          const nextDeadline = upcoming[0].deadline;
                          const pays = (billing[r.id]?.payments || []);
                          const lastPaymentAt = pays.length > 0 ? new Date(Math.max(...pays.map((p: any) => new Date(p.createdAt).getTime()))) : null;
                          const now = new Date();
                          const priceNow = (r.registrationOptions || []).reduce((s: number, ro: any) => s + optionUnitPrice(ro, lastPaymentAt, now) * (ro.quantity || 0), 0);
                          const afterPrice = (r.registrationOptions || []).reduce((s: number, ro: any) => s + optionUnitPrice(ro, lastPaymentAt, new Date(nextDeadline.getTime() + 1000)) * (ro.quantity || 0), 0);
                          const dateStr = nextDeadline.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: '2-digit' });
                          if (afterPrice > priceNow) {
                            return (
                              <div className="mt-1 text-xs text-amber-700">
                                Early bird: R {priceNow.toFixed(2)} if paid before {dateStr}. Price increases to R {afterPrice.toFixed(2)} thereafter.
                              </div>
                            );
                          }
                          return (
                            <div className="mt-1 text-xs text-amber-700">
                              Early bird pricing in effect until {dateStr}.
                            </div>
                          );
                        })()}
                      </div>
                      <div className="text-right">
                        {isCancelled ? (
                          <div className="text-xs text-gray-500">No outstanding — registration cancelled</div>
                        ) : (
                          <>
                            <div className="text-sm">Outstanding: <span className={outstanding > 0 ? "text-red-600" : "text-green-700"}>{formatRand(outstanding)}</span></div>
                            <div className="text-xs text-gray-500">Total: {formatRand(totalDue)}</div>
                          </>
                        )}
                      </div>
                    </div>
                  </li>
                );
              })}
          </ul>
        )}
      </section>

      <section className="mb-8">
        <h2 className="text-xl font-semibold mb-2">Upcoming Events</h2>
        {upcomingEvents.length === 0 ? (
          <p className="text-gray-600 text-sm">No upcoming events.</p>
        ) : (
          <ul className="grid md:grid-cols-2 gap-3">
            {upcomingEvents.map(ev => (
              <li key={ev.id} className="border rounded p-4">
                <div className="font-medium">{ev.title}</div>
                <div className="text-sm text-gray-600">{new Date(ev.startDate).toLocaleString()} - {new Date(ev.endDate).toLocaleString()}</div>
                <div className="flex flex-wrap gap-2 mt-2">
                  <button
                    className="px-3 py-1.5 text-sm rounded bg-gray-100 hover:bg-gray-200 text-gray-800 shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1"
                    onClick={() => {
                      const list = tickets.filter(t => t.eventId === ev.id);
                      printTickets(list);
                    }}
                  >Print all tickets</button>
                  <button
                    className="px-3 py-1.5 text-sm bg-blue-600 text-white rounded hover:bg-blue-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1"
                    onClick={() => {
                      const ids = tickets.filter(t => t.eventId === ev.id).map(t => t.id);
                      emailTickets(ids);
                    }}
                  >Email all tickets</button>
                  {user?.phoneNumber && (
                    <button
                      className="px-3 py-1.5 text-sm bg-green-600 text-white rounded hover:bg-green-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-1"
                      onClick={() => {
                        const ids = tickets.filter(t => t.eventId === ev.id).map(t => t.id);
                        whatsappTickets(ids);
                      }}
                    >WhatsApp tickets</button>
                  )}
                </div>
              </li>
            ))}
          </ul>
        )}
      </section>

      <section>
        <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 mb-2">
          <h2 className="text-xl font-semibold">My Tickets</h2>
          {tickets.length > 0 && (
            <div className="flex flex-wrap gap-2">
              <button className="px-3 py-1.5 text-sm rounded bg-gray-100 hover:bg-gray-200 text-gray-800 shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1" onClick={() => selectAll(true)}>Select all</button>
              <button className="px-3 py-1.5 text-sm rounded bg-gray-100 hover:bg-gray-200 text-gray-800 shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1" onClick={() => selectAll(false)}>Clear</button>
              <button
                className="px-3 py-1.5 text-sm rounded bg-gray-100 hover:bg-gray-200 text-gray-800 shadow-sm disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1"
                disabled={selectedIds.length === 0}
                onClick={() => printTickets(tickets.filter(t => selectedIds.includes(t.id)))}
              >Print selected</button>
              <button
                className="px-3 py-1.5 text-sm bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50 shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1"
                disabled={selectedIds.length === 0}
                onClick={() => emailTickets(selectedIds)}
              >Email selected</button>
              {user?.phoneNumber && (
                <button
                  className="px-3 py-1.5 text-sm bg-green-600 text-white rounded hover:bg-green-700 disabled:opacity-50 shadow-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-1"
                  disabled={selectedIds.length === 0}
                  onClick={() => whatsappTickets(selectedIds)}
                >WhatsApp selected</button>
              )}
            </div>
          )}
        </div>
        {tickets.filter(t => showPast || !isEventOver(t.event)).length === 0 ? (
          <p className="text-gray-600 text-sm">No tickets yet.</p>
        ) : (
          <ul className="grid sm:grid-cols-2 lg:grid-cols-3 gap-3">
            {tickets
                        .filter((t: any) => showPast || !isEventOver(t.event))
                        .map((t: any) => {
              const eventDate = t.event?.startDate ? new Date(t.event.startDate) : null;
              const optionName = t.registrationOption?.eventOption?.name || "Ticket";
              const variantName = t.registrationOption?.variant?.name;
              const type = variantName ? `${optionName} — ${variantName}` : optionName;
              return (
                <li key={t.id} className="border rounded-xl p-3 space-y-2 bg-white shadow-sm">
                  <div className="flex items-start justify-between">
                    <label className="flex items-center gap-2 text-sm">
                      <input type="checkbox" checked={selected[t.id]} onChange={e => toggleSelect(t.id, e.target.checked)} />
                      <span className="font-medium">{t.event?.title || t.eventId}</span>
                    </label>
                    {eventDate && <span className="text-xs text-gray-500">{formatDate(eventDate)}</span>}
                  </div>
                  <div className="text-sm text-gray-700">{type}</div>
                  <div className="text-xs font-medium text-blue-700 bg-blue-50 rounded px-2 py-0.5 inline-block">
                    Qty: {t.quantity || 1}
                  </div>
                  <div className="flex justify-center"><QrImage value={t.qrCode || t.id} size={120} className="w-28 h-28" /></div>
                  <div className="text-center text-xs text-gray-500">#{t.id.slice(0, 8)}</div>
                  <div className="flex gap-2 pt-1 flex-wrap">
                    <button onClick={() => emailTickets([t.id])} className="px-3 py-1.5 text-sm bg-blue-600 text-white rounded hover:bg-blue-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1">Email</button>
                    {user?.phoneNumber && (
                      <button onClick={() => whatsappTickets([t.id])} className="px-3 py-1.5 text-sm bg-green-600 text-white rounded hover:bg-green-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-1">WhatsApp</button>
                    )}
                    <button onClick={() => printTickets([t])} className="px-3 py-1.5 text-sm rounded bg-gray-100 hover:bg-gray-200 text-gray-800 shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1">Print</button>
                  </div>
                </li>
              );
            })}
          </ul>
        )}
      </section>

      {activeReg && (
        <div className="fixed inset-0 bg-black/40 flex items-center justify-center z-50" onClick={() => { setEditMode(false); setEditError(null); setShowCancelConfirm(false); setActiveRegId(null); }}>
          <div className="bg-white rounded-lg shadow-lg max-w-xl w-full mx-4 p-5 max-h-[90vh] overflow-y-auto" onClick={e => e.stopPropagation()}>
            <div className="flex items-center justify-between mb-3">
              <h3 className="text-lg font-semibold">{activeReg.event?.title || activeReg.eventId}</h3>
              <button className="px-2.5 py-1 text-sm rounded bg-gray-100 hover:bg-gray-200 text-gray-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1" onClick={() => { setEditMode(false); setEditError(null); setShowCancelConfirm(false); setActiveRegId(null); }}>Close</button>
            </div>
            <div className="space-y-3">
              <div>
                <div className="text-sm text-gray-600">Status: {activeReg.status}</div>
                {activeBill && (
                  <div className="text-sm">
                    <div>Total: {formatRand(activeBill.totalDue)}</div>
                    <div>Paid: {formatRand(activeBill.totalPaid)}</div>
                    <div>Outstanding: <span className={activeBill.outstanding > 0 ? "text-red-600" : "text-green-700"}>{formatRand(activeBill.outstanding)}</span></div>
                  </div>
                )}
              </div>
              <div>
                <div className="font-medium mb-1 flex items-center justify-between">
                  <span>Registration items</span>
                  {!editMode && canModifyActive && (
                    <button disabled={editLoading} onClick={beginEdit} className="px-2.5 py-1 text-xs bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50">Edit</button>
                  )}
                </div>
                {!editMode ? (
                  <ul className="text-sm list-disc pl-5 space-y-1">
                    {(activeReg.registrationOptions || []).map((opt: any) => {
                      const variantLabel = opt.variant?.name ? ` (${opt.variant.name})` : '';
                      const unitPrice = (opt.priceSnapshot !== null && opt.priceSnapshot !== undefined)
                        ? Number(opt.priceSnapshot)
                        : (opt.variant?.price ?? opt.eventOption?.price ?? 0);
                      return (
                        <li key={opt.id}>
                          {opt.eventOption?.name}{variantLabel} x {opt.quantity} — {formatRand(unitPrice * (opt.quantity || 0))}
                          {unitPrice < (opt.eventOption?.price || 0) && (
                            <span className="ml-1 text-xs text-green-700">(early bird)</span>
                          )}
                        </li>
                      );
                    })}
                  </ul>
                ) : (
                  <div className="border rounded p-3 space-y-2 bg-gray-50">
                    {editError && <p className="text-xs text-red-600">{editError}</p>}
                    {editLoading ? (
                      <div className="text-sm text-gray-600">Loading options…</div>
                    ) : (
                      <>
                        <div className="space-y-2">
                          {editEventOptions.map((eo: any) => {
                            const hasVariants = Array.isArray(eo.variants) && eo.variants.length > 0;

                            const renderQtyInput = (key: string, unitPrice: number, stockLimit?: number, availableCount?: number) => {
                              const qty = editQuantities[key] || 0;
                              const minQty = editMinQty[key] || 0;
                              const baseQty = editBaseQty[key] || 0;
                              const maxQty = ((stockLimit ?? 0) > 0 && availableCount !== undefined)
                                ? availableCount + baseQty
                                : undefined;
                              return (
                                <div className="flex items-center gap-2">
                                  <label className="text-xs text-gray-600">Qty</label>
                                  <input type="number" min={minQty} max={maxQty} value={qty}
                                         onChange={e => {
                                           let v = Math.max(minQty, parseInt(e.target.value || '0', 10) || 0);
                                           if (maxQty !== undefined) v = Math.min(v, maxQty);
                                           setEditQuantities(prev => ({ ...prev, [key]: v }));
                                         }}
                                         className="w-20 border rounded px-2 py-1 text-sm" />
                                </div>
                              );
                            };

                            if (hasVariants) {
                              const variants = eo.variants.slice().sort((a: any, b: any) => (a.order || 0) - (b.order || 0));
                              return (
                                <div key={eo.id} className="border rounded bg-white overflow-hidden">
                                  <div className="px-3 py-2 bg-gray-100 text-sm font-medium">{eo.name}</div>
                                  <ul className="divide-y">
                                    {variants.map((v: any) => {
                                      const key = `${eo.id}:${v.id}`;
                                      const minQty = editMinQty[key] || 0;
                                      const unitPrice = effectiveEventOptionUnitPrice(eo, v.id);
                                      return (
                                        <li key={v.id} className="flex items-center justify-between gap-2 px-3 py-2">
                                          <div className="text-sm">
                                            <div>{v.name}</div>
                                            <div className="text-gray-600 text-xs">{formatRand(unitPrice)}</div>
                                            {minQty > 0 && (
                                              <div className="text-gray-500 text-[11px]">{minQty} already issued</div>
                                            )}
                                          </div>
                                          {renderQtyInput(key, unitPrice, v.stockLimit, v.availableCount)}
                                        </li>
                                      );
                                    })}
                                  </ul>
                                </div>
                              );
                            }

                            const key = eo.id;
                            const minQty = editMinQty[key] || 0;
                            const unitPrice = effectiveEventOptionUnitPrice(eo, null);
                            return (
                              <div key={eo.id} className="flex items-center justify-between gap-2 border rounded bg-white px-3 py-2">
                                <div className="text-sm">
                                  <div className="font-medium">{eo.name}</div>
                                  <div className="text-gray-600 text-xs">{formatRand(unitPrice)}</div>
                                  {minQty > 0 && (
                                    <div className="text-gray-500 text-[11px]">{minQty} already issued</div>
                                  )}
                                </div>
                                {renderQtyInput(key, unitPrice, eo.stockLimit, eo.availableCount)}
                              </div>
                            );
                          })}
                        </div>
                        <div className="flex items-center justify-between pt-2">
                          <div className="text-sm">
                            {(() => {
                              const paid = activeBill?.totalPaid || 0;
                              const hasAnyQty = Object.values(editQuantities).some(q => q > 0);
                              const invalid = editTotal < paid || !hasAnyQty;
                              return (
                                <>
                                  <div>New total: {formatRand(editTotal)}</div>
                                  {paid > 0 && <div className="text-xs text-gray-600">Paid: {formatRand(paid)}</div>}
                                  {invalid && <div className="text-xs text-red-600">Total cannot be below amount already paid and at least one item is required.</div>}
                                </>
                              );
                            })()}
                          </div>
                          <div className="flex gap-2">
                            <button onClick={() => { setEditMode(false); setEditError(null); }} className="px-2.5 py-1 text-xs rounded bg-gray-100 hover:bg-gray-200">Cancel</button>
                            <button onClick={saveEdit} className="px-2.5 py-1 text-xs bg-green-600 text-white rounded hover:bg-green-700">Save</button>
                          </div>
                        </div>
                      </>
                    )}
                  </div>
                )}
              </div>
              {activeBill && activeBill.payments.length > 0 && (
                <div>
                  <div className="font-medium mb-1">Payments</div>
                  <ul className="text-sm list-disc pl-5 space-y-1">
                    {activeBill.payments.map((p: any) => (
                      <li key={p.id}>{new Date(p.createdAt).toLocaleString()} — {formatRand(p.amount)} ({p.method || "Payment"})</li>
                    ))}
                  </ul>
                </div>
              )}
              <div className="flex flex-wrap gap-2 pt-2">
                {showFormsButton && (
                  <button
                    className="px-3 py-1.5 text-sm rounded bg-indigo-600 text-white hover:bg-indigo-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-1"
                    onClick={() => router.push(`/dashboard/user/forms?registrationId=${encodeURIComponent(activeReg.id)}`)}
                  >Attendee forms</button>
                )}
                {canModifyActive && activeBill && activeBill.outstanding > 0 ? (
                  <button
                    className="px-3 py-1.5 text-sm bg-green-600 text-white rounded hover:bg-green-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-1"
                    onClick={() => router.push(`/dashboard/user/pay?registrationId=${encodeURIComponent(activeReg.id)}`)}
                  >Make payment</button>
                ) : (
                  <>
                    <button className="px-3 py-1.5 text-sm rounded bg-gray-100 hover:bg-gray-200 text-gray-800 shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1" onClick={() => {
                      const regOptIds = new Set((activeReg.registrationOptions || []).map((o: any) => o.id));
                      const list = tickets.filter(t => regOptIds.has(t.registrationOptionId));
                      printTickets(list);
                    }}>Print all tickets</button>
                    <button className="px-3 py-1.5 text-sm bg-blue-600 text-white rounded hover:bg-blue-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1" onClick={() => emailRegistration(activeReg.id)}>Email all tickets</button>
                    {user?.phoneNumber && (
                      <button className="px-3 py-1.5 text-sm bg-green-600 text-white rounded hover:bg-green-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-1" onClick={() => whatsappRegistration(activeReg.id)}>WhatsApp tickets</button>
                    )}
                  </>
                )}
              </div>

              {/* Cancel registration — only shown when no payments have been made and the event still permits changes */}
              {canModifyActive && activeReg.status !== 'cancelled' && (activeBill?.totalPaid ?? 0) === 0 && (
                <div className="pt-3 border-t mt-1">
                  {!showCancelConfirm ? (
                    <button
                      className="text-sm text-red-600 hover:text-red-800 underline underline-offset-2"
                      onClick={() => setShowCancelConfirm(true)}
                    >
                      Cancel registration
                    </button>
                  ) : (
                    <div className="flex items-center gap-2 p-2 rounded border border-red-200 bg-red-50">
                      <span className="text-sm text-red-700 flex-1">Are you sure you want to cancel? This cannot be undone.</span>
                      <button
                        disabled={cancelLoading}
                        className="px-2.5 py-1 text-xs bg-red-600 text-white rounded hover:bg-red-700 disabled:opacity-50"
                        onClick={cancelRegistration}
                      >{cancelLoading ? 'Cancelling…' : 'Yes, cancel'}</button>
                      <button
                        className="px-2.5 py-1 text-xs rounded bg-gray-200 hover:bg-gray-300"
                        onClick={() => setShowCancelConfirm(false)}
                      >No</button>
                    </div>
                  )}
                </div>
              )}
            </div>
          </div>
        </div>
      )}

      {dialog.open && (
        <div
          className="fixed inset-0 bg-black/40 flex items-center justify-center z-50"
          onClick={() => { if (!dialog.loading) setDialog({ open: false, message: "", loading: false }); }}
        >
          <div className="bg-white rounded-lg shadow-lg max-w-sm w-full p-5" onClick={e => e.stopPropagation()}>
            {dialog.loading ? (
              <div className="flex flex-col items-center">
                <div className="w-10 h-10 mb-3 border-4 border-blue-600 border-t-transparent rounded-full animate-spin" aria-label="Loading" />
                <div className="text-base font-medium">Sending tickets…</div>
                <p className="text-sm text-gray-600 mt-1">Please wait while we send your tickets.</p>
              </div>
            ) : (
              <>
                <div className="text-lg font-semibold mb-2">Tickets sent</div>
                <p className="text-sm text-gray-700 mb-4">{dialog.message}</p>
                <div className="flex justify-end">
                  <button
                    className="px-3 py-1.5 text-sm bg-blue-600 text-white rounded hover:bg-blue-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1"
                    onClick={() => setDialog({ open: false, message: "", loading: false })}
                  >OK</button>
                </div>
              </>
            )}
          </div>
        </div>
      )}
    </div>
  );
}
