"use client";

import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { apiFetch } from "@/lib/api";

// ─── Types ────────────────────────────────────────────────────────────────────
type EarlyBirdTier = { deadline: string; price: number; order?: number; variantId?: string | null };
type OptionVariant = { id: string; name: string; price: number | null; stockLimit?: number; availableCount?: number | null };
type EventOption = {
  id: string;
  name: string;
  price: number;
  isMainTicket?: boolean;
  earlyBirdTiers?: EarlyBirdTier[];
  variants?: OptionVariant[];
};
type FormField = {
  id: string;
  type: string;
  label: string;
  isRequired: boolean;
  order: number;
  helpText?: string | null;
  options?: any;
};
type EventForm = {
  id: string;
  isRequired: boolean;
  fields: FormField[];
};
type KioskEvent = {
  id: string;
  title: string;
  description?: string;
  startDate: string;
  endDate: string;
  picture?: string;
  eventOptions?: EventOption[];
  form?: EventForm | null;
};

type Screen = "setup" | "form" | "eventform" | "confirmation";

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

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

function fmtDate(dateStr: string) {
  try {
    return new Date(dateStr).toLocaleDateString(undefined, {
      weekday: "short",
      year: "numeric",
      month: "short",
      day: "numeric",
    });
  } catch {
    return dateStr;
  }
}

function fmtCurrency(val: number) {
  return val === 0 ? "Free" : `R${val.toFixed(2)}`;
}

function prefLabel(pref: "email" | "whatsapp" | "both") {
  return pref === "whatsapp" ? "WhatsApp" : pref === "both" ? "Email & WhatsApp" : "Email";
}

// Loose "does this look like a mobile number" check — covers 0821234567 (10, leading 0),
// 821234567 (9, no leading 0), and 27821234567 / +27821234567 (11 digits, country code).
function looksLikePhone(s: string): boolean {
  const digits = s.replace(/\D/g, "");
  return digits.length >= 9 && digits.length <= 11;
}

// Show/hide toggle rendered inside a password input — absolutely positioned on its
// right edge, so callers must wrap the input in a `relative` container and add
// enough right padding (`pr-12`) for it not to overlap the typed text.
function PasswordToggleButton({ shown, onToggle }: { shown: boolean; onToggle: () => void }) {
  return (
    <button
      type="button"
      onClick={onToggle}
      tabIndex={-1}
      className="absolute inset-y-0 right-0 flex items-center px-4 text-gray-400 hover:text-gray-600"
      aria-label={shown ? "Hide password" : "Show password"}
    >
      {shown ? (
        <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
          <path strokeLinecap="round" strokeLinejoin="round" d="M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c1.563 0 3.042-.34 4.377-.955M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88" />
        </svg>
      ) : (
        <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
          <path strokeLinecap="round" strokeLinejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" />
          <path strokeLinecap="round" strokeLinejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
        </svg>
      )}
    </button>
  );
}

// ─── Kiosk Page ───────────────────────────────────────────────────────────────
export default function SelfServicePage() {
  const [screen, setScreen] = useState<Screen>("setup");

  // ── Setup state ─────────────────────────────────────────────────
  const [setupEmail, setSetupEmail] = useState("");
  const [setupPassword, setSetupPassword] = useState("");
  const [showSetupPassword, setShowSetupPassword] = useState(false);
  const [setupLoading, setSetupLoading] = useState(false);
  const [setupError, setSetupError] = useState<string | null>(null);
  const [supervisorToken, setSupervisorToken] = useState<string | null>(null);
  const [events, setEvents] = useState<KioskEvent[]>([]);
  const [selectedEventId, setSelectedEventId] = useState("");
  const [eventsLoading, setEventsLoading] = useState(false);

  // ── Change-event modal ───────────────────────────────────────────
  const [showChangeModal, setShowChangeModal] = useState(false);
  const [changePassword, setChangePassword] = useState("");
  const [showChangePassword, setShowChangePassword] = useState(false);
  const [changeError, setChangeError] = useState<string | null>(null);
  const [changeLoading, setChangeLoading] = useState(false);

  // ── Visitor form state ───────────────────────────────────────────
  const [visitorName, setVisitorName] = useState("");
  const [visitorEmail, setVisitorEmail] = useState("");
  const [visitorPhone, setVisitorPhone] = useState("");
  const [notificationPref, setNotificationPref] = useState<"email" | "whatsapp" | "both">("email");
  const [createAccount, setCreateAccount] = useState(false);
  const [visitorPassword, setVisitorPassword] = useState("");
  const [showVisitorPassword, setShowVisitorPassword] = useState(false);
  const [quantities, setQuantities] = useState<Record<string, number>>({});

  // ── Account lookup (automatic, triggered when email/phone is entered) ──
  // Email and phone are resolved to an existing account independently. If they
  // resolve to the SAME account, that account is "matched". If they resolve to
  // two DIFFERENT accounts, that's a conflict — surfaced to the operator instead
  // of silently overwriting one field's details with the other's account.
  type MatchedAccount = { id: string; name: string; email: string | null; phoneNumber: string | null; notificationPreference: "email" | "whatsapp" | "both" };
  const [emailMatch, setEmailMatch] = useState<MatchedAccount | null>(null);
  const [phoneMatch, setPhoneMatch] = useState<MatchedAccount | null>(null);
  const accountConflict = !!(emailMatch && phoneMatch && emailMatch.id !== phoneMatch.id);
  const matchedAccount = accountConflict ? null : (emailMatch || phoneMatch);
  const accountExists = !!matchedAccount;
  const [lookupLoading, setLookupLoading] = useState(false);
  const [lookupMessage, setLookupMessage] = useState<string | null>(null);
  const [showUpdateConfirm, setShowUpdateConfirm] = useState(false);
  const [formLoading, setFormLoading] = useState(false);
  const [formError, setFormError] = useState<string | null>(null);

  // ── Event form (attendee form) state ────────────────────────────
  const [currentRegistrationId, setCurrentRegistrationId] = useState<string | null>(null);
  const [currentUserId, setCurrentUserId] = useState<string | null>(null);
  const [currentTicketIndex, setCurrentTicketIndex] = useState(0);
  const [allFormAnswers, setAllFormAnswers] = useState<Record<string, string>[]>([]);
  const [currentTicketAnswers, setCurrentTicketAnswers] = useState<Record<string, string>>({});
  const [formSubmitLoading, setFormSubmitLoading] = useState(false);
  const [formSubmitError, setFormSubmitError] = useState<string | null>(null);

  // ── Confirmation state ───────────────────────────────────────────
  const [confirmationName, setConfirmationName] = useState("");
  const [registrationIsFree, setRegistrationIsFree] = useState(false);
  const [countdown, setCountdown] = useState(10);
  const countdownRef = useRef<ReturnType<typeof setInterval> | null>(null);

  // ─── Derived ────────────────────────────────────────────────────
  const selectedEvent = useMemo(
    () => events.find((e) => e.id === selectedEventId) || null,
    [events, selectedEventId]
  );

  const total = useMemo(() => {
    if (!selectedEvent) return 0;
    return (selectedEvent.eventOptions || []).reduce((sum, o) => {
      if ((o.variants || []).length > 0) {
        return sum + (o.variants || []).reduce((vs, v) => vs + (quantities[`${o.id}::${v.id}`] || 0) * effectiveVariantUnit(o, v), 0);
      }
      return sum + (quantities[o.id] || 0) * effectiveUnit(o);
    }, 0);
  }, [selectedEvent, quantities]);

  // Does the selected event have a required form?
  const eventHasRequiredForm = useMemo(() => {
    return !!(selectedEvent?.form?.isRequired && (selectedEvent.form.fields || []).some(f => f.type !== 'statement'));
  }, [selectedEvent]);

  // Answerable form fields (exclude statement-type display fields)
  const answerableFields = useMemo(() => {
    if (!selectedEvent?.form) return [];
    return (selectedEvent.form.fields || [])
      .filter(f => f.type !== 'statement')
      .sort((a, b) => (a.order || 0) - (b.order || 0));
  }, [selectedEvent]);

  // Number of main tickets selected (for form count)
  const mainTicketCount = useMemo(() => {
    if (!selectedEvent) return 0;
    return (selectedEvent.eventOptions || [])
      .filter(o => o.isMainTicket)
      .reduce((sum, o) => {
        if ((o.variants || []).length > 0) {
          return sum + (o.variants || []).reduce((vs, v) => vs + (quantities[`${o.id}::${v.id}`] || 0), 0);
        }
        return sum + (quantities[o.id] || 0);
      }, 0);
  }, [selectedEvent, quantities]);

  // Differences between what's on file for the matched account and what's currently
  // typed in the form — shown to the operator for confirmation before anything is saved.
  const pendingChanges = useMemo(() => {
    if (!matchedAccount) return [];
    const changes: { field: string; from: string; to: string }[] = [];
    const name = visitorName.trim();
    const email = visitorEmail.trim();
    const phone = visitorPhone.trim();
    if (name && name !== matchedAccount.name) {
      changes.push({ field: "Name", from: matchedAccount.name, to: name });
    }
    if (email && email !== (matchedAccount.email || "")) {
      changes.push({ field: "Email", from: matchedAccount.email || "(none on file)", to: email });
    }
    if (phone && phone !== (matchedAccount.phoneNumber || "")) {
      changes.push({ field: "Phone", from: matchedAccount.phoneNumber || "(none on file)", to: phone });
    }
    if (notificationPref !== matchedAccount.notificationPreference) {
      changes.push({
        field: "Send tickets via",
        from: prefLabel(matchedAccount.notificationPreference),
        to: prefLabel(notificationPref),
      });
    }
    return changes;
  }, [matchedAccount, visitorName, visitorEmail, visitorPhone, notificationPref]);

  // ─── Load events after supervisor login ─────────────────────────
  const loadEvents = useCallback(async (token: string) => {
    setEventsLoading(true);
    try {
      const data: KioskEvent[] = await apiFetch(
        "/api/events/all?includePast=false&includeInactive=false&excludeClosed=true",
        { authToken: token }
      );
      setEvents(data);
    } catch {
      setEvents([]);
    } finally {
      setEventsLoading(false);
    }
  }, []);

  // ─── Setup: supervisor login ─────────────────────────────────────
  async function handleSetupLogin(e: React.FormEvent) {
    e.preventDefault();
    setSetupError(null);
    setSetupLoading(true);
    try {
      const data = await apiFetch("/api/users/login", {
        method: "POST",
        body: { email: setupEmail, password: setupPassword },
      });
      const role: string = data.role || "";
      if (!["admin", "supervisor"].includes(role)) {
        setSetupError("Only admins and supervisors can set up the kiosk.");
        setSetupLoading(false);
        return;
      }
      setSupervisorToken(data.token);
      await loadEvents(data.token);
    } catch (err: any) {
      setSetupError(err?.message || "Login failed. Please check your credentials.");
    } finally {
      setSetupLoading(false);
    }
  }

  function handleStartKiosk() {
    if (!selectedEventId || !selectedEvent) return;
    const initial: Record<string, number> = {};
    (selectedEvent.eventOptions || []).forEach((o) => {
      if ((o.variants || []).length > 0) {
        (o.variants || []).forEach((v) => (initial[`${o.id}::${v.id}`] = 0));
      } else {
        initial[o.id] = 0;
      }
    });
    setQuantities(initial);
    setScreen("form");
  }

  // ─── Change event modal ──────────────────────────────────────────
  async function handleChangeEvent(e: React.FormEvent) {
    e.preventDefault();
    setChangeError(null);
    setChangeLoading(true);
    try {
      const data = await apiFetch("/api/users/login", {
        method: "POST",
        body: { email: setupEmail, password: changePassword },
      });
      const role: string = data.role || "";
      if (!["admin", "supervisor"].includes(role)) {
        setChangeError("Only admins and supervisors can change the event.");
        setChangeLoading(false);
        return;
      }
      setSupervisorToken(data.token);
      await loadEvents(data.token);
      setChangePassword("");
      setChangeError(null);
      setShowChangeModal(false);
      setScreen("setup");
      setSelectedEventId("");
      resetForm();
    } catch (err: any) {
      setChangeError(err?.message || "Incorrect password.");
    } finally {
      setChangeLoading(false);
    }
  }

  // ─── Visitor registration ────────────────────────────────────────
  // Validates the form and, if the typed name/email/phone differ from the matched
  // account's details, shows a confirmation modal before anything is saved.
  function handleRegisterSubmit(e: React.FormEvent) {
    e.preventDefault();
    setFormError(null);
    if (!visitorName.trim() || (!visitorEmail.trim() && !visitorPhone.trim())) {
      setFormError("Name and at least an email or phone number are required.");
      return;
    }
    if (createAccount && visitorPassword.trim().length < 6) {
      setFormError("Password must be at least 6 characters.");
      return;
    }
    if (!selectedEventId) {
      setFormError("No event selected.");
      return;
    }
    if (accountConflict) {
      setFormError("The email and phone number entered belong to two different existing accounts. Please check and correct one of them before continuing.");
      return;
    }
    if (pendingChanges.length > 0) {
      setShowUpdateConfirm(true);
      return;
    }
    handleRegister();
  }

  async function handleRegister() {
    setFormLoading(true);
    try {
      const payload: any = {
        eventId: selectedEventId,
        options: Object.entries(quantities)
          .filter(([, qty]) => qty > 0)
          .map(([key, quantity]) => {
            const [eventOptionId, variantId] = key.split("::");
            return { eventOptionId, quantity, ...(variantId ? { variantId } : {}) };
          }),
        user: {
          name: visitorName.trim(),
          ...(visitorEmail.trim() ? { email: visitorEmail.trim() } : {}),
          ...(visitorPhone.trim() ? { phoneNumber: visitorPhone.trim() } : {}),
        },
        guestOnly: !createAccount,
        notificationPreference: notificationPref,
      };
      if (createAccount && visitorPassword) {
        payload.user.password = visitorPassword;
      }

      const result: any = await apiFetch("/api/registrations/manual", {
        method: "POST",
        body: payload,
        authToken: supervisorToken,
      });

      setCurrentRegistrationId(result?.id || null);
      setCurrentUserId(result?.userId || null);
      setRegistrationIsFree(result?.status === "paid" || total === 0);
      setConfirmationName(visitorName.trim());

      // If event has a required form and there are main tickets, show form step
      if (eventHasRequiredForm && mainTicketCount > 0 && result?.id) {
        setCurrentTicketIndex(0);
        setAllFormAnswers([]);
        setCurrentTicketAnswers({});
        setFormSubmitError(null);
        setScreen("eventform");
      } else {
        setScreen("confirmation");
        startCountdown();
      }
    } catch (err: any) {
      setFormError(err?.message || "Registration failed. Please try again.");
    } finally {
      setFormLoading(false);
    }
  }

  // ─── Event form submission (per-ticket) ──────────────────────────
  async function handleFormSubmit(e: React.FormEvent) {
    e.preventDefault();
    setFormSubmitError(null);

    // Validate required fields for current ticket
    for (const field of answerableFields) {
      if (field.isRequired && !currentTicketAnswers[field.id]?.trim()) {
        setFormSubmitError(`"${field.label}" is required.`);
        return;
      }
    }

    if (!currentRegistrationId) {
      setFormSubmitError("No registration found.");
      return;
    }

    const collectedAnswers = [...allFormAnswers, currentTicketAnswers];

    // If more tickets remain, advance to the next one
    if (currentTicketIndex < mainTicketCount - 1) {
      setAllFormAnswers(collectedAnswers);
      setCurrentTicketAnswers({});
      setCurrentTicketIndex((i) => i + 1);
      return;
    }

    // Last ticket — submit all responses
    setFormSubmitLoading(true);
    try {
      const responses = collectedAnswers.map((answers) => ({ answers }));

      await apiFetch(`/api/registrations/${currentRegistrationId}/forms/responses`, {
        method: "POST",
        body: { responses },
        authToken: supervisorToken,
      });

      setScreen("confirmation");
      startCountdown();
    } catch (err: any) {
      setFormSubmitError(err?.message || "Form submission failed. Please try again.");
    } finally {
      setFormSubmitLoading(false);
    }
  }

  // ─── Confirmation countdown ──────────────────────────────────────
  function startCountdown() {
    setCountdown(10);
    if (countdownRef.current) clearInterval(countdownRef.current);
    countdownRef.current = setInterval(() => {
      setCountdown((c) => {
        if (c <= 1) {
          clearInterval(countdownRef.current!);
          resetAndGoToForm();
          return 0;
        }
        return c - 1;
      });
    }, 1000);
  }

  function resetAndGoToForm() {
    if (countdownRef.current) clearInterval(countdownRef.current);
    resetForm();
    setScreen("form");
    const initial: Record<string, number> = {};
    (selectedEvent?.eventOptions || []).forEach((o) => {
      if ((o.variants || []).length > 0) {
        (o.variants || []).forEach((v) => (initial[`${o.id}::${v.id}`] = 0));
      } else {
        initial[o.id] = 0;
      }
    });
    setQuantities(initial);
  }

  function resetForm() {
    setVisitorName("");
    setVisitorEmail("");
    setVisitorPhone("");
    setNotificationPref("email");
    setCreateAccount(false);
    setVisitorPassword("");
    setShowVisitorPassword(false);
    setEmailMatch(null);
    setPhoneMatch(null);
    appliedMatchIdRef.current = null;
    setShowUpdateConfirm(false);
    setLookupMessage(null);
    setFormError(null);
    setCurrentRegistrationId(null);
    setCurrentUserId(null);
    setCurrentTicketIndex(0);
    setAllFormAnswers([]);
    setCurrentTicketAnswers({});
    setFormSubmitError(null);
  }

  useEffect(() => {
    return () => {
      if (countdownRef.current) clearInterval(countdownRef.current);
    };
  }, []);

  // ─── Automatic account lookup — runs once the operator finishes entering the
  // email or phone field (on blur), never on keystroke. Matches exactly against
  // that one value and only ever returns that one matched account (or nothing) —
  // never a broader/fuzzy match. Email and phone are tracked as two independent
  // matches (emailMatch/phoneMatch, above) rather than being merged into a single
  // "last found account" — that's what previously let changing the phone number
  // silently pull in and overwrite the form with an unrelated account's details. ──
  async function performLookup(kind: "email" | "phone", rawValue: string) {
    const value = rawValue.trim();
    const setMatch = kind === "email" ? setEmailMatch : setPhoneMatch;
    if (!value || !supervisorToken) { setMatch(null); return; }
    if (kind === "email" ? !value.includes("@") : !looksLikePhone(value)) { setMatch(null); return; }

    setLookupLoading(true);
    setLookupMessage(null);
    try {
      const params = new URLSearchParams();
      if (kind === "email") params.set("email", value);
      else params.set("phone", value);
      const data = await apiFetch<{
        exists: boolean;
        user?: MatchedAccount | null;
      }>(`/api/users/check-exists?${params.toString()}`, { authToken: supervisorToken });
      if (data?.exists && data.user) {
        setMatch(data.user);
        setLookupMessage("Account found — details filled in below.");
      } else {
        setMatch(null);
        setLookupMessage(null);
      }
    } catch {
      setLookupMessage("Lookup failed. Please try again.");
    } finally {
      setLookupLoading(false);
    }
  }

  function handleEmailBlur() {
    performLookup("email", visitorEmail);
  }

  function handlePhoneBlur() {
    performLookup("phone", visitorPhone);
  }

  // Autofill Name/Email/Phone/preference from the matched account — but only once per
  // distinct account id. Re-focusing elsewhere on the page (e.g. tapping a ticket
  // quantity button) blurs whatever field was last active and re-runs its lookup;
  // that returns the same account as a new object each time, and keying this off
  // object identity instead of id made it re-fire and stomp every field — including
  // ones the operator had already deliberately edited — back to the account's
  // original values on every unrelated tap.
  const appliedMatchIdRef = useRef<string | null>(null);
  useEffect(() => {
    if (!matchedAccount || appliedMatchIdRef.current === matchedAccount.id) return;
    appliedMatchIdRef.current = matchedAccount.id;
    setVisitorName(matchedAccount.name);
    if (matchedAccount.email) setVisitorEmail(matchedAccount.email);
    if (matchedAccount.phoneNumber) setVisitorPhone(matchedAccount.phoneNumber);
    setNotificationPref(matchedAccount.notificationPreference);
  }, [matchedAccount]);

  // Existing accounts are linked automatically — never show the "create account" toggle for them
  useEffect(() => {
    if (accountExists && createAccount) {
      setCreateAccount(false);
      setVisitorPassword("");
    }
  }, [accountExists, createAccount]);

  // ─── Setup screen ────────────────────────────────────────────────
  const isLoggedIn = !!supervisorToken;

  // ─── Render ──────────────────────────────────────────────────────
  return (
    <div className="min-h-screen bg-gray-50 flex flex-col">
      {/* Change Event button */}
      {screen === "form" && (
        <div className="fixed top-3 right-3 z-50">
          <button
            onClick={() => { setShowChangeModal(true); setChangePassword(""); setChangeError(null); }}
            className="text-xs bg-white border border-gray-300 text-gray-500 rounded px-3 py-1.5 shadow-sm hover:bg-gray-100 transition"
          >
            Change Event
          </button>
        </div>
      )}

      {/* ── Change Event Modal ─────────────────────────────────────── */}
      {showChangeModal && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
          <div className="bg-white rounded-2xl shadow-2xl p-8 w-full max-w-sm mx-4">
            <h2 className="text-xl font-bold text-gray-800 mb-1">Change Event</h2>
            <p className="text-sm text-gray-500 mb-5">Re-enter your password to change the event.</p>
            <form onSubmit={handleChangeEvent} className="space-y-4">
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-1">Password</label>
                <div className="relative">
                  <input
                    type={showChangePassword ? "text" : "password"}
                    value={changePassword}
                    onChange={(e) => setChangePassword(e.target.value)}
                    className="w-full border border-gray-300 rounded-lg px-4 py-3 pr-12 text-base focus:outline-none focus:ring-2 focus:ring-blue-500"
                    placeholder="Your password"
                    autoFocus
                    required
                  />
                  <PasswordToggleButton shown={showChangePassword} onToggle={() => setShowChangePassword((v) => !v)} />
                </div>
              </div>
              {changeError && <p className="text-red-600 text-sm">{changeError}</p>}
              <div className="flex gap-3 pt-1">
                <button
                  type="button"
                  onClick={() => setShowChangeModal(false)}
                  className="flex-1 border border-gray-300 text-gray-700 rounded-lg py-3 text-base font-medium hover:bg-gray-50 transition"
                >
                  Cancel
                </button>
                <button
                  type="submit"
                  disabled={changeLoading}
                  className="flex-1 bg-blue-600 text-white rounded-lg py-3 text-base font-semibold hover:bg-blue-700 disabled:opacity-60 transition"
                >
                  {changeLoading ? "Verifying…" : "Confirm"}
                </button>
              </div>
            </form>
          </div>
        </div>
      )}

      {/* ── Setup Screen ───────────────────────────────────────────── */}
      {screen === "setup" && (
        <div className="flex-1 flex items-center justify-center p-6">
          <div className="bg-white rounded-2xl shadow-xl w-full max-w-md p-8">
            <div className="text-center mb-8">
              <h1 className="text-3xl font-bold text-gray-900">Self-Service Kiosk</h1>
              <p className="text-gray-500 mt-2">Supervisor setup required</p>
            </div>

            {!isLoggedIn && (
              <form onSubmit={handleSetupLogin} className="space-y-5">
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-1">Email</label>
                  <input
                    type="email"
                    value={setupEmail}
                    onChange={(e) => setSetupEmail(e.target.value)}
                    className="w-full border border-gray-300 rounded-xl px-4 py-3 text-base focus:outline-none focus:ring-2 focus:ring-blue-500"
                    placeholder="supervisor@example.com"
                    required
                    autoComplete="email"
                  />
                </div>
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-1">Password</label>
                  <div className="relative">
                    <input
                      type={showSetupPassword ? "text" : "password"}
                      value={setupPassword}
                      onChange={(e) => setSetupPassword(e.target.value)}
                      className="w-full border border-gray-300 rounded-xl px-4 py-3 pr-12 text-base focus:outline-none focus:ring-2 focus:ring-blue-500"
                      placeholder="••••••••"
                      required
                      autoComplete="current-password"
                    />
                    <PasswordToggleButton shown={showSetupPassword} onToggle={() => setShowSetupPassword((v) => !v)} />
                  </div>
                </div>
                {setupError && <p className="text-red-600 text-sm">{setupError}</p>}
                <button
                  type="submit"
                  disabled={setupLoading}
                  className="w-full bg-blue-600 text-white rounded-xl py-3.5 text-lg font-semibold hover:bg-blue-700 disabled:opacity-60 transition mt-2"
                >
                  {setupLoading ? "Signing in…" : "Sign In"}
                </button>
              </form>
            )}

            {isLoggedIn && (
              <div className="space-y-5">
                <p className="text-green-700 text-sm font-medium bg-green-50 border border-green-200 rounded-lg px-4 py-2">
                  Signed in as supervisor. Select an event to begin.
                </p>
                {eventsLoading ? (
                  <p className="text-gray-500 text-center py-4">Loading events…</p>
                ) : (
                  <div>
                    <label className="block text-sm font-medium text-gray-700 mb-1">Event</label>
                    <select
                      value={selectedEventId}
                      onChange={(e) => setSelectedEventId(e.target.value)}
                      className="w-full border border-gray-300 rounded-xl px-4 py-3 text-base focus:outline-none focus:ring-2 focus:ring-blue-500"
                    >
                      <option value="">— Select an event —</option>
                      {events.map((ev) => (
                        <option key={ev.id} value={ev.id}>
                          {ev.title} ({fmtDate(ev.startDate)})
                        </option>
                      ))}
                    </select>
                  </div>
                )}
                {selectedEvent && (
                  <div className="bg-blue-50 border border-blue-200 rounded-xl px-4 py-3 text-sm text-blue-800">
                    <p className="font-semibold">{selectedEvent.title}</p>
                    <p className="text-blue-600">{fmtDate(selectedEvent.startDate)} — {fmtDate(selectedEvent.endDate)}</p>
                    {selectedEvent.form?.isRequired && (
                      <p className="text-orange-600 mt-1 text-xs font-medium">This event requires an attendee form to be completed at registration.</p>
                    )}
                  </div>
                )}
                <button
                  onClick={handleStartKiosk}
                  disabled={!selectedEventId}
                  className="w-full bg-blue-600 text-white rounded-xl py-3.5 text-lg font-semibold hover:bg-blue-700 disabled:opacity-50 transition"
                >
                  Start Kiosk
                </button>
              </div>
            )}
          </div>
        </div>
      )}

      {/* ── Registration Form Screen ───────────────────────────────── */}
      {screen === "form" && selectedEvent && (
        <div className="flex-1 flex items-center justify-center p-6">
          <div className="bg-white rounded-2xl shadow-xl w-full max-w-lg p-8">
            <div className="text-center mb-7">
              <p className="text-sm text-gray-500 uppercase tracking-wide font-medium">Registering for</p>
              <h2 className="text-2xl font-bold text-gray-900 mt-1">{selectedEvent.title}</h2>
              <p className="text-gray-500 text-sm mt-1">{fmtDate(selectedEvent.startDate)}</p>
            </div>

            <form onSubmit={handleRegisterSubmit} className="space-y-5">
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-1">
                  Email Address
                  {!visitorPhone.trim() && <span className="text-red-500"> *</span>}
                  {visitorPhone.trim() && <span className="text-gray-400 font-normal"> (optional if phone provided)</span>}
                </label>
                <input
                  type="email"
                  value={visitorEmail}
                  onChange={(e) => {
                    const v = e.target.value;
                    setVisitorEmail(v);
                    // Auto-derive preference when only one contact channel is present
                    if (v.trim() && !visitorPhone.trim()) setNotificationPref("email");
                    else if (!v.trim() && visitorPhone.trim()) setNotificationPref("whatsapp");
                  }}
                  onBlur={handleEmailBlur}
                  className="w-full border border-gray-300 rounded-xl px-4 py-3.5 text-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
                  placeholder="john@example.com"
                />
              </div>
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-1">
                  Cell Number
                  {!visitorEmail.trim() && <span className="text-red-500"> *</span>}
                  {visitorEmail.trim() && <span className="text-gray-400 font-normal"> (optional if email provided)</span>}
                </label>
                <input
                  type="tel"
                  value={visitorPhone}
                  onChange={(e) => {
                    const v = e.target.value;
                    setVisitorPhone(v);
                    if (v.trim() && !visitorEmail.trim()) setNotificationPref("whatsapp");
                    else if (!v.trim() && visitorEmail.trim()) setNotificationPref("email");
                  }}
                  onBlur={handlePhoneBlur}
                  className="w-full border border-gray-300 rounded-xl px-4 py-3.5 text-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
                  placeholder="+27 82 000 0000"
                />
              </div>

              {lookupLoading && (
                <p className="text-sm text-gray-500 -mt-2">Checking for an existing account…</p>
              )}
              {!lookupLoading && accountConflict && emailMatch && phoneMatch && (
                <div className="bg-red-50 border border-red-200 rounded-xl px-4 py-3 text-red-700 text-sm -mt-2">
                  This email matches an existing account for <strong>{emailMatch.name}</strong>, but this phone number
                  matches a different existing account for <strong>{phoneMatch.name}</strong>. Please check and correct
                  one of these fields before continuing.
                </div>
              )}
              {!lookupLoading && !accountConflict && lookupMessage && (
                <p className={`text-sm -mt-2 ${lookupMessage.startsWith("Account found") ? "text-green-700" : "text-gray-500"}`}>
                  {lookupMessage}
                </p>
              )}

              <div>
                <label className="block text-sm font-medium text-gray-700 mb-1">Full Name <span className="text-red-500">*</span></label>
                <input
                  type="text"
                  value={visitorName}
                  onChange={(e) => setVisitorName(e.target.value)}
                  className="w-full border border-gray-300 rounded-xl px-4 py-3.5 text-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
                  placeholder="John Smith"
                  required
                />
              </div>

              {/* Preference selector — only shown when both channels are available */}
              {visitorEmail.trim() && visitorPhone.trim() && (
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-2">Send tickets via</label>
                  <div className="flex rounded-xl border border-gray-200 overflow-hidden text-sm font-medium">
                    {(["email", "whatsapp", "both"] as const).map((p) => (
                      <button
                        key={p}
                        type="button"
                        onClick={() => setNotificationPref(p)}
                        className={`flex-1 py-3 transition-colors ${
                          notificationPref === p
                            ? p === "whatsapp" ? "bg-green-600 text-white"
                              : p === "both" ? "bg-indigo-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>
              )}

              {/* Ticket options */}
              {(selectedEvent.eventOptions || []).length > 0 && (
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-3">Ticket Options</label>
                  <div className="space-y-3">
                    {(selectedEvent.eventOptions || []).map((opt) => {
                      const hasVariants = (opt.variants || []).length > 0;
                      if (hasVariants) {
                        return (
                          <div key={opt.id} className="border border-gray-200 rounded-xl overflow-hidden">
                            <div className="px-4 py-2.5 bg-gray-50 border-b border-gray-200">
                              <p className="font-medium text-gray-800 text-sm">{opt.name}</p>
                            </div>
                            <div className="divide-y divide-gray-100">
                              {(opt.variants || []).map((v) => {
                                const unit = effectiveVariantUnit(opt, v);
                                const baseVariantPrice = v.price !== null && v.price !== undefined ? v.price : opt.price;
                                const key = `${opt.id}::${v.id}`;
                                return (
                                  <div key={v.id} className="flex items-center justify-between px-4 py-3">
                                    <div>
                                      <p className="text-gray-800">{v.name}</p>
                                      <p className="text-sm text-gray-500">
                                        {fmtCurrency(unit)}
                                        {unit !== baseVariantPrice && baseVariantPrice > 0 ? ` (was ${fmtCurrency(baseVariantPrice)})` : ""}
                                      </p>
                                    </div>
                                    <div className="flex items-center gap-3">
                                      <button
                                        type="button"
                                        onClick={() => setQuantities((q) => ({ ...q, [key]: Math.max(0, (q[key] || 0) - 1) }))}
                                        className="w-10 h-10 rounded-full border-2 border-gray-300 text-xl font-bold text-gray-600 hover:bg-gray-100 flex items-center justify-center transition"
                                      >
                                        −
                                      </button>
                                      <span className="w-8 text-center text-lg font-semibold">{quantities[key] || 0}</span>
                                      <button
                                        type="button"
                                        onClick={() => setQuantities((q) => ({ ...q, [key]: (q[key] || 0) + 1 }))}
                                        className="w-10 h-10 rounded-full border-2 border-blue-500 text-xl font-bold text-blue-600 hover:bg-blue-50 flex items-center justify-center transition"
                                      >
                                        +
                                      </button>
                                    </div>
                                  </div>
                                );
                              })}
                            </div>
                          </div>
                        );
                      }
                      const unit = effectiveUnit(opt);
                      return (
                        <div key={opt.id} className="flex items-center justify-between border border-gray-200 rounded-xl px-4 py-3.5">
                          <div>
                            <p className="font-medium text-gray-800">{opt.name}</p>
                            <p className="text-sm text-gray-500">{fmtCurrency(unit)}{unit !== opt.price && opt.price > 0 ? ` (was ${fmtCurrency(opt.price)})` : ""}</p>
                          </div>
                          <div className="flex items-center gap-3">
                            <button
                              type="button"
                              onClick={() => setQuantities((q) => ({ ...q, [opt.id]: Math.max(0, (q[opt.id] || 0) - 1) }))}
                              className="w-10 h-10 rounded-full border-2 border-gray-300 text-xl font-bold text-gray-600 hover:bg-gray-100 flex items-center justify-center transition"
                            >
                              −
                            </button>
                            <span className="w-8 text-center text-lg font-semibold">{quantities[opt.id] || 0}</span>
                            <button
                              type="button"
                              onClick={() => setQuantities((q) => ({ ...q, [opt.id]: (q[opt.id] || 0) + 1 }))}
                              className="w-10 h-10 rounded-full border-2 border-blue-500 text-xl font-bold text-blue-600 hover:bg-blue-50 flex items-center justify-center transition"
                            >
                              +
                            </button>
                          </div>
                        </div>
                      );
                    })}
                  </div>
                  {total > 0 && (
                    <div className="mt-3 text-right text-base font-semibold text-gray-800">
                      Total: {fmtCurrency(total)}
                    </div>
                  )}
                </div>
              )}

              {/* Account creation toggle — hidden once we know an account already exists */}
              {accountExists ? (
                <div className="border border-green-200 bg-green-50 rounded-xl px-4 py-3 text-sm text-green-700">
                  An account with this email/number already exists — you&apos;ll be registered using that account.
                </div>
              ) : (
                <div className="border border-gray-200 rounded-xl px-4 py-4">
                  <label className="flex items-center gap-3 cursor-pointer">
                    <div
                      onClick={() => setCreateAccount((v) => !v)}
                      className={`relative w-12 h-6 rounded-full transition-colors ${createAccount ? "bg-blue-600" : "bg-gray-300"}`}
                    >
                      <span className={`absolute top-0.5 left-0.5 w-5 h-5 bg-white rounded-full shadow transition-transform ${createAccount ? "translate-x-6" : ""}`} />
                    </div>
                    <div>
                      <p className="font-medium text-gray-800">Create an account</p>
                      <p className="text-sm text-gray-500">Save your details for future events</p>
                    </div>
                  </label>
                  {createAccount && (
                    <div className="mt-3">
                      <label className="block text-sm font-medium text-gray-700 mb-1">Choose a password</label>
                      <div className="relative">
                        <input
                          type={showVisitorPassword ? "text" : "password"}
                          value={visitorPassword}
                          onChange={(e) => setVisitorPassword(e.target.value)}
                          className="w-full border border-gray-300 rounded-xl px-4 py-3 pr-12 text-base focus:outline-none focus:ring-2 focus:ring-blue-500"
                          placeholder="Min. 6 characters"
                          autoComplete="new-password"
                        />
                        <PasswordToggleButton shown={showVisitorPassword} onToggle={() => setShowVisitorPassword((v) => !v)} />
                      </div>
                    </div>
                  )}
                </div>
              )}

              {formError && (
                <div className="bg-red-50 border border-red-200 rounded-xl px-4 py-3 text-red-700 text-sm">
                  {formError}
                </div>
              )}

              <button
                type="submit"
                disabled={formLoading || accountConflict}
                className="w-full bg-blue-600 text-white rounded-xl py-4 text-xl font-bold hover:bg-blue-700 disabled:opacity-60 transition"
              >
                {formLoading ? "Registering…" : eventHasRequiredForm && mainTicketCount > 0 ? "Next — Fill in Form" : "Register"}
              </button>
            </form>
          </div>
        </div>
      )}

      {/* ── Confirm Account Changes Modal ──────────────────────────── */}
      {showUpdateConfirm && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
          <div className="bg-white rounded-2xl shadow-2xl p-8 w-full max-w-sm mx-4">
            <h2 className="text-xl font-bold text-gray-800 mb-1">Confirm account changes</h2>
            <p className="text-sm text-gray-500 mb-5">
              These details differ from what&apos;s on file for this account. Confirm to update them.
            </p>
            <div className="space-y-3 mb-6">
              {pendingChanges.map((c) => (
                <div key={c.field} className="border border-gray-200 rounded-lg px-3 py-2">
                  <p className="text-xs font-semibold text-gray-500 uppercase tracking-wide">{c.field}</p>
                  <p className="text-sm text-gray-400 line-through">{c.from}</p>
                  <p className="text-sm text-green-700 font-medium">{c.to}</p>
                </div>
              ))}
            </div>
            <div className="flex gap-3">
              <button
                type="button"
                onClick={() => setShowUpdateConfirm(false)}
                className="flex-1 border border-gray-300 text-gray-700 rounded-lg py-3 text-base font-medium hover:bg-gray-50 transition"
              >
                Cancel
              </button>
              <button
                type="button"
                onClick={() => { setShowUpdateConfirm(false); handleRegister(); }}
                className="flex-1 bg-blue-600 text-white rounded-lg py-3 text-base font-semibold hover:bg-blue-700 transition"
              >
                Confirm &amp; Update
              </button>
            </div>
          </div>
        </div>
      )}

      {/* ── Event Form Screen ──────────────────────────────────────── */}
      {screen === "eventform" && selectedEvent?.form && (
        <div className="flex-1 flex items-center justify-center p-6">
          <div className="bg-white rounded-2xl shadow-xl w-full max-w-lg p-8">
            <div className="text-center mb-6">
              <p className="text-sm text-gray-500 uppercase tracking-wide font-medium">{selectedEvent.title}</p>
              <h2 className="text-2xl font-bold text-gray-900 mt-1">Attendee Information</h2>
              {mainTicketCount > 1 && (
                <div className="mt-3">
                  <p className="text-base font-semibold text-blue-700">
                    Attendee {currentTicketIndex + 1} of {mainTicketCount}
                  </p>
                  <div className="flex gap-1.5 justify-center mt-2">
                    {Array.from({ length: mainTicketCount }).map((_, i) => (
                      <div
                        key={i}
                        className={`h-2 rounded-full transition-all ${
                          i < currentTicketIndex
                            ? "w-6 bg-green-500"
                            : i === currentTicketIndex
                            ? "w-6 bg-blue-600"
                            : "w-6 bg-gray-200"
                        }`}
                      />
                    ))}
                  </div>
                </div>
              )}
              {mainTicketCount <= 1 && (
                <p className="text-sm text-gray-500 mt-1">This form is required to complete your registration.</p>
              )}
            </div>

            <form onSubmit={handleFormSubmit} className="space-y-5">
              {answerableFields.map((field) => (
                <div key={field.id}>
                  <label className="block text-sm font-medium text-gray-700 mb-1">
                    {field.label}
                    {field.isRequired && <span className="text-red-500 ml-1">*</span>}
                  </label>
                  {field.helpText && (
                    <p className="text-xs text-gray-500 mb-1">{field.helpText}</p>
                  )}
                  {field.type === "yes_no" ? (
                    <div className="flex gap-4">
                      {["Yes", "No"].map((opt) => (
                        <label key={opt} className="flex items-center gap-2 cursor-pointer">
                          <input
                            type="radio"
                            name={field.id}
                            value={opt}
                            checked={currentTicketAnswers[field.id] === opt}
                            onChange={() => setCurrentTicketAnswers(a => ({ ...a, [field.id]: opt }))}
                            required={field.isRequired && !currentTicketAnswers[field.id]}
                            className="accent-blue-600"
                          />
                          <span className="text-base">{opt}</span>
                        </label>
                      ))}
                    </div>
                  ) : field.type === "numeric" ? (
                    <input
                      type="number"
                      value={currentTicketAnswers[field.id] || ""}
                      onChange={e => setCurrentTicketAnswers(a => ({ ...a, [field.id]: e.target.value }))}
                      required={field.isRequired}
                      className="w-full border border-gray-300 rounded-xl px-4 py-3 text-base focus:outline-none focus:ring-2 focus:ring-blue-500"
                    />
                  ) : field.type === "date" ? (
                    <input
                      type="date"
                      value={currentTicketAnswers[field.id] || ""}
                      onChange={e => setCurrentTicketAnswers(a => ({ ...a, [field.id]: e.target.value }))}
                      required={field.isRequired}
                      className="w-full border border-gray-300 rounded-xl px-4 py-3 text-base focus:outline-none focus:ring-2 focus:ring-blue-500"
                    />
                  ) : field.type === "paragraph" ? (
                    <textarea
                      value={currentTicketAnswers[field.id] || ""}
                      onChange={e => setCurrentTicketAnswers(a => ({ ...a, [field.id]: e.target.value }))}
                      required={field.isRequired}
                      rows={3}
                      className="w-full border border-gray-300 rounded-xl px-4 py-3 text-base focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none"
                    />
                  ) : (
                    <input
                      type="text"
                      value={currentTicketAnswers[field.id] || ""}
                      onChange={e => setCurrentTicketAnswers(a => ({ ...a, [field.id]: e.target.value }))}
                      required={field.isRequired}
                      className="w-full border border-gray-300 rounded-xl px-4 py-3 text-base focus:outline-none focus:ring-2 focus:ring-blue-500"
                    />
                  )}
                </div>
              ))}

              {formSubmitError && (
                <div className="bg-red-50 border border-red-200 rounded-xl px-4 py-3 text-red-700 text-sm">
                  {formSubmitError}
                </div>
              )}

              <button
                type="submit"
                disabled={formSubmitLoading}
                className="w-full bg-blue-600 text-white rounded-xl py-4 text-xl font-bold hover:bg-blue-700 disabled:opacity-60 transition"
              >
                {formSubmitLoading
                  ? "Submitting…"
                  : currentTicketIndex < mainTicketCount - 1
                  ? `Next — Attendee ${currentTicketIndex + 2} of ${mainTicketCount}`
                  : "Complete Registration"}
              </button>
            </form>
          </div>
        </div>
      )}

      {/* ── Confirmation Screen ────────────────────────────────────── */}
      {screen === "confirmation" && (
        <div className="flex-1 flex items-center justify-center p-6">
          <div className="bg-white rounded-2xl shadow-xl w-full max-w-md p-10 text-center">
            <div className="mx-auto mb-6 w-20 h-20 bg-green-100 rounded-full flex items-center justify-center">
              <svg className="w-10 h-10 text-green-600" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
                <path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
              </svg>
            </div>

            <h2 className="text-3xl font-bold text-gray-900 mb-2">You&apos;re Registered!</h2>
            {confirmationName && (
              <p className="text-lg text-gray-600 mb-3">Welcome, <span className="font-semibold">{confirmationName}</span>!</p>
            )}
            {selectedEvent && (
              <p className="text-blue-700 font-medium mb-4">{selectedEvent.title}</p>
            )}

            {registrationIsFree ? (
              <div className="bg-green-50 border border-green-200 rounded-xl px-4 py-3 text-green-800 text-sm mb-5">
                <p className="font-semibold">
                  {notificationPref === "whatsapp"
                    ? "Your tickets have been sent to your WhatsApp."
                    : notificationPref === "both"
                    ? "Your tickets have been sent via email and WhatsApp."
                    : "Your tickets have been emailed to you."}
                </p>
              </div>
            ) : (
              <div className="bg-blue-50 border border-blue-200 rounded-xl px-4 py-3 text-blue-800 text-sm mb-5 text-left">
                <p className="font-semibold mb-1">
                  {notificationPref === "whatsapp"
                    ? "Payment instructions have been sent to your WhatsApp."
                    : notificationPref === "both"
                    ? "Payment instructions have been sent via email and WhatsApp."
                    : "Payment instructions have been emailed to you."}
                </p>
                <p className="text-blue-700">Payment can also be made at the door — cash and card accepted.</p>
              </div>
            )}

            <div className="mb-6">
              <div className="inline-flex items-center justify-center w-16 h-16 rounded-full border-4 border-blue-200 bg-blue-50 text-2xl font-bold text-blue-700">
                {countdown}
              </div>
              <p className="text-sm text-gray-500 mt-2">Returning to registration in {countdown}s</p>
            </div>

            <button
              onClick={resetAndGoToForm}
              className="w-full bg-blue-600 text-white rounded-xl py-4 text-xl font-bold hover:bg-blue-700 transition"
            >
              OK — Next Person
            </button>
          </div>
        </div>
      )}
    </div>
  );
}