"use client";

import React, { useEffect, useMemo, useState } from "react";
import { useAuth } from "@/hooks/useAuth";
import { useRouter } from "next/navigation";
import { apiFetch } from "@/lib/api";
import { scoreUser } from "@/lib/fuzzyMatch";
import { useDismissingState } from "@/hooks/useDismissingState";
import { DoorOpen, UserPlus, CreditCard, CheckSquare, Ticket, RotateCcw, type LucideIcon } from "lucide-react";

type Mode = "registration" | "payment" | "checkin" | "tickets" | "refund";

const MODE_LABELS: Record<Mode, string> = {
    registration: "REGISTRATION",
    payment: "PAYMENT",
    checkin: "CHECK-IN",
    tickets: "TICKETS",
    refund: "REFUND",
};

const MODE_ICONS: Record<Mode, LucideIcon> = {
    registration: UserPlus,
    payment: CreditCard,
    checkin: CheckSquare,
    tickets: Ticket,
    refund: RotateCcw,
};

// ─── Fuzzy search helpers ─────────────────────────────────────────────────────

function fuzzyFilterRegs(allRegs: any[], search: string): any[] {
    if (!search) return allRegs;
    if (search.length === 1) {
        const q = search.toLowerCase();
        return allRegs.filter(r =>
            String(r.user?.name || "").toLowerCase().includes(q) ||
            String(r.user?.email || "").toLowerCase().includes(q) ||
            String(r.user?.phoneNumber || "").includes(q)
        );
    }
    return allRegs
        .map(r => ({ r, score: scoreUser(r.user || {}, search) }))
        .filter(x => x.score >= 0.45)
        .sort((a, b) => b.score - a.score)
        .map(x => x.r);
}

// ─── Pricing helpers ─────────────────────────────────────────────────────────

function effectiveOptionUnit(opt: any): number {
    const base = opt.price || 0;
    const tiers = (Array.isArray(opt.earlyBirdTiers) ? opt.earlyBirdTiers : []).filter((t: any) => !t.variantId);
    if (!tiers.length) return base;
    const now = new Date();
    const hit = tiers
        .map((t: any) => ({ ...t, deadline: new Date(t.deadline) }))
        .filter((t: any) => now < t.deadline)
        .sort((a: any, b: any) => a.deadline - b.deadline || (a.order || 0) - (b.order || 0) || a.price - b.price);
    return hit.length ? hit[0].price : base;
}

function effectiveVariantUnit(opt: any, variant: any): number {
    const base = variant.price !== null && variant.price !== undefined ? variant.price : opt.price || 0;
    const allTiers = Array.isArray(opt.earlyBirdTiers) ? opt.earlyBirdTiers : [];
    const vtiers = allTiers.filter((t: any) => t.variantId === variant.id);
    const tiers = vtiers.length ? vtiers : allTiers.filter((t: any) => !t.variantId);
    if (!tiers.length) return base;
    const now = new Date();
    const hit = tiers
        .map((t: any) => ({ ...t, deadline: new Date(t.deadline) }))
        .filter((t: any) => now < t.deadline)
        .sort((a: any, b: any) => a.deadline - b.deadline || (a.order || 0) - (b.order || 0) || a.price - b.price);
    return hit.length ? hit[0].price : base;
}

function initQuantities(eventOptions: any[]): Record<string, number> {
    const map: Record<string, number> = {};
    (eventOptions || []).forEach((o: any) => {
        if ((o.variants || []).length > 0) {
            (o.variants as any[]).forEach((v: any) => { map[`${o.id}::${v.id}`] = 0; });
        } else {
            map[o.id] = 0;
        }
    });
    return map;
}

function ticketLabel(t: any): string {
    const opt = t.registrationOption?.eventOption?.name || "Ticket";
    const variant = t.registrationOption?.variant?.name;
    return variant ? `${opt} — ${variant}` : opt;
}

export default function AtTheDoorPage() {
    const { user, loading, token } = useAuth();
    const router = useRouter();
    const [events, setEvents] = useState<any[]>([]);
    const [eventId, setEventId] = useState("");

    const [eventOptions, setEventOptions] = useState<any[]>([]);
    const [showOptionsModal, setShowOptionsModal] = useState(false);
    const [pendingUser, setPendingUser] = useState<any | null>(null);
    const [pendingEditReg, setPendingEditReg] = useState<any | null>(null);
    const [confirming, setConfirming] = useState(false);
    const [quantities, setQuantities] = useState<Record<string, number>>({});
    // Already-issued ticket quantity per option/variant, keyed like `quantities` — a
    // registration being edited can never drop an item below this (tickets are never
    // deleted or shrunk, only ever grown, once paid).
    const [minQuantities, setMinQuantities] = useState<Record<string, number>>({});

    const [showDonationModal, setShowDonationModal] = useState(false);
    const [donationUser, setDonationUser] = useState<any | null>(null);

    const [showNewAttendeeModal, setShowNewAttendeeModal] = useState(false);
    const [newAttendeeSeed, setNewAttendeeSeed] = useState("");

    useEffect(() => {
        if (!token) return;
        (async () => {
            try {
                const evs = await apiFetch<any[]>("/api/events/all", { authToken: token });
                const now = Date.now();

                const active = (evs || []).filter(ev => {
                    const t = new Date(ev.endDate).getTime();
                    // Registrations/payments are rejected server-side for closed (cashed-up)
                    // events — don't offer them here.
                    return !isNaN(t) && t > now && ev.cashupStatus !== 'closed';
                });

                active.sort(
                    (a, b) =>
                        new Date(a.startDate).getTime() -
                        new Date(b.startDate).getTime()
                );

                setEvents(active);

                if (active.length > 0) {
                    setEventId(active[0].id); // default
                }
            } catch {}
        })();
    }, [token]);

    useEffect(() => {
        if (!token || !eventId) return;

        (async () => {
            try {
                const ev = await apiFetch(`/api/events/${eventId}`, {
                    authToken: token
                });

                setEventOptions(ev.options || ev.eventOptions || []);
            } catch {
                setEventOptions([]);
            }
        })();
    }, [eventId, token]);

    const canView = useMemo(() => {
        const role = user?.role;
        return role === "admin" || role === "supervisor" || role === "staff";
    }, [user]);

    useEffect(() => {
        if (loading) return;
        if (!user) router.replace("/login");
    }, [user, loading]);

    const [mode, setMode] = useState<Mode>("registration");

    const [activeRegistration, setActiveRegistration] = useState<any | null>(null);
    const [info, setInfo] = useDismissingState<string | null>(null);
    const [error, setError] = useDismissingState<string | null>(null);

    const handleRegistrationCreated = (registration: any) => {
        setActiveRegistration(registration); // 🚀 Jump automatically (see effect below)
    };

    const handleRegistrationSelected = (registration: any) => {
        setActiveRegistration(registration);
    };

    useEffect(() => {
        if (!activeRegistration) return;

        const id = setTimeout(() => {
            // Fully paid → head straight to check-in; otherwise there's still a
            // balance to collect, so go capture payment first.
            setMode(activeRegistration.status === "paid" ? "checkin" : "payment");
        }, 0);

        return () => clearTimeout(id);

    }, [activeRegistration]);

    const confirmRegistration = async () => {
        if (confirming) return;

        const opts = Object.entries(quantities)
            .filter(([, qty]) => qty > 0)
            .map(([key, quantity]) => {
                const [eventOptionId, variantId] = key.split("::");
                return { eventOptionId, quantity, ...(variantId ? { variantId } : {}) };
            });

        if (!opts.length) {
            setError("Select at least one item");
            return;
        }

        for (const [key, minQty] of Object.entries(minQuantities)) {
            if (minQty > 0 && (quantities[key] || 0) < minQty) {
                const [eventOptionId, variantId] = key.split("::");
                const opt = eventOptions.find((o: any) => o.id === eventOptionId);
                const variant = variantId ? (opt?.variants || []).find((v: any) => v.id === variantId) : null;
                const label = variant ? `${opt?.name || "item"} (${variant.name})` : (opt?.name || "item");
                setError(`Cannot reduce "${label}" below the ${minQty} already issued`);
                return;
            }
        }

        setConfirming(true);
        try {
            if (pendingEditReg) {
                // Edit existing registration — replace options via PUT
                const res = await apiFetch(`/api/registrations/${pendingEditReg.id}/options`, {
                    method: "PUT",
                    authToken: token,
                    body: { options: opts }
                });
                setShowOptionsModal(false);
                setPendingEditReg(null);
                setInfo("Registration updated");
                handleRegistrationSelected(res);
            } else if (pendingUser) {
                // New attendee
                const res = await apiFetch("/api/registrations/manual", {
                    method: "POST",
                    authToken: token,
                    body: {
                        eventId,
                        user: {
                            name: pendingUser.name,
                            ...(pendingUser.email ? { email: pendingUser.email } : {}),
                            ...(pendingUser.phone ? { phoneNumber: pendingUser.phone } : {}),
                        },
                        options: opts,
                        notificationPreference: pendingUser.notifPref,
                    }
                });
                setShowOptionsModal(false);
                handleRegistrationCreated(res);
            }
        } catch (e: any) {
            setError(e?.message || "Failed");
        } finally {
            setConfirming(false);
        }
    };

    // Opens the new-attendee modal (pre-filled with whatever the user typed in search)
    const handleShowNewAttendee = (seed: string) => {
        setNewAttendeeSeed(seed);
        setShowNewAttendeeModal(true);
    };

    // Called when NewAttendeeModal is confirmed — proceed to options selection
    const handleNewAttendeeConfirm = ({ name, email, phone, notifPref }: { name: string; email: string; phone: string; notifPref: "email" | "whatsapp" | "both" }) => {
        const qtyMap = initQuantities(eventOptions);
        // Default main ticket to 1 (first variant if variants exist)
        eventOptions.forEach(o => {
            if (!o.isMainTicket) return;
            if ((o.variants || []).length > 0) {
                qtyMap[`${o.id}::${(o.variants as any[])[0].id}`] = 1;
            } else {
                qtyMap[o.id] = 1;
            }
        });
        setQuantities(qtyMap);
        setMinQuantities({});
        setPendingUser({ name, email: email || null, phone: phone || null, notifPref });
        setPendingEditReg(null);
        setShowNewAttendeeModal(false);
        setShowOptionsModal(true);
    };

    // Edit an existing registration — pre-fill with current quantities.
    // Re-fetches the registration fresh rather than trusting the (possibly up to 5-minutes-stale,
    // see DoorRegistrationPanel's polling interval) cached search-result snapshot, so the
    // already-issued-ticket floor below is always computed from current data.
    const handleEditRegistration = async (reg: any) => {
        let freshReg = reg;
        try {
            freshReg = await apiFetch<any>(`/api/registrations/${reg.id}`, { authToken: token });
        } catch (e: any) {
            setError(e?.message || "Failed to load latest registration data");
            return;
        }

        const qtyMap = initQuantities(eventOptions);
        const regOptions = freshReg.registrationOptions || freshReg.options || [];
        regOptions.forEach((ro: any) => {
            const key = ro.variantId ? `${ro.eventOptionId}::${ro.variantId}` : ro.eventOptionId;
            if (key in qtyMap) qtyMap[key] = ro.quantity || 0;
        });

        // Already-issued ticket quantity per option/variant — floor for the edit below
        const minQtyMap: Record<string, number> = {};
        regOptions.forEach((ro: any) => {
            const key = ro.variantId ? `${ro.eventOptionId}::${ro.variantId}` : ro.eventOptionId;
            const issuedQty = (ro.tickets || []).reduce((s: number, t: any) => s + (t.quantity || 0), 0);
            if (issuedQty > 0) minQtyMap[key] = (minQtyMap[key] || 0) + issuedQty;
        });

        setQuantities(qtyMap);
        setMinQuantities(minQtyMap);
        setPendingEditReg(freshReg);
        setPendingUser(null);
        setShowOptionsModal(true);
    };

    const handlePaymentCaptured = async (registration?: any, partial?: boolean) => {

        if (partial && registration) {
            setActiveRegistration(registration);
            setInfo("Partial payment recorded");
            return;
        }

        if (!registration && !activeRegistration) return;

        const reg = registration || activeRegistration;

        // Tickets are generated and emailed/WhatsApped automatically server-side
        // once a registration reaches "paid" (see paymentController) — no need to
        // fetch/print them here, just move straight to checking the attendee in.
        setActiveRegistration(reg);
        setInfo("Payment recorded — tickets sent. Ready to check in.");
        setMode("checkin");
    };

    const handleDonation = (user?: any) => {
        setDonationUser(user || null); // null = anonymous
        setShowDonationModal(true);
    };

    return (
        <div className="max-w-6xl mx-auto w-full p-4 sm:p-6">

            <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 mb-4">
                <div className="flex items-center gap-3 shrink-0">
                    <div className="w-10 h-10 rounded-xl bg-brand-50 flex items-center justify-center shrink-0">
                        <DoorOpen className="w-5 h-5 text-brand-600" />
                    </div>
                    <h1 className="text-2xl font-semibold text-gray-900">At The Door</h1>
                </div>
                <select
                    className="border rounded px-3 py-2 text-sm w-full sm:w-72 max-w-full"
                    value={eventId}
                    onChange={e => setEventId(e.target.value)}
                >
                    <option value="">Select event…</option>
                    {events.map(ev => (
                        <option key={ev.id} value={ev.id}>
                            {ev.title}
                        </option>
                    ))}
                </select>
                <button
                    className="px-3 py-1.5 text-sm rounded bg-gray-100 hover:bg-gray-200 shrink-0 self-start sm:self-auto"
                    onClick={() => router.push("/dashboard")}
                >
                    Back
                </button>
            </div>

            {!canView && (
                <div className="p-3 border rounded bg-yellow-50 text-sm mb-4">
                    Access denied.
                </div>
            )}

            {error && (
                <div className="p-3 mb-3 border rounded bg-red-100 text-red-700 text-sm animate-pulse">
                    {error}
                </div>
            )}

            {info && (
                <div className="p-3 mb-3 border rounded bg-emerald-100 text-emerald-700 text-sm">
                    {info}
                </div>
            )}

            {/* Mode Buttons */}
            <div className="flex gap-2 mb-4 flex-wrap">
                {(["registration", "payment", "checkin", "tickets", "refund"] as Mode[]).map(m => {
                    const Icon = MODE_ICONS[m];
                    return (
                        <button
                            key={m}
                            onClick={() => setMode(m)}
                            className={`inline-flex items-center gap-1.5 px-4 py-2 rounded text-sm font-medium border ${
                                mode === m
                                    ? m === "refund"
                                        ? "bg-red-600 text-white border-red-600"
                                        : "bg-brand-600 text-white border-brand-600"
                                    : "bg-white hover:bg-gray-50"
                            }`}
                        >
                            <Icon className="w-4 h-4" />
                            {MODE_LABELS[m]}
                        </button>
                    );
                })}
            </div>

            {/* ✅ Panels */}
            {mode === "registration" && (
                <DoorRegistrationPanel
                    token={token}
                    eventId={eventId}
                    onCreated={handleRegistrationCreated}
                    onSelected={handleRegistrationSelected}
                    onEditRegistration={handleEditRegistration}
                    onNewAttendee={handleShowNewAttendee}
                    onDonation={handleDonation}
                    setError={setError}
                />
            )}

            {mode === "payment" && (
                <DoorPaymentPanel
                    token={token}
                    registration={activeRegistration}
                    onSuccess={handlePaymentCaptured}
                    setError={setError}
                />
            )}

            {mode === "checkin" && (
                <DoorCheckInPanel token={token} eventId={eventId} registration={activeRegistration} setError={setError} setInfo={setInfo} />
            )}

            {mode === "tickets" && (
                <DoorTicketsPanel token={token} eventId={eventId} />
            )}

            {mode === "refund" && (
                <DoorRefundPanel token={token} eventId={eventId} setError={setError} setInfo={setInfo} />
            )}
            <OptionsModal
                open={showOptionsModal}
                onClose={() => { setShowOptionsModal(false); setPendingEditReg(null); }}
                options={eventOptions}
                quantities={quantities}
                setQuantities={setQuantities}
                minQuantities={minQuantities}
                onConfirm={confirmRegistration}
                confirming={confirming}
                isEdit={!!pendingEditReg}
                totalPaid={(pendingEditReg?.payments || []).reduce((s: number, p: any) => s + (p.amount || 0), 0)}
            />
            <DonationModal
                open={showDonationModal}
                onClose={() => setShowDonationModal(false)}
                user={donationUser}
                token={token}
                eventId={eventId}
                setError={setError}
            />
            <NewAttendeeModal
                open={showNewAttendeeModal}
                onClose={() => setShowNewAttendeeModal(false)}
                seed={newAttendeeSeed}
                onConfirm={handleNewAttendeeConfirm}
            />
        </div>
    );
}

function DoorRegistrationPanel({ token, eventId, onCreated, onSelected, onEditRegistration, onNewAttendee, onDonation, setError }: any) {
    const [search, setSearch] = useState("");
    const [allRegs, setAllRegs] = useState<any[]>([]);
    const [loading, setLoading] = useState(false);

    // Load registrations for this event — once on mount/eventId change, then every 5 min
    useEffect(() => {
        if (!token || !eventId) return;
        let cancelled = false;

        const load = async () => {
            try {
                setLoading(true);
                const regs = await apiFetch<any[]>(`/api/registrations/event/${eventId}`, { authToken: token });
                if (!cancelled) setAllRegs(regs || []);
            } catch {
                if (!cancelled) setAllRegs([]);
            } finally {
                if (!cancelled) setLoading(false);
            }
        };

        load();
        const timer = setInterval(load, 300000);
        return () => { cancelled = true; clearInterval(timer); };
    }, [token, eventId]);

    const results = fuzzyFilterRegs(allRegs, search);

    return (
        <div className="border rounded-xl p-4 bg-white shadow-sm">

            <div className="flex items-center justify-between mb-3">
                <div className="text-lg font-semibold">Find / Register</div>
                <button
                    onClick={async () => {
                        if (!token || !eventId) return;
                        try {
                            setLoading(true);
                            const regs = await apiFetch<any[]>(`/api/registrations/event/${eventId}`, { authToken: token });
                            setAllRegs(regs || []);
                        } catch {} finally { setLoading(false); }
                    }}
                    className="text-xs px-2 py-1 rounded border hover:bg-gray-50"
                >
                    {loading ? "Loading…" : "Refresh"}
                </button>
            </div>

            <input
                className="w-full border rounded px-3 py-3 text-lg"
                placeholder="Name, email or phone…"
                value={search}
                onChange={e => setSearch(e.target.value)}
                autoFocus
            />

            <div className="mt-3 space-y-2 max-h-96 overflow-auto">

                {results.map(r => (
                    <div key={r.id} className="border rounded p-3">
                        <div className="flex justify-between items-center">
                            <div>
                                <div className="font-medium text-sm">{r.user?.name || "Guest"}</div>
                                <div className="text-xs text-gray-500">
                                    {r.user?.email && !r.user.email.endsWith("@guest.local") ? r.user.email : ""}
                                    {r.user?.phoneNumber ? ` · ${r.user.phoneNumber}` : ""}
                                </div>
                                <div className="text-xs text-gray-400">
                                    {r.status === "paid" ? "PAID ✅" : `UNPAID · ${r.status}`}
                                </div>
                            </div>
                            <div className="flex gap-2">
                                <button onClick={() => onSelected(r)} className="px-2 py-1 text-xs rounded bg-brand-600 text-white">Open</button>
                                <button onClick={() => onEditRegistration(r)} className="px-2 py-1 text-xs rounded bg-emerald-600 text-white">Edit</button>
                                <button onClick={() => onDonation(r.user)} className="px-2 py-1 text-xs rounded bg-amber-500 text-white">Donation</button>
                            </div>
                        </div>
                    </div>
                ))}

                {/* New attendee row */}
                <div
                    className="border rounded p-3 flex justify-between items-center bg-emerald-50 hover:bg-emerald-100 cursor-pointer"
                    onClick={() => onNewAttendee(search)}
                >
                    <div className="font-medium text-sm text-emerald-800">
                        {search ? `New attendee "${search}"…` : "New attendee…"}
                    </div>
                    <div className="text-xs text-emerald-600 font-medium">+ Register</div>
                </div>

                {!loading && allRegs.length === 0 && (
                    <div className="text-sm text-gray-500">No registrations yet for this event.</div>
                )}
            </div>

            <button
                onClick={() => onDonation()}
                className="w-full py-3 rounded bg-amber-500 text-white font-semibold mt-3"
            >
                Anonymous Donation
            </button>
        </div>
    );
}

function DoorPaymentPanel({ token, registration, onSuccess, setError }: any) {
    const [amount, setAmount] = useState("");
    const [method, setMethod] = useState("card");
    const [saving, setSaving] = useState(false);
    const [showRefund, setShowRefund] = useState(false);
    const [showSendTickets, setShowSendTickets] = useState(false);

    if (!registration) {
        return (
            <div className="border rounded-xl p-6 bg-white shadow-sm text-sm text-gray-500">
                No registration selected
            </div>
        );
    }

    const options = registration.options || registration.registrationOptions || [];
    const payments = registration.payments || [];

    // Backend attaches a tranche-aware totalDueComputed (exact even when a line spans
    // multiple early-bird prices) — fall back to the old client-side estimate otherwise.
    const totalValue = registration.totalDueComputed ?? options.reduce((sum: number, opt: any) => {
        const price = (opt.priceSnapshot !== null && opt.priceSnapshot !== undefined)
            ? Number(opt.priceSnapshot)
            : (opt.eventOption?.price ?? opt.price ?? 0);
        const qty = opt.quantity || 0;
        return sum + price * qty;
    }, 0);

    const paidValue = payments.reduce(
        (sum: number, p: any) => sum + (p.amount || 0),
        0
    );

    const balance = Math.max(0, totalValue - paidValue);

    const save = async () => {
        if (!balance) {
            setError("Nothing due on this registration");
            return;
        }

        try {
            setSaving(true);

            await apiFetch("/api/payments", {
                method: "POST",
                authToken: token,
                body: {
                    registrationId: registration.id,
                    amount: parseFloat(amount),
                    method
                }
            });

            const updated = await apiFetch(`/api/registrations/${registration.id}`, {
                authToken: token
            });

            const updatedOptions = updated.options || updated.registrationOptions || [];
            const updatedPayments = updated.payments || [];

            const totalValue = updated.totalDueComputed ?? updatedOptions.reduce((sum: number, opt: any) => {
                const price = (opt.priceSnapshot !== null && opt.priceSnapshot !== undefined)
                    ? Number(opt.priceSnapshot)
                    : (opt.eventOption?.price ?? opt.price ?? 0);
                return sum + price * (opt.quantity || 0);
            }, 0);

            const paidValue = updatedPayments.reduce(
                (sum: number, p: any) => sum + (p.amount || 0),
                0
            );

            const updatedBalance = Math.max(0, totalValue - paidValue);

            if (updatedBalance === 0) {
                onSuccess(updated);  // 🎯 ONLY NOW generate tickets
            } else {
                onSuccess(updated, true); // 🎯 partial payment flow
            }

        } catch (e: any) {
            setError(e?.message || "Payment failed");
        } finally {
            setSaving(false);
        }
    };

    return (
        <div className="border rounded-xl p-6 bg-white shadow-sm">

            <div className="text-xl font-semibold mb-4">Payment</div>

            {/* ✅ User */}
            <div className="mb-4">
                <div className="text-lg font-semibold">
                    {registration.user?.name || "Guest"}
                </div>
            </div>

            {/* ✅ BIG MONEY BLOCK 😌🔥 */}
            <div className="grid grid-cols-3 gap-3 mb-5">

                <div className="border rounded-lg p-3 text-center">
                    <div className="text-xs text-gray-500">TOTAL</div>
                    <div className="text-lg font-semibold">
                        R {totalValue.toFixed(2)}
                    </div>
                </div>

                <div className="border rounded-lg p-3 text-center">
                    <div className="text-xs text-gray-500">PAID</div>
                    <div className="text-lg font-semibold">
                        R {paidValue.toFixed(2)}
                    </div>
                </div>

                <div className="border rounded-lg p-3 text-center bg-emerald-50">
                    <div className="text-xs text-gray-500">DUE</div>
                    <div className="text-2xl font-bold text-emerald-600">
                        R {balance.toFixed(2)}
                    </div>
                </div>

            </div>

            {/* ✅ Amount + Full Pay */}
            <div className="flex gap-2">

                <input
                    className="flex-1 border rounded px-3 py-4 text-2xl font-semibold"
                    placeholder="Amount"
                    type="number"
                    value={amount}
                    onChange={e => setAmount(e.target.value)}
                    autoFocus
                />

                {balance > 0 && (
                    <button
                        onClick={() => setAmount(String(balance))}
                        className="px-4 rounded bg-brand-600 text-white text-sm font-medium"
                    >
                        Full
                    </button>
                )}

            </div>

            {/* ✅ Method */}
            <select
                className="w-full border rounded px-3 py-3 mt-3 text-lg"
                value={method}
                onChange={e => setMethod(e.target.value)}
            >
                <option value="card">Card</option>
                <option value="cash">Cash</option>
                <option value="eft">EFT</option>
            </select>

            {/* Capture — only show when there's a balance */}
            {balance > 0 && (
                <button
                    onClick={save}
                    disabled={saving || !amount}
                    className="mt-4 w-full py-4 rounded bg-emerald-600 text-white text-lg font-semibold disabled:opacity-60"
                >
                    {saving ? "Saving…" : "Capture Payment"}
                </button>
            )}

            {/* Print / Send — show when fully paid */}
            {balance === 0 && (
                <div className="mt-4 flex gap-2">
                    <button
                        onClick={() => onSuccess(registration)}
                        className="flex-1 py-3 rounded bg-brand-600 text-white text-sm font-medium"
                    >
                        Print Tickets
                    </button>
                    <button
                        onClick={() => setShowSendTickets(true)}
                        className="flex-1 py-3 rounded bg-green-600 text-white text-sm font-medium"
                    >
                        Send Tickets
                    </button>
                </div>
            )}

            {/* Refund */}
            {paidValue > 0 && (
                <button
                    onClick={() => setShowRefund(true)}
                    className="mt-2 w-full py-2 rounded border border-red-300 text-red-600 text-sm hover:bg-red-50"
                >
                    Issue Refund
                </button>
            )}

            <RefundModal
                open={showRefund}
                onClose={() => setShowRefund(false)}
                token={token}
                registration={registration}
                maxRefund={paidValue}
                onRefunded={(updated: any) => {
                    setShowRefund(false);
                    onSuccess(updated, true);
                }}
                setError={setError}
            />

            <SendTicketsModal
                open={showSendTickets}
                onClose={() => setShowSendTickets(false)}
                token={token}
                registration={registration}
                setError={setError}
                setInfo={() => {}}
            />
        </div>
    );
}

function DoorTicketsPanel({ token, eventId }: any) {
    const [search, setSearch] = useState("");
    const [allTickets, setAllTickets] = useState<any[]>([]);
    const [loading, setLoading] = useState(false);
    const [sendTarget, setSendTarget] = useState<any | null>(null);

    // Load all tickets for the event once
    useEffect(() => {
        if (!token || !eventId) return;
        (async () => {
            try {
                setLoading(true);
                const res = await apiFetch<any>(`/api/tickets/event/${eventId}`, { authToken: token });
                setAllTickets(res?.tickets || res?.data || (Array.isArray(res) ? res : []));
            } catch {
                setAllTickets([]);
            } finally {
                setLoading(false);
            }
        })();
    }, [token, eventId]);

    const tickets = !search
        ? allTickets
        : (() => {
            const q = search.toLowerCase();
            const byId = allTickets.filter(t =>
                String(t.id).toLowerCase().includes(q) ||
                String(t.qrCode || "").toLowerCase().includes(q)
            );
            if (byId.length > 0) return byId;
            if (search.length < 2) return allTickets.filter(t =>
                String(t.user?.name || "").toLowerCase().includes(q) ||
                String(t.user?.email || "").toLowerCase().includes(q)
            );
            return allTickets
                .map(t => ({ t, score: scoreUser(t.user || {}, search) }))
                .filter(x => x.score >= 0.45)
                .sort((a, b) => b.score - a.score)
                .map(x => x.t);
        })();

    const load = async () => {
        if (!token || !eventId) return;
        try {
            setLoading(true);
            const res = await apiFetch<any>(`/api/tickets/event/${eventId}`, { authToken: token });
            setAllTickets(res?.tickets || res?.data || (Array.isArray(res) ? res : []));
        } catch {
            setAllTickets([]);
        } finally {
            setLoading(false);
        }
    };

    const print = (ticket: any) => {
        const w = window.open("", "_blank");
        if (!w) return;
        const eventTitle = ticket.event?.title || ticket.eventId || "Event";
        const eventDate = ticket.event?.startDate ? new Date(ticket.event.startDate) : null;
        const dateStr = eventDate ? eventDate.toLocaleDateString("en-ZA", { day: "numeric", month: "long", year: "numeric" }) : "";
        const type = ticketLabel(ticket);
        const qty = ticket.quantity || 1;
        const holder = ticket.user?.name || ticket.userId || "";
        const qrData = encodeURIComponent(ticket.qrCode || ticket.id);
        const qrSrc = `https://api.qrserver.com/v1/create-qr-code/?size=220x220&data=${qrData}`;

        w.document.write(`<!doctype html><html><head><title>Ticket</title>
<style>
  @page { size: A6; margin: 6mm; }
  * { box-sizing: border-box; }
  body { font-family: Arial, Helvetica, sans-serif; margin: 0; padding: 0; }
  .ticket { border: 1.5px solid #222; border-radius: 3mm; padding: 5mm; height: calc(148mm - 12mm); display: flex; flex-direction: column; justify-content: space-between; }
  .evt { font-weight: bold; font-size: 15pt; line-height: 1.2; }
  .date { font-size: 10pt; color: #555; margin-top: 2mm; }
  .type { font-size: 12pt; margin-top: 2mm; color: #222; }
  .holder { font-size: 10pt; margin-top: 1mm; color: #555; }
  .qty { font-size: 10pt; margin-top: 1mm; }
  .qrwrap { display: flex; justify-content: center; align-items: center; flex: 1; }
  .qrwrap img { width: 55mm; height: 55mm; display: block; }
  .meta { font-size: 9pt; text-align: center; color: #666; word-break: break-all; }
</style>
</head><body>
<div class="ticket">
  <div>
    <div class="evt">${eventTitle}</div>
    ${dateStr ? `<div class="date">${dateStr}</div>` : ""}
    <div class="type">${type}</div>
    ${holder ? `<div class="holder">${holder}</div>` : ""}
    <div class="qty">Qty: <strong>${qty}</strong></div>
  </div>
  <div class="qrwrap"><img src="${qrSrc}" alt="QR" /></div>
  <div class="meta">${ticket.id}</div>
</div>
<script>
(function(){
  function go(){
    var imgs=Array.prototype.slice.call(document.images);
    if(!imgs.length){window.print();return;}
    var n=imgs.length;
    function done(){if(--n<=0)setTimeout(function(){window.print();},150);}
    imgs.forEach(function(i){if(i.complete)done();else{i.addEventListener('load',done,{once:true});i.addEventListener('error',done,{once:true});}});
  }
  if(document.readyState==='complete')go();else window.addEventListener('load',go);
})();
</script>
</body></html>`);
        w.document.close();
        w.focus();
    };

    return (
        <div className="border rounded-xl p-4 bg-white shadow-sm">
            <div className="flex items-center justify-between mb-3">
                <div className="text-lg font-semibold">Tickets</div>
                <button onClick={load} className="text-xs px-2 py-1 rounded border hover:bg-gray-50">
                    {loading ? "Loading…" : "Refresh"}
                </button>
            </div>

            <div className="flex gap-2">
                <input
                    className="flex-1 border rounded px-3 py-3 text-lg"
                    placeholder="Filter by name, phone or ticket ID…"
                    value={search}
                    onChange={e => setSearch(e.target.value)}
                    autoFocus
                />
            </div>

            {loading && (
                <div className="text-sm text-gray-500 mt-2">
                    Searching…
                </div>
            )}

            <div className="mt-3 space-y-2 max-h-96 overflow-auto">
                {tickets.map(t => (
                    <div
                        key={t.id}
                        className="border rounded p-2 flex justify-between items-center"
                    >
                        <div className="text-sm">
                            <div className="font-medium">
                                {t.user?.name || "Guest"}
                            </div>
                            <div className="text-xs text-gray-500">
                                {ticketLabel(t)}
                            </div>
                        </div>

                        <div className="flex gap-1">
                            <button
                                onClick={() => print(t)}
                                className="px-3 py-1 text-xs rounded bg-emerald-600 text-white"
                            >
                                Print
                            </button>
                            <button
                                onClick={() => setSendTarget(t)}
                                className="px-3 py-1 text-xs rounded bg-green-600 text-white"
                            >
                                Send
                            </button>
                        </div>
                    </div>
                ))}

                {!loading && tickets.length === 0 && (
                    <div className="text-sm text-gray-500">
                        No tickets found
                    </div>
                )}
            </div>

            {sendTarget && (
                <SendTicketsModal
                    open={true}
                    onClose={() => setSendTarget(null)}
                    token={token}
                    registration={{
                        id: sendTarget.registrationOption?.registration?.id || sendTarget.registrationOption?.registrationId,
                        user: sendTarget.user,
                    }}
                    setError={() => {}}
                    setInfo={() => {}}
                />
            )}
        </div>
    );
}

function DoorCheckInPanel({ token, eventId, registration, setError, setInfo }: any) {
    const [ticketsForEvent, setTicketsForEvent] = useState<any[]>([]);
    const [loading, setLoading] = useState(false);
    const [qtyByTicket, setQtyByTicket] = useState<Record<string, number>>({});
    const [submittingId, setSubmittingId] = useState<string | null>(null);

    const load = async () => {
        if (!token || !eventId) return;
        try {
            setLoading(true);
            const res = await apiFetch<any>(`/api/tickets/event/${eventId}`, { authToken: token });
            const tickets = res?.tickets || res?.data || (Array.isArray(res) ? res : []);
            setTicketsForEvent(tickets.filter((t: any) => t.registrationOption?.eventOption?.isMainTicket));
        } catch {
            setTicketsForEvent([]);
        } finally {
            setLoading(false);
        }
    };

    useEffect(() => { load(); }, [token, eventId]);

    if (!registration) {
        return (
            <div className="border rounded-xl p-6 bg-white shadow-sm text-sm text-gray-500">
                No registration selected
            </div>
        );
    }

    const myTickets = ticketsForEvent
        .filter(t => t.registrationOption?.registration?.id === registration.id)
        .map(t => {
            const totalRedeemed = (t.usages || []).reduce((s: number, u: any) => s + (u.quantityRedeemed || 1), 0);
            const remaining = (t.quantity || 1) - totalRedeemed;
            return { ...t, totalRedeemed, remaining };
        });

    const qtyFor = (t: any) => qtyByTicket[t.id] ?? (t.remaining > 0 ? t.remaining : 1);
    const setQtyFor = (t: any, n: number) =>
        setQtyByTicket(q => ({ ...q, [t.id]: Math.max(1, Math.min(t.remaining || 1, n)) }));

    const commit = async (ticket: any) => {
        const qty = qtyFor(ticket);
        try {
            setSubmittingId(ticket.id);
            const res = await apiFetch<any>(
                `/api/tickets/scan/${encodeURIComponent(ticket.qrCode)}?eventId=${encodeURIComponent(eventId)}`,
                { method: "POST", authToken: token, body: { qty } }
            );
            setInfo(`${res?.qtyRedeemed ?? qty} checked in for ${registration.user?.name || "guest"}${
                res?.remaining > 0 ? ` — ${res.remaining} remaining` : " — fully checked in"
            }. Confirmation sent.`);
            await load();
        } catch (e: any) {
            setError(e?.message || "Check-in failed");
        } finally {
            setSubmittingId(null);
        }
    };

    return (
        <div className="border rounded-xl p-6 bg-white shadow-sm">

            <div className="text-xl font-semibold mb-4">Check-In</div>

            {/* ✅ User */}
            <div className="mb-4">
                <div className="text-lg font-semibold">
                    {registration.user?.name || "Guest"}
                </div>
            </div>

            {loading && (
                <div className="text-sm text-gray-500">Loading…</div>
            )}

            {!loading && myTickets.length === 0 && (
                <div className="text-sm text-gray-500">
                    No Main Tickets on this registration
                </div>
            )}

            <div className="space-y-4">
                {myTickets.map(t => {
                    const qty = qtyFor(t);
                    return (
                        <div key={t.id} className="border rounded-lg p-4">
                            <div className="text-sm font-medium mb-3">{ticketLabel(t)}</div>

                            <div className="grid grid-cols-3 gap-3 mb-4">
                                <div className="border rounded-lg p-3 text-center">
                                    <div className="text-xs text-gray-500">TOTAL</div>
                                    <div className="text-lg font-semibold">{t.quantity || 1}</div>
                                </div>

                                <div className="border rounded-lg p-3 text-center">
                                    <div className="text-xs text-gray-500">CHECKED IN</div>
                                    <div className="text-lg font-semibold">{t.totalRedeemed}</div>
                                </div>

                                <div className="border rounded-lg p-3 text-center bg-emerald-50">
                                    <div className="text-xs text-gray-500">REMAINING</div>
                                    <div className="text-2xl font-bold text-emerald-600">{t.remaining}</div>
                                </div>
                            </div>

                            {t.remaining > 0 ? (
                                <div className="flex items-center gap-3">
                                    <button
                                        onClick={() => setQtyFor(t, qty - 1)}
                                        className="w-9 h-9 border rounded flex items-center justify-center text-lg font-bold"
                                    >
                                        –
                                    </button>
                                    <div className="w-10 text-center text-lg font-semibold">{qty}</div>
                                    <button
                                        onClick={() => setQtyFor(t, qty + 1)}
                                        className="w-9 h-9 border rounded flex items-center justify-center text-lg font-bold bg-emerald-50 border-emerald-300 text-emerald-700"
                                    >
                                        +
                                    </button>

                                    <button
                                        onClick={() => commit(t)}
                                        disabled={submittingId === t.id}
                                        className="ml-auto px-4 py-2 text-sm rounded bg-brand-600 text-white disabled:opacity-50"
                                    >
                                        {submittingId === t.id ? "Checking in…" : `Check In ${qty}`}
                                    </button>
                                </div>
                            ) : (
                                <div className="text-sm text-emerald-600 font-medium">Fully checked in ✓</div>
                            )}
                        </div>
                    );
                })}
            </div>
        </div>
    );
}

function OptionsModal({ open, onClose, options, quantities, setQuantities, minQuantities = {}, onConfirm, confirming, isEdit, totalPaid = 0 }: any) {
    if (!open) return null;

    const safeOptions: any[] = options || [];

    const total = safeOptions.reduce((sum: number, o: any) => {
        if ((o.variants || []).length > 0) {
            return sum + (o.variants as any[]).reduce((vs: number, v: any) =>
                vs + (quantities[`${o.id}::${v.id}`] || 0) * effectiveVariantUnit(o, v), 0);
        }
        return sum + (quantities[o.id] || 0) * effectiveOptionUnit(o);
    }, 0);

    const belowPaid = isEdit && total < totalPaid;
    const belowIssued = isEdit && Object.entries(minQuantities).some(
        ([key, minQty]: [string, any]) => minQty > 0 && (quantities[key] || 0) < minQty
    );

    const stepper = (key: string, delta: number) =>
        setQuantities((q: Record<string, number>) => ({ ...q, [key]: Math.max(minQuantities[key] || 0, (q[key] || 0) + delta) }));

    return (
        <div className="fixed inset-0 bg-black/40 flex items-center justify-center z-50 p-4">
            <div className="bg-white rounded-2xl w-full max-w-2xl shadow-xl flex flex-col max-h-[90vh] overflow-hidden">

                {/* Header */}
                <div className="p-5 border-b flex-shrink-0">
                    <div className="text-xl font-semibold">
                        {isEdit ? "Edit Registration" : "Select Items"}
                    </div>
                    {isEdit && totalPaid > 0 && (
                        <div className="text-sm text-gray-500 mt-1">
                            Already paid: <strong>R {Number(totalPaid).toFixed(2)}</strong> — new total must be at least this amount.
                        </div>
                    )}
                </div>

                {/* Scrollable Content */}
                <div className="flex-1 overflow-y-auto overscroll-contain p-5 space-y-3">
                    {safeOptions.map((opt: any) => {
                        const hasVariants = (opt.variants || []).length > 0;
                        if (hasVariants) {
                            return (
                                <div key={opt.id} className="border rounded-xl overflow-hidden">
                                    <div className="px-4 py-2 bg-gray-50 border-b font-medium text-sm">
                                        {opt.name}
                                        {opt.isMainTicket && <span className="ml-1.5 text-xs text-brand-600 font-normal">• Main</span>}
                                    </div>
                                    {(opt.variants as any[]).map((v: any) => {
                                        const unit = effectiveVariantUnit(opt, v);
                                        const basePrice = v.price !== null && v.price !== undefined ? v.price : opt.price;
                                        const key = `${opt.id}::${v.id}`;
                                        const minQty = minQuantities[key] || 0;
                                        return (
                                            <div key={v.id} className="flex items-center justify-between px-4 py-2.5 border-b last:border-b-0">
                                                <div>
                                                    <div className="text-sm">{v.name}</div>
                                                    <div className="text-xs text-gray-500">
                                                        R {unit.toFixed(2)}
                                                        {unit < basePrice && basePrice > 0 && <span className="ml-1 text-green-600">(early bird)</span>}
                                                    </div>
                                                    {minQty > 0 && <div className="text-xs text-gray-400">{minQty} already issued</div>}
                                                </div>
                                                <div className="flex items-center gap-3">
                                                    <button onClick={() => stepper(key, -1)} disabled={(quantities[key] || 0) <= minQty} className="w-8 h-8 border rounded flex items-center justify-center text-lg font-bold disabled:opacity-40">–</button>
                                                    <div className="w-6 text-center text-base font-semibold">{quantities[key] || 0}</div>
                                                    <button onClick={() => stepper(key, 1)} className="w-8 h-8 border rounded flex items-center justify-center text-lg font-bold bg-emerald-50 border-emerald-300 text-emerald-700">+</button>
                                                </div>
                                            </div>
                                        );
                                    })}
                                </div>
                            );
                        }
                        const unit = effectiveOptionUnit(opt);
                        const minQty = minQuantities[opt.id] || 0;
                        return (
                            <div key={opt.id} className="border rounded-xl p-3">
                                <div className="font-medium">{opt.name}</div>
                                <div className="text-xs text-gray-500">
                                    R {unit.toFixed(2)}
                                    {unit < opt.price && opt.price > 0 && <span className="ml-1 text-green-600">(early bird, was R {opt.price.toFixed(2)})</span>}
                                    {opt.isMainTicket ? " • Main" : ""}
                                </div>
                                {minQty > 0 && <div className="text-xs text-gray-400">{minQty} already issued</div>}
                                <div className="flex gap-3 items-center mt-2">
                                    <button onClick={() => stepper(opt.id, -1)} disabled={(quantities[opt.id] || 0) <= minQty} className="w-8 h-8 border rounded flex items-center justify-center text-lg font-bold disabled:opacity-40">–</button>
                                    <div className="w-6 text-center text-lg font-semibold">{quantities[opt.id] || 0}</div>
                                    <button onClick={() => stepper(opt.id, 1)} className="w-8 h-8 border rounded flex items-center justify-center text-lg font-bold bg-emerald-50 border-emerald-300 text-emerald-700">+</button>
                                </div>
                            </div>
                        );
                    })}
                </div>

                {/* Footer */}
                <div className="p-4 border-t flex-shrink-0 bg-white">
                    {belowPaid && (
                        <div className="mb-3 text-sm text-red-600 bg-red-50 border border-red-200 rounded px-3 py-2">
                            New total (R {total.toFixed(2)}) is less than amount already paid (R {Number(totalPaid).toFixed(2)}). Please increase the selection.
                        </div>
                    )}
                    {belowIssued && (
                        <div className="mb-3 text-sm text-red-600 bg-red-50 border border-red-200 rounded px-3 py-2">
                            One or more items are below the quantity already issued as tickets. Please increase the selection.
                        </div>
                    )}
                    <div className="flex justify-between items-center">
                        <div className="text-lg font-semibold">Total: R {total.toFixed(2)}</div>
                        <div className="flex gap-2">
                            <button onClick={onClose} className="px-4 py-2 border rounded" disabled={confirming}>
                                Cancel
                            </button>
                            <button
                                onClick={onConfirm}
                                disabled={confirming || belowPaid || belowIssued}
                                className="px-4 py-2 rounded bg-emerald-600 text-white disabled:opacity-60 min-w-[140px]"
                            >
                                {confirming
                                    ? "Processing…"
                                    : isEdit ? "Save Changes" : "Confirm Registration"}
                            </button>
                        </div>
                    </div>
                </div>

            </div>
        </div>
    );
}

function DonationModal({ open, onClose, user, token, eventId, onSuccess, setError }: any) {
    const [amount, setAmount] = useState("");
    const [method, setMethod] = useState("cash");
    const [saving, setSaving] = useState(false);

    if (!open) return null;

    const saveDonation = async () => {
        const amt = parseFloat(amount);

        if (!amt || amt <= 0) {
            setError("Enter valid amount");
            return;
        }

        try {
            setSaving(true);

            await apiFetch("/api/payments", {
                method: "POST",
                authToken: token,
                body: {
                    amount: amt,
                    method,
                    userId: user?.id || undefined,
                    eventId,
                    isDonation: true
                }
            });

            onSuccess?.();

            setAmount("");
            onClose();

        } catch (e: any) {
            setError(e?.message || "Donation failed");
        } finally {
            setSaving(false);
        }
    };

    return (
        <div className="fixed inset-0 bg-black/40 flex items-center justify-center z-50">
            <div className="bg-white rounded-2xl p-6 w-full max-w-md shadow-xl">

                <div className="text-xl font-semibold mb-2">
                    Donation
                </div>

                <div className="text-sm text-gray-500 mb-4">
                    {user ? user.name : "Anonymous Donation"}
                </div>

                <input
                    className="w-full border rounded px-3 py-3 text-2xl font-semibold"
                    placeholder="Amount"
                    type="number"
                    value={amount}
                    onChange={e => setAmount(e.target.value)}
                    autoFocus
                />

                <select
                    className="w-full border rounded px-3 py-3 mt-3"
                    value={method}
                    onChange={e => setMethod(e.target.value)}
                >
                    <option value="cash">Cash</option>
                    <option value="card">Card</option>
                    <option value="eft">EFT</option>
                </select>

                <div className="flex gap-2 mt-4">
                    <button
                        onClick={onClose}
                        className="flex-1 py-3 border rounded"
                    >
                        Cancel
                    </button>

                    <button
                        onClick={saveDonation}
                        disabled={saving}
                        className="flex-1 py-3 rounded bg-emerald-600 text-white font-semibold"
                    >
                        {saving ? "Saving…" : "Capture"}
                    </button>
                </div>
            </div>
        </div>
    );
}

function SendTicketsModal({ open, onClose, token, registration, setError, setInfo }: any) {
    const [channel, setChannel] = useState<"email" | "whatsapp" | "both">("email");
    const [phone, setPhone] = useState("");
    const [email, setEmail] = useState("");
    const [sending, setSending] = useState(false);
    const [localError, setLocalError] = useDismissingState("");
    const [localInfo, setLocalInfo] = useState("");

    useEffect(() => {
        if (open && registration) {
            setPhone(registration.user?.phoneNumber || "");
            setEmail(registration.user?.email?.endsWith("@guest.local") ? "" : registration.user?.email || "");
            setLocalError("");
            setLocalInfo("");
        }
    }, [open, registration]);

    if (!open) return null;

    const send = async () => {
        setLocalError("");
        if ((channel === "email" || channel === "both") && !email.trim()) {
            setLocalError("Email address is required for email delivery.");
            return;
        }
        if ((channel === "whatsapp" || channel === "both") && !phone.trim()) {
            setLocalError("Phone number is required for WhatsApp delivery.");
            return;
        }
        setSending(true);
        try {
            await apiFetch("/api/tickets/send-to", {
                method: "POST",
                authToken: token,
                body: {
                    registrationId: registration.id,
                    channel,
                    overrideEmail: email.trim() || undefined,
                    overridePhone: phone.trim() || undefined,
                },
            });
            setLocalInfo("Tickets sent successfully.");
            setTimeout(() => { setLocalInfo(""); onClose(); }, 7000);
        } catch (e: any) {
            setLocalError(e?.message || "Failed to send tickets");
        } finally {
            setSending(false);
        }
    };

    return (
        <div className="fixed inset-0 bg-black/40 flex items-center justify-center z-50 p-4">
            <div className="bg-white rounded-2xl w-full max-w-md shadow-xl">
                <div className="p-6 space-y-4">
                    <div className="text-xl font-semibold">Send Tickets</div>
                    <div className="text-sm text-gray-600">
                        <span className="font-medium">{registration?.user?.name || "Guest"}</span>
                    </div>

                    <div>
                        <label className="block text-sm font-medium mb-1">Send via</label>
                        <div className="flex gap-2">
                            {(["email", "whatsapp", "both"] as const).map((c) => (
                                <button
                                    key={c}
                                    type="button"
                                    onClick={() => setChannel(c)}
                                    className={`flex-1 py-2 rounded border text-sm font-medium ${
                                        channel === c
                                            ? c === "whatsapp" ? "bg-green-600 text-white border-green-600"
                                            : c === "both" ? "bg-brand-600 text-white border-brand-600"
                                            : "bg-blue-600 text-white border-blue-600"
                                            : "bg-white text-gray-700 border-gray-300 hover:bg-gray-50"
                                    }`}
                                >
                                    {c === "both" ? "Both" : c === "whatsapp" ? "WhatsApp" : "Email"}
                                </button>
                            ))}
                        </div>
                    </div>

                    {(channel === "email" || channel === "both") && (
                        <div>
                            <label className="block text-sm font-medium mb-1">Email address</label>
                            <input
                                className="w-full border rounded px-3 py-2 text-sm"
                                type="email"
                                placeholder="recipient@example.com"
                                value={email}
                                onChange={(e) => setEmail(e.target.value)}
                            />
                        </div>
                    )}

                    {(channel === "whatsapp" || channel === "both") && (
                        <div>
                            <label className="block text-sm font-medium mb-1">WhatsApp number</label>
                            <input
                                className="w-full border rounded px-3 py-2 text-sm"
                                type="tel"
                                placeholder="e.g. 0821234567"
                                value={phone}
                                onChange={(e) => setPhone(e.target.value)}
                            />
                        </div>
                    )}

                    {localError && <p className="text-sm text-red-600">{localError}</p>}
                    {localInfo && <p className="text-sm text-emerald-600">{localInfo}</p>}

                    <div className="flex gap-2 pt-1">
                        <button type="button" onClick={onClose} className="flex-1 py-2 border rounded text-sm" disabled={sending}>
                            Cancel
                        </button>
                        <button
                            type="button"
                            onClick={send}
                            disabled={sending}
                            className="flex-1 py-2 rounded bg-brand-600 text-white text-sm font-medium disabled:opacity-60"
                        >
                            {sending ? "Sending…" : "Send Tickets"}
                        </button>
                    </div>
                </div>
            </div>
        </div>
    );
}

function RefundModal({ open, onClose, token, registration, maxRefund, onRefunded, setError }: any) {
    const [amount, setAmount] = useState("");
    const [method, setMethod] = useState("cash");
    const [reason, setReason] = useState("");
    const [saving, setSaving] = useState(false);
    const [localError, setLocalError] = useDismissingState("");

    useEffect(() => {
        if (open) { setAmount(""); setReason(""); setLocalError(""); }
    }, [open]);

    if (!open) return null;

    const save = async (e: React.FormEvent) => {
        e.preventDefault();
        const amt = parseFloat(amount);
        if (!amt || amt <= 0) { setLocalError("Enter a valid amount."); return; }
        if (amt > maxRefund) { setLocalError(`Cannot exceed total paid (R ${Number(maxRefund).toFixed(2)}).`); return; }

        setSaving(true);
        setLocalError("");
        try {
            await apiFetch("/api/payments/refund", {
                method: "POST",
                authToken: token,
                body: {
                    userId: registration.userId,
                    registrationId: registration.id,
                    amount: amt,
                    method,
                    reason: reason || undefined,
                }
            });
            // Re-fetch registration to get updated status & payments
            const updated = await apiFetch<any>(`/api/registrations/${registration.id}`, { authToken: token });
            onRefunded(updated);
        } catch (e: any) {
            setLocalError(e?.message || "Refund failed.");
        } finally {
            setSaving(false);
        }
    };

    return (
        <div className="fixed inset-0 bg-black/40 flex items-center justify-center z-50 p-4">
            <div className="bg-white rounded-2xl w-full max-w-md shadow-xl">
                <form onSubmit={save} className="p-6 space-y-4">
                    <div className="text-xl font-semibold text-red-700">Issue Refund</div>
                    <div className="text-sm text-gray-600">
                        <span className="font-medium">{registration.user?.name || "Guest"}</span>
                        <span className="ml-2 text-gray-400">· Total paid: R {Number(maxRefund).toFixed(2)}</span>
                    </div>

                    <div>
                        <label className="block text-sm font-medium mb-1">Refund amount</label>
                        <div className="flex gap-2">
                            <input
                                className="flex-1 border rounded px-3 py-3 text-2xl font-semibold"
                                type="number"
                                step="0.01"
                                min="0.01"
                                max={maxRefund}
                                placeholder="0.00"
                                value={amount}
                                onChange={e => setAmount(e.target.value)}
                                autoFocus
                            />
                            <button
                                type="button"
                                onClick={() => setAmount(String(maxRefund))}
                                className="px-3 rounded border text-sm"
                            >
                                Full
                            </button>
                        </div>
                    </div>

                    <div>
                        <label className="block text-sm font-medium mb-1">Method</label>
                        <select
                            className="w-full border rounded px-3 py-2"
                            value={method}
                            onChange={e => setMethod(e.target.value)}
                        >
                            <option value="cash">Cash</option>
                            <option value="card">Card</option>
                            <option value="eft">EFT</option>
                        </select>
                    </div>

                    <div>
                        <label className="block text-sm font-medium mb-1">Reason <span className="text-gray-400 font-normal">(optional)</span></label>
                        <input
                            className="w-full border rounded px-3 py-2 text-sm"
                            placeholder="e.g. Cancelled, overpayment…"
                            value={reason}
                            onChange={e => setReason(e.target.value)}
                        />
                    </div>

                    {localError && <p className="text-sm text-red-600">{localError}</p>}

                    <div className="flex gap-2 pt-1">
                        <button type="button" onClick={onClose} className="flex-1 py-2 border rounded text-sm" disabled={saving}>
                            Cancel
                        </button>
                        <button
                            type="submit"
                            disabled={saving || !amount}
                            className="flex-1 py-2 rounded bg-red-600 text-white text-sm font-medium disabled:opacity-60"
                        >
                            {saving ? "Processing…" : "Confirm Refund"}
                        </button>
                    </div>
                </form>
            </div>
        </div>
    );
}

function DoorRefundPanel({ token, eventId, setError, setInfo }: any) {
    const [search, setSearch] = useState("");
    const [allRegs, setAllRegs] = useState<any[]>([]);
    const [loading, setLoading] = useState(false);
    const [selectedReg, setSelectedReg] = useState<any | null>(null);
    const [showRefund, setShowRefund] = useState(false);

    const load = async () => {
        if (!token || !eventId) return;
        try {
            setLoading(true);
            const regs = await apiFetch<any[]>(`/api/registrations/event/${eventId}`, { authToken: token });
            setAllRegs(regs || []);
        } catch {
            setAllRegs([]);
        } finally {
            setLoading(false);
        }
    };

    useEffect(() => {
        load();
    }, [token, eventId]);

    // Only show registrations that have at least one payment
    const paidRegs = allRegs.filter(r =>
        (r.payments || []).reduce((s: number, p: any) => s + (p.amount || 0), 0) > 0
    );
    const results = fuzzyFilterRegs(paidRegs, search);

    const handleRefunded = async (updated: any) => {
        setShowRefund(false);
        setSelectedReg(updated);
        setInfo("Refund recorded");
        // Refresh list
        const regs = await apiFetch<any[]>(`/api/registrations/event/${eventId}`, { authToken: token }).catch(() => null);
        if (regs) setAllRegs(regs);
    };

    const maxRefund = selectedReg
        ? (selectedReg.payments || []).reduce((s: number, p: any) => s + (p.amount || 0), 0)
        : 0;

    return (
        <div className="border rounded-xl p-4 bg-white shadow-sm">
            <div className="flex items-center justify-between mb-3">
                <div className="text-lg font-semibold text-red-700">Refunds</div>
                <button
                    onClick={load}
                    className="text-xs px-2 py-1 rounded border hover:bg-gray-50"
                >
                    {loading ? "Loading…" : "Refresh"}
                </button>
            </div>

            {!selectedReg ? (
                <>
                    <input
                        className="w-full border rounded px-3 py-3 text-lg mb-3"
                        placeholder="Search name, email or phone…"
                        value={search}
                        onChange={e => setSearch(e.target.value)}
                        autoFocus
                    />

                    <div className="space-y-2 max-h-[32rem] overflow-auto">
                        {results.map(r => {
                            const paidValue = (r.payments || []).reduce((s: number, p: any) => s + (p.amount || 0), 0);
                            return (
                                <div key={r.id} className="border rounded p-3 flex justify-between items-center">
                                    <div>
                                        <div className="font-medium text-sm">{r.user?.name || "Guest"}</div>
                                        <div className="text-xs text-gray-500">
                                            {r.user?.email && !r.user.email.endsWith("@guest.local") ? r.user.email : ""}
                                            {r.user?.phoneNumber ? ` · ${r.user.phoneNumber}` : ""}
                                        </div>
                                        <div className="text-xs text-gray-400">
                                            Paid: R {paidValue.toFixed(2)} · {r.status}
                                        </div>
                                    </div>
                                    <button
                                        onClick={() => setSelectedReg(r)}
                                        className="px-3 py-1.5 text-sm rounded bg-red-600 text-white hover:bg-red-700"
                                    >
                                        Refund
                                    </button>
                                </div>
                            );
                        })}

                        {!loading && results.length === 0 && (
                            <div className="text-sm text-gray-500 py-4 text-center">
                                No paid registrations found for this event.
                            </div>
                        )}
                    </div>
                </>
            ) : (
                <div>
                    <button
                        onClick={() => setSelectedReg(null)}
                        className="text-sm text-gray-500 hover:text-gray-700 mb-4 flex items-center gap-1"
                    >
                        ← Back to list
                    </button>

                    <div className="border rounded-lg p-4 mb-4">
                        <div className="font-semibold text-lg">{selectedReg.user?.name || "Guest"}</div>
                        <div className="text-sm text-gray-500">
                            {selectedReg.user?.email && !selectedReg.user.email.endsWith("@guest.local") ? selectedReg.user.email : ""}
                            {selectedReg.user?.phoneNumber ? ` · ${selectedReg.user.phoneNumber}` : ""}
                        </div>
                        <div className="mt-3 grid grid-cols-2 gap-3">
                            <div className="border rounded p-3 text-center">
                                <div className="text-xs text-gray-500">TOTAL</div>
                                <div className="font-semibold">
                                    R {(selectedReg.totalDueComputed ?? (selectedReg.options || selectedReg.registrationOptions || []).reduce((s: number, o: any) => {
                                        const price = o.priceSnapshot !== null && o.priceSnapshot !== undefined
                                            ? Number(o.priceSnapshot)
                                            : (o.eventOption?.price || o.price || 0);
                                        return s + price * (o.quantity || 0);
                                    }, 0)).toFixed(2)}
                                </div>
                            </div>
                            <div className="border rounded p-3 text-center bg-red-50">
                                <div className="text-xs text-gray-500">PAID</div>
                                <div className="font-semibold text-red-700">R {maxRefund.toFixed(2)}</div>
                            </div>
                        </div>

                        {(selectedReg.payments || []).length > 0 && (
                            <div className="mt-3">
                                <div className="text-xs font-medium text-gray-500 mb-1">Payment history</div>
                                <div className="space-y-1">
                                    {selectedReg.payments.map((p: any, i: number) => (
                                        <div key={i} className="flex justify-between text-sm">
                                            <span className={p.amount < 0 ? "text-red-600" : ""}>
                                                {p.amount < 0 ? "Refund" : "Payment"} — {p.method || "—"}
                                                {p.reason ? ` (${p.reason})` : ""}
                                            </span>
                                            <span className={p.amount < 0 ? "text-red-600 font-medium" : ""}>
                                                R {Number(p.amount).toFixed(2)}
                                            </span>
                                        </div>
                                    ))}
                                </div>
                            </div>
                        )}
                    </div>

                    {maxRefund > 0 ? (
                        <button
                            onClick={() => setShowRefund(true)}
                            className="w-full py-3 rounded bg-red-600 text-white font-semibold hover:bg-red-700"
                        >
                            Issue Refund
                        </button>
                    ) : (
                        <div className="text-center text-sm text-gray-500 py-2">
                            Nothing to refund — net paid is R 0.00.
                        </div>
                    )}
                </div>
            )}

            <RefundModal
                open={showRefund}
                onClose={() => setShowRefund(false)}
                token={token}
                registration={selectedReg}
                maxRefund={maxRefund}
                onRefunded={handleRefunded}
                setError={setError}
            />
        </div>
    );
}

function NewAttendeeModal({ open, onClose, seed, onConfirm }: {
    open: boolean;
    onClose: () => void;
    seed: string;
    onConfirm: (data: { name: string; email: string; phone: string; notifPref: "email" | "whatsapp" | "both" }) => void;
}) {
    const [name, setName] = useState("");
    const [email, setEmail] = useState("");
    const [phone, setPhone] = useState("");
    const [notifPref, setNotifPref] = useState<"email" | "whatsapp" | "both">("email");
    const [err, setErr] = useState("");

    // Pre-fill name from whatever was typed in search
    useEffect(() => {
        if (open) {
            setName(seed || "");
            setEmail("");
            setPhone("");
            setNotifPref("email");
            setErr("");
        }
    }, [open, seed]);

    if (!open) return null;

    const derivedPref = email.trim() && phone.trim() ? notifPref : phone.trim() ? "whatsapp" : "email";

    const submit = (e: React.FormEvent) => {
        e.preventDefault();
        if (!name.trim()) { setErr("Name is required."); return; }
        if (!email.trim() && !phone.trim()) { setErr("Provide at least an email or phone number."); return; }
        onConfirm({ name: name.trim(), email: email.trim(), phone: phone.trim(), notifPref: derivedPref });
    };

    return (
        <div className="fixed inset-0 bg-black/40 flex items-center justify-center z-50 p-4">
            <div className="bg-white rounded-2xl w-full max-w-md shadow-xl">
                <form onSubmit={submit} className="p-6 space-y-4">
                    <div className="text-xl font-semibold">New Attendee</div>

                    <div>
                        <label className="block text-sm font-medium mb-1">Full name *</label>
                        <input
                            className="w-full border rounded px-3 py-2 text-sm"
                            value={name}
                            onChange={e => setName(e.target.value)}
                            placeholder="Full name"
                            autoFocus
                        />
                    </div>

                    <div>
                        <label className="block text-sm font-medium mb-1">Email</label>
                        <input
                            className="w-full border rounded px-3 py-2 text-sm"
                            type="email"
                            value={email}
                            onChange={e => setEmail(e.target.value)}
                            placeholder="Email address"
                        />
                    </div>

                    <div>
                        <label className="block text-sm font-medium mb-1">Cell number</label>
                        <input
                            className="w-full border rounded px-3 py-2 text-sm"
                            type="tel"
                            value={phone}
                            onChange={e => {
                                const v = e.target.value;
                                setPhone(v);
                                if (v.trim() && !email.trim()) setNotifPref("whatsapp");
                                else if (!v.trim() && email.trim()) setNotifPref("email");
                            }}
                            placeholder="+27…"
                        />
                    </div>

                    {/* Preference selector — shown only when both channels are provided */}
                    {email.trim() && phone.trim() && (
                        <div>
                            <label className="block text-xs font-medium text-gray-600 mb-1">Send tickets via</label>
                            <div className="flex rounded-lg border overflow-hidden text-xs font-medium">
                                {(["email", "whatsapp", "both"] as const).map((p) => (
                                    <button
                                        key={p}
                                        type="button"
                                        onClick={() => setNotifPref(p)}
                                        className={`flex-1 py-2 transition-colors ${
                                            notifPref === p
                                                ? p === "whatsapp" ? "bg-green-600 text-white"
                                                    : p === "both" ? "bg-brand-600 text-white"
                                                    : "bg-blue-600 text-white"
                                                : "bg-white text-gray-600 hover:bg-gray-50"
                                        }`}
                                    >
                                        {p === "email" ? "Email" : p === "whatsapp" ? "WhatsApp" : "Both"}
                                    </button>
                                ))}
                            </div>
                        </div>
                    )}

                    <p className="text-xs text-gray-500">At least one of email or cell number is required. If no email is provided, a guest account is created.</p>

                    {err && <p className="text-sm text-red-600">{err}</p>}

                    <div className="flex gap-2 pt-2">
                        <button type="button" onClick={onClose} className="flex-1 py-2 border rounded text-sm">Cancel</button>
                        <button type="submit" className="flex-1 py-2 rounded bg-emerald-600 text-white text-sm font-medium">Next — Choose Items</button>
                    </div>
                </form>
            </div>
        </div>
    );
}
