'use client';

import { useForm, useFieldArray } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { useRouter } from 'next/navigation';
import { useBookingStore } from '@/lib/booking-store';
import { useAuthStore } from '@/lib/auth-store';
import { apiClient } from '@/lib/api-client';
import { useState, useEffect, useRef } from 'react';
import { CheckCircle, ExternalLink, Loader2, CalendarDays, X, Globe, ChevronLeft, AlertCircle } from 'lucide-react';
import { gregorianToEthiopian, ethiopianToGregorian, ETHIOPIAN_MONTHS, getDaysInEthiopianMonth } from '@/lib/ethiopian-calendar';

const GC_MONTHS = ['January','February','March','April','May','June','July','August','September','October','November','December'];

const COUNTRIES = [
  'Djibouti', 'Afghanistan','Albania','Algeria','Andorra','Angola','Antigua and Barbuda','Argentina','Armenia','Australia','Austria',
  'Azerbaijan','Bahamas','Bahrain','Bangladesh','Barbados','Belarus','Belgium','Belize','Benin','Bhutan',
  'Bolivia','Bosnia and Herzegovina','Botswana','Brazil','Brunei','Bulgaria','Burkina Faso','Burundi','Cabo Verde','Cambodia',
  'Cameroon','Canada','Central African Republic','Chad','Chile','China','Colombia','Comoros','Congo','Costa Rica',
  'Croatia','Cuba','Cyprus','Czech Republic','Denmark','Dominica','Dominican Republic','Ecuador','Egypt',
  'El Salvador','Equatorial Guinea','Eritrea','Estonia','Eswatini','Fiji','Finland','France','Gabon',
  'Gambia','Georgia','Germany','Ghana','Greece','Grenada','Guatemala','Guinea','Guinea-Bissau','Guyana',
  'Haiti','Honduras','Hungary','Iceland','India','Indonesia','Iran','Iraq','Ireland','Israel',
  'Italy','Jamaica','Japan','Jordan','Kazakhstan','Kenya','Kiribati','Kuwait','Kyrgyzstan','Laos',
  'Latvia','Lebanon','Lesotho','Liberia','Libya','Liechtenstein','Lithuania','Luxembourg','Madagascar','Malawi',
  'Malaysia','Maldives','Mali','Malta','Marshall Islands','Mauritania','Mauritius','Mexico','Micronesia','Moldova',
  'Monaco','Mongolia','Montenegro','Morocco','Mozambique','Myanmar','Namibia','Nauru','Nepal','Netherlands',
  'New Zealand','Nicaragua','Niger','Nigeria','North Korea','North Macedonia','Norway','Oman','Pakistan','Palau',
  'Palestine','Panama','Papua New Guinea','Paraguay','Peru','Philippines','Poland','Portugal','Qatar','Romania',
  'Russia','Rwanda','Saint Kitts and Nevis','Saint Lucia','Saint Vincent and the Grenadines','Samoa','San Marino',
  'Sao Tome and Principe','Saudi Arabia','Senegal','Serbia','Seychelles','Sierra Leone','Singapore','Slovakia',
  'Slovenia','Solomon Islands','Somalia','South Africa','South Korea','South Sudan','Spain','Sri Lanka','Sudan',
  'Suriname','Sweden','Switzerland','Syria','Taiwan','Tajikistan','Tanzania','Thailand','Timor-Leste','Togo',
  'Tonga','Trinidad and Tobago','Tunisia','Turkey','Turkmenistan','Tuvalu','Uganda','Ukraine','United Arab Emirates',
  'United Kingdom','United States','Uruguay','Uzbekistan','Vanuatu','Vatican City','Venezuela','Vietnam',
  'Yemen','Zambia','Zimbabwe',
] as const;

function daysInGCMonth(y: number, m: number) {
  return new Date(y, m, 0).getDate();
}

const ADULT_MIN_AGE = 6;   // adults must be older than 5 years
const CHILD_MAX_AGE = 5;   // children must be 5 years old or younger
const ADULT_MAX_AGE_SPAN = 110;
const ADULT_DEFAULT_YEAR = 2000;

// ─── fayda passenger tracking ───────────────────────────────────────────────
// Fayda's OAuth redirect can land back on this route either inside the popup
// window we opened, or — on browsers/mobile contexts that refuse to open a
// popup — as a full-page navigation of this same tab. React state doesn't
// survive that reload, so we track which passenger triggered the verification
// in sessionStorage, which does survive same-tab navigation.
const FAYDA_PENDING_INDEX_KEY = 'edr_fayda_pending_passenger_index';

function getPendingFaydaIndex(): number | null {
  if (typeof window === 'undefined') return null;
  const raw = window.sessionStorage.getItem(FAYDA_PENDING_INDEX_KEY);
  if (raw === null) return null;
  const parsed = parseInt(raw, 10);
  return Number.isNaN(parsed) ? null : parsed;
}

function setPendingFaydaIndex(index: number) {
  if (typeof window === 'undefined') return;
  window.sessionStorage.setItem(FAYDA_PENDING_INDEX_KEY, String(index));
}

function clearPendingFaydaIndex() {
  if (typeof window === 'undefined') return;
  window.sessionStorage.removeItem(FAYDA_PENDING_INDEX_KEY);
}

// Verification is a full-page redirect out to Fayda and back (same flow on desktop and mobile —
// no popup). The in-progress form only lives in React memory, which the reload wipes, so we
// snapshot it to sessionStorage before leaving and restore it (in the form's defaultValues) on
// return. sessionStorage survives a same-tab navigation, including the cross-origin round trip.
const FAYDA_FORM_SNAPSHOT_KEY = 'edr_fayda_form_snapshot';

function saveFaydaFormSnapshot(snapshot: unknown) {
  if (typeof window === 'undefined') return;
  try {
    window.sessionStorage.setItem(FAYDA_FORM_SNAPSHOT_KEY, JSON.stringify(snapshot));
  } catch {
    // sessionStorage full/unavailable — verification still works, only unsaved fields are lost.
  }
}

function getFaydaFormSnapshot(): { passengers?: any[]; createAccount?: boolean } | null {
  if (typeof window === 'undefined') return null;
  try {
    const raw = window.sessionStorage.getItem(FAYDA_FORM_SNAPSHOT_KEY);
    return raw ? JSON.parse(raw) : null;
  } catch {
    return null;
  }
}

function clearFaydaFormSnapshot() {
  if (typeof window === 'undefined') return;
  window.sessionStorage.removeItem(FAYDA_FORM_SNAPSHOT_KEY);
}

// Fayda may return gender as "MALE"/"M" etc — normalize to the form's expected values
function normalizeFaydaGender(raw: unknown): 'Male' | 'Female' | '' {
  const g = String(raw || '').trim().toUpperCase();
  if (g === 'MALE' || g === 'M') return 'Male';
  if (g === 'FEMALE' || g === 'F') return 'Female';
  return '';
}

function DobPickerModal({
  value,
  onChange,
  error,
  passengerType = 'ADULT',
  disabled = false,
}: {
  value: string;
  onChange: (iso: string) => void;
  error?: string;
  passengerType?: 'ADULT' | 'CHILD';
  disabled?: boolean;
}) {
  const [open, setOpen] = useState(false);
  const [manualMode, setManualMode] = useState(false);
  const [calType, setCalType] = useState<'gregorian' | 'ethiopian'>('gregorian');
  const isChild = passengerType === 'CHILD';
  const currentYear = new Date().getFullYear();
  const currentEthYear = gregorianToEthiopian(new Date()).year;

  // Selectable year bounds, scoped to passenger type so the picker can't produce an invalid age
  const minGCYear = isChild ? currentYear - CHILD_MAX_AGE : currentYear - ADULT_MAX_AGE_SPAN;
  const maxGCYear = isChild ? currentYear : currentYear - ADULT_MIN_AGE;
  const minEthYear = isChild ? currentEthYear - CHILD_MAX_AGE : currentEthYear - ADULT_MAX_AGE_SPAN;
  const maxEthYear = isChild ? currentEthYear : currentEthYear - ADULT_MIN_AGE;

  // Parse stored ISO value (always Gregorian)
  const parsed = value ? value.split('-') : [];
  const defaultGCYear = isChild ? maxGCYear : Math.min(Math.max(ADULT_DEFAULT_YEAR, minGCYear), maxGCYear);
  const initGCYear  = parsed[0] ? parseInt(parsed[0]) : defaultGCYear;
  const initGCMonth = parsed[1] ? parseInt(parsed[1]) : 1;
  const initGCDay   = parsed[2] ? parseInt(parsed[2]) : 1;

  // Gregorian drum state
  const [selGCYear,  setSelGCYear]  = useState(initGCYear);
  const [selGCMonth, setSelGCMonth] = useState(initGCMonth);
  const [selGCDay,   setSelGCDay]   = useState(initGCDay);

  // Ethiopian drum state — initialise from parsed value if present
  const initEth = value ? gregorianToEthiopian(new Date(initGCYear, initGCMonth - 1, initGCDay)) : { year: isChild ? maxEthYear : Math.min(Math.max(ADULT_DEFAULT_YEAR - 8, minEthYear), maxEthYear), month: 1, day: 1 };
  const [selEthYear,  setSelEthYear]  = useState(initEth.year);
  const [selEthMonth, setSelEthMonth] = useState(initEth.month);
  const [selEthDay,   setSelEthDay]   = useState(initEth.day);

  // Manual inputs
  const [manDay,   setManDay]   = useState(parsed[2] ? String(parseInt(parsed[2])) : '');
  const [manMonth, setManMonth] = useState(parsed[1] ? String(parseInt(parsed[1])) : '');
  const [manYear,  setManYear]  = useState(parsed[0] || '');

  // Computed
  const gcMaxDay  = daysInGCMonth(selGCYear, selGCMonth);
  const ethMaxDay = getDaysInEthiopianMonth(selEthYear, selEthMonth);
  const gcSafeDay  = Math.min(selGCDay,  gcMaxDay);
  const ethSafeDay = Math.min(selEthDay, ethMaxDay);

  const gcYears   = Array.from({ length: maxGCYear - minGCYear + 1 }, (_, i) => maxGCYear - i);
  const ethYears  = Array.from({ length: maxEthYear - minEthYear + 1 }, (_, i) => maxEthYear - i);
  const gcMonths  = GC_MONTHS.map((m, i) => ({ label: m, value: i + 1 }));
  const ethMonths = ETHIOPIAN_MONTHS.map((m, i) => ({ label: m, value: i + 1 }));
  const gcDays    = Array.from({ length: gcMaxDay  }, (_, i) => i + 1);
  const ethDays   = Array.from({ length: ethMaxDay }, (_, i) => i + 1);

  const dayRef   = useRef<HTMLDivElement>(null);
  const monthRef = useRef<HTMLDivElement>(null);
  const yearRef  = useRef<HTMLDivElement>(null);
  const ITEM_H   = 48;

  const scrollTo = (ref: React.RefObject<HTMLDivElement>, idx: number) => {
    ref.current?.scrollTo({ top: Math.max(0, idx) * ITEM_H, behavior: 'smooth' });
  };

  // Scroll drums to current selection when opened or calType changed
  useEffect(() => {
    if (!open || manualMode) return;
    setTimeout(() => {
      if (calType === 'gregorian') {
        scrollTo(dayRef,   gcSafeDay - 1);
        scrollTo(monthRef, selGCMonth - 1);
        scrollTo(yearRef,  gcYears.indexOf(selGCYear));
      } else {
        scrollTo(dayRef,   ethSafeDay - 1);
        scrollTo(monthRef, selEthMonth - 1);
        scrollTo(yearRef,  ethYears.indexOf(selEthYear));
      }
    }, 60);
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open, manualMode, calType]);

  const makeScrollHandler = (
    ref: React.RefObject<HTMLDivElement>,
    setter: (v: number) => void,
    getList: () => number[],
  ) => {
    let timer: ReturnType<typeof setTimeout>;
    return () => {
      clearTimeout(timer);
      timer = setTimeout(() => {
        const el = ref.current;
        if (!el) return;
        const list = getList();
        const idx = Math.round(el.scrollTop / ITEM_H);
        const clamped = Math.max(0, Math.min(idx, list.length - 1));
        setter(list[clamped]);
        el.scrollTo({ top: clamped * ITEM_H, behavior: 'smooth' });
      }, 150);
    };
  };

  const gcDayHandler   = useRef(makeScrollHandler(dayRef,   setSelGCDay,   () => Array.from({ length: daysInGCMonth(selGCYear, selGCMonth) }, (_, i) => i + 1))).current;
  const gcMonthHandler = useRef(makeScrollHandler(monthRef, setSelGCMonth, () => GC_MONTHS.map((_, i) => i + 1))).current;
  const gcYearHandler  = useRef(makeScrollHandler(yearRef,  setSelGCYear,  () => gcYears)).current;

  const ethDayHandler   = useRef(makeScrollHandler(dayRef,   setSelEthDay,   () => Array.from({ length: getDaysInEthiopianMonth(selEthYear, selEthMonth) }, (_, i) => i + 1))).current;
  const ethMonthHandler = useRef(makeScrollHandler(monthRef, setSelEthMonth, () => ETHIOPIAN_MONTHS.map((_, i) => i + 1))).current;
  const ethYearHandler  = useRef(makeScrollHandler(yearRef,  setSelEthYear,  () => ethYears)).current;

  const confirm = () => {
    let gregDate: Date;
    if (calType === 'gregorian') {
      const d = Math.min(selGCDay, daysInGCMonth(selGCYear, selGCMonth));
      gregDate = new Date(selGCYear, selGCMonth - 1, d);
    } else {
      const d = Math.min(selEthDay, getDaysInEthiopianMonth(selEthYear, selEthMonth));
      gregDate = ethiopianToGregorian({ year: selEthYear, month: selEthMonth, day: d });
    }
    const iso = `${gregDate.getFullYear()}-${String(gregDate.getMonth() + 1).padStart(2,'0')}-${String(gregDate.getDate()).padStart(2,'0')}`;
    onChange(iso);
    setOpen(false);
  };

  const confirmManual = () => {
    const d = parseInt(manDay), m = parseInt(manMonth), y = parseInt(manYear);
    if (!d || !m || !y || m < 1 || m > 12 || d < 1 || d > daysInGCMonth(y, m) || y < minGCYear || y > maxGCYear) return;
    onChange(`${y}-${String(m).padStart(2,'0')}-${String(d).padStart(2,'0')}`);
    setOpen(false);
  };

  const manualValid = (() => {
    const d = parseInt(manDay), m = parseInt(manMonth), y = parseInt(manYear);
    return d >= 1 && m >= 1 && m <= 12 && y >= minGCYear && y <= maxGCYear && d <= daysInGCMonth(y, m);
  })();

  const manualRangeMessage = isChild
    ? `Child's date of birth must fall between ${minGCYear} and ${maxGCYear} (age 5 or younger)`
    : `Adult's date of birth must fall between ${minGCYear} and ${maxGCYear} (age older than 5)`;

  // Display: always show Gregorian ISO as human-readable, with calendar label
  const displayValue = (() => {
    if (!value) return '';
    const [y, mo, d] = value.split('-').map(Number);
    const gcStr = `${GC_MONTHS[mo - 1]} ${d}, ${y}`;
    if (calType === 'ethiopian') {
      const eth = gregorianToEthiopian(new Date(y, mo - 1, d));
      return `${ETHIOPIAN_MONTHS[eth.month - 1]} ${eth.day}, ${eth.year} (${gcStr})`;
    }
    return gcStr;
  })();

  // Confirm button label
  const confirmLabel = (() => {
    if (manualMode) return manualValid ? `Confirm — ${manDay}/${manMonth}/${manYear}` : 'Confirm';
    if (calType === 'gregorian') {
      const d = Math.min(selGCDay, gcMaxDay);
      return `Confirm — ${GC_MONTHS[selGCMonth - 1]} ${d}, ${selGCYear}`;
    } else {
      const d = Math.min(selEthDay, ethMaxDay);
      const gcDate = ethiopianToGregorian({ year: selEthYear, month: selEthMonth, day: d });
      return `Confirm — ${ETHIOPIAN_MONTHS[selEthMonth - 1]} ${d}, ${selEthYear} (GC: ${GC_MONTHS[gcDate.getMonth()]} ${gcDate.getDate()}, ${gcDate.getFullYear()})`;
    }
  })();

  const col = (
    ref: React.RefObject<HTMLDivElement>,
    list: Array<{ label: string; value: number }>,
    selected: number,
    setter: (v: number) => void,
    scrollHandler: () => void,
  ) => (
    <div className="flex-1 flex flex-col items-center">
      <div
        ref={ref}
        onScroll={scrollHandler}
        className="h-full overflow-y-auto scrollbar-hide"
        style={{ scrollSnapType: 'y mandatory' }}
      >
        <div style={{ height: ITEM_H * 2 }} />
        {list.map((item, idx) => (
          <div
            key={item.value}
            style={{ height: ITEM_H, scrollSnapAlign: 'center', cursor: 'pointer' }}
            onClick={() => { setter(item.value); ref.current?.scrollTo({ top: idx * ITEM_H, behavior: 'smooth' }); }}
            className={`flex items-center justify-center text-sm font-medium transition-all select-none ${
              item.value === selected ? 'text-primary font-bold text-base' : 'text-gray-400 dark:text-gray-500'
            }`}
          >
            {item.label}
          </div>
        ))}
        <div style={{ height: ITEM_H * 2 }} />
      </div>
    </div>
  );

  return (
    <div>
      <button
        type="button"
        onClick={() => setOpen(true)}
        disabled={disabled}
        className={`input-field w-full text-left flex items-center justify-between ${
          error ? 'border-red-500' : ''
        } ${disabled ? 'bg-gray-100 dark:bg-gray-700 cursor-not-allowed' : ''}`}
      >
        <span className={displayValue ? 'text-gray-900 dark:text-white text-sm' : 'text-gray-400 text-sm'}>
          {displayValue || 'Select date of birth'}
        </span>
        <CalendarDays className="w-4 h-4 text-gray-400 flex-shrink-0" />
      </button>
      {error && <p className="text-red-500 text-xs mt-1">{error}</p>}

      {open && (
        <>
          <div className="fixed inset-0 z-[99] bg-black/50" onClick={() => setOpen(false)} />
          <div
            className="fixed inset-x-0 bottom-0 z-[100] bg-white dark:bg-gray-900 rounded-t-2xl shadow-2xl"
            style={{ animation: 'dob-slide-up 0.25s cubic-bezier(0.32,0.72,0,1)' }}
          >
            {/* Header */}
            <div className="flex items-center justify-between px-5 py-4 border-b border-gray-100 dark:border-gray-800">
              <div className="flex items-center gap-3">
                <h2 className="text-base font-bold text-gray-900 dark:text-white">Date of Birth</h2>
                {!manualMode && (
                  <button
                    type="button"
                    onClick={() => setCalType(c => c === 'gregorian' ? 'ethiopian' : 'gregorian')}
                    className="flex items-center gap-1 text-xs font-semibold px-2.5 py-1 rounded-lg bg-primary/10 text-primary hover:bg-primary/20 transition-colors"
                  >
                    <Globe className="w-3 h-3" />
                    {calType === 'gregorian' ? 'ET' : 'GC'}
                  </button>
                )}
                <button
                  type="button"
                  onClick={() => setManualMode(!manualMode)}
                  className="text-xs text-gray-500 font-medium hover:underline"
                >
                  {manualMode ? 'Use scroll' : 'Enter manually'}
                </button>
              </div>
              <button type="button" onClick={() => setOpen(false)} className="w-9 h-9 flex items-center justify-center rounded-full hover:bg-gray-100 dark:hover:bg-gray-800">
                <X className="w-5 h-5 text-gray-500" />
              </button>
            </div>

            {/* Calendar type label */}
            {!manualMode && (
              <div className="px-5 pt-2 pb-0">
                <p className="text-xs text-gray-400">
                  {calType === 'gregorian' ? 'Gregorian Calendar' : 'Ethiopian Calendar (ኢትዮጵያ)'}
                </p>
              </div>
            )}

            {manualMode ? (
              <div className="px-5 py-5 space-y-4">
                <div className="grid grid-cols-3 gap-3">
                  <div>
                    <label className="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5">Day</label>
                    <input type="number" min={1} max={31} value={manDay} onChange={(e) => setManDay(e.target.value)} placeholder="DD" className="input-field text-center text-lg font-semibold" />
                  </div>
                  <div>
                    <label className="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5">Month</label>
                    <input type="number" min={1} max={12} value={manMonth} onChange={(e) => setManMonth(e.target.value)} placeholder="MM" className="input-field text-center text-lg font-semibold" />
                  </div>
                  <div>
                    <label className="block text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5">Year</label>
                    <input type="number" min={minGCYear} max={maxGCYear} value={manYear} onChange={(e) => setManYear(e.target.value)} placeholder="YYYY" className="input-field text-center text-lg font-semibold" />
                  </div>
                </div>
                <p className="text-xs text-gray-400">Valid years: {minGCYear} – {maxGCYear}</p>
                {manDay && manMonth && manYear && !manualValid && (
                  <p className="text-red-500 text-xs">{manualRangeMessage}</p>
                )}
              </div>
            ) : (
              <>
                <div className="flex px-5 pt-2 pb-1">
                  {['Day', 'Month', 'Year'].map(l => (
                    <div key={l} className="flex-1 text-center text-xs font-semibold text-gray-400 uppercase tracking-wide">{l}</div>
                  ))}
                </div>
                <div className="relative px-5 pb-2" style={{ height: ITEM_H * 5 }}>
                  <div
                    className="absolute left-5 right-5 pointer-events-none rounded-xl border border-primary/30 bg-primary/5 dark:bg-primary/10"
                    style={{ top: ITEM_H * 2, height: ITEM_H }}
                  />
                  <div className="flex gap-2 h-full">
                    {calType === 'gregorian' ? (
                      <>
                        {col(dayRef,   gcDays.map(d => ({ label: String(d), value: d })), gcSafeDay,   setSelGCDay,   gcDayHandler)}
                        {col(monthRef, gcMonths,                                           selGCMonth,  setSelGCMonth, gcMonthHandler)}
                        {col(yearRef,  gcYears.map(y => ({ label: String(y), value: y })), selGCYear,   setSelGCYear,  gcYearHandler)}
                      </>
                    ) : (
                      <>
                        {col(dayRef,   ethDays.map(d => ({ label: String(d), value: d })), ethSafeDay,  setSelEthDay,   ethDayHandler)}
                        {col(monthRef, ethMonths,                                            selEthMonth, setSelEthMonth, ethMonthHandler)}
                        {col(yearRef,  ethYears.map(y => ({ label: String(y), value: y })), selEthYear,  setSelEthYear,  ethYearHandler)}
                      </>
                    )}
                  </div>
                </div>
              </>
            )}

            <div className="px-5 pb-8 pt-3 flex justify-end">
              <button
                type="button"
                onClick={manualMode ? confirmManual : confirm}
                disabled={manualMode && !manualValid}
                className="px-6 py-2.5 bg-[rgb(20,113,76)] hover:bg-[rgb(16,89,60)] text-white font-bold text-sm rounded-xl transition-all shadow disabled:opacity-40 disabled:cursor-not-allowed"
              >
                {confirmLabel}
              </button>
            </div>
          </div>
          <style>{`@keyframes dob-slide-up{from{transform:translateY(100%);opacity:0}to{transform:translateY(0);opacity:1}}`}</style>
        </>
      )}
    </div>
  );
}

// ─── phone validation ─────────────────────────────────────────────────────────

type PhoneNat = 'ETHIOPIAN' | 'DJIBOUTIAN' | 'OTHER';

const PHONE_PRESETS: Record<PhoneNat, { flag: string; code: string; example: string; hint: string }> = {
  ETHIOPIAN:  { flag: '🇪🇹', code: '+251', example: '912345678',   hint: '+251912345678 or 0912345678' },
  DJIBOUTIAN: { flag: '🇩🇯', code: '+253', example: '77123456',    hint: '+25377123456' },
  OTHER:      { flag: '🌐',   code: '+',    example: '14155552671', hint: 'International: +[country code][number]' },
};

function getPhoneNat(nationality: string): PhoneNat {
  const n = (nationality || '').toUpperCase();
  if (n === 'ETHIOPIAN') return 'ETHIOPIAN';
  if (n === 'DJIBOUTIAN') return 'DJIBOUTIAN';
  return 'OTHER';
}

function validatePhone(phone: string, nationality: string): string | null {
  const normalized = (phone || '').replace(/[\s\-().]/g, '');
  if (!normalized) return 'Phone number is required';
  const nat = getPhoneNat(nationality);
  if (nat === 'ETHIOPIAN') {
    // Only Ethio Telecom (0/+2519...) and Safaricom Ethiopia (0/+2517...) mobile ranges —
    // other prefixes (e.g. landlines, unallocated blocks) are rejected.
    if (/^(\+251[79]\d{8}|0[79]\d{8})$/.test(normalized)) return null;
    return 'Enter a valid Ethio Telecom or Safaricom Ethiopia number (e.g., +251912345678 or 0712345678)';
  }
  if (nat === 'DJIBOUTIAN') {
    if (/^\+253\d{8}$/.test(normalized)) return null;
    return 'Invalid Djiboutian phone number (e.g., +25377123456)';
  }
  if (/^\+[1-9]\d{7,14}$/.test(normalized)) return null;
  return 'Invalid international phone number (e.g., +14155552671)';
}

function stripPhonePrefix(stored: string, nat: PhoneNat): string {
  const code = PHONE_PRESETS[nat].code;
  if (nat !== 'OTHER' && stored.startsWith(code)) return stored.slice(code.length);
  if (nat === 'OTHER' && stored.startsWith('+')) return stored.slice(1);
  return stored;
}

function buildFullNumber(localInput: string, nat: PhoneNat): string {
  const stripped = localInput.replace(/[\s\-().]/g, '');
  if (!stripped) return stripped;
  if (nat === 'ETHIOPIAN') {
    if (stripped.startsWith('+') || stripped.startsWith('0')) return stripped;
    return '+251' + stripped;
  }
  if (nat === 'DJIBOUTIAN') {
    if (stripped.startsWith('+')) return stripped;
    return '+253' + stripped;
  }
  return stripped.startsWith('+') ? stripped : '+' + stripped;
}

function PhoneInput({
  nationality,
  storedValue,
  onInterimChange,
  onNormalized,
  error,
  disabled = false,
}: {
  nationality: string;
  storedValue: string;
  onInterimChange: (full: string) => void;
  onNormalized: (full: string) => void;
  error?: string;
  disabled?: boolean;
}) {
  const nat = getPhoneNat(nationality);
  const preset = PHONE_PRESETS[nat];
  const [localInput, setLocalInput] = useState(() => stripPhonePrefix(storedValue || '', nat));
  const prevStoredRef = useRef(storedValue);

  useEffect(() => {
    if (storedValue !== prevStoredRef.current) {
      prevStoredRef.current = storedValue;
      setLocalInput(stripPhonePrefix(storedValue || '', nat));
    }
  }, [storedValue, nat]);

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const raw = e.target.value;
    setLocalInput(raw);
    onInterimChange(buildFullNumber(raw, nat));
  };

  const handleBlur = () => {
    const full = buildFullNumber(localInput, nat);
    setLocalInput(stripPhonePrefix(full, nat));
    onNormalized(full);
  };

  return (
    <div>
      <div className={`flex rounded-lg overflow-hidden border transition-colors focus-within:ring-1 ${
        error
          ? 'border-red-500 focus-within:ring-red-500'
          : 'border-gray-300 dark:border-gray-600 focus-within:border-primary focus-within:ring-primary'
      }`}>
        <div className="flex items-center gap-1.5 px-3 py-2.5 bg-gray-50 dark:bg-gray-800 border-r border-gray-300 dark:border-gray-600 select-none flex-shrink-0">
          <span className="text-sm leading-none">{preset.flag}</span>
          <span className="text-xs font-semibold text-gray-600 dark:text-gray-300">{preset.code}</span>
        </div>
        <input
          type="tel"
          value={localInput}
          onChange={handleChange}
          onBlur={handleBlur}
          placeholder={preset.example}
          autoComplete="tel"
          readOnly={disabled}
          className={`flex-1 px-3 py-2.5 text-sm text-gray-900 dark:text-white outline-none min-w-0 ${
            disabled ? 'bg-gray-100 dark:bg-gray-700 cursor-not-allowed' : 'bg-white dark:bg-gray-900'
          }`}
        />
      </div>
      {error ? (
        <p className="text-red-500 text-xs mt-1">{error}</p>
      ) : (
        <p className="text-xs text-gray-400 dark:text-gray-500 mt-1">Format: {preset.hint}</p>
      )}
    </div>
  );
}

// ─── age calculation ─────────────────────────────────────────────────────────

function calculateAge(dateOfBirth: string): number | null {
  if (!dateOfBirth) return null;
  const dob = new Date(dateOfBirth);
  if (isNaN(dob.getTime())) return null;
  const today = new Date();
  let age = today.getFullYear() - dob.getFullYear();
  const monthDiff = today.getMonth() - dob.getMonth();
  if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < dob.getDate())) {
    age--;
  }
  return age;
}

// ─── passenger zod schema ──────────────────────────────────────────────────────

const passengerSchema = z.object({
  name: z.string().min(2, 'Full name is required (min 2 characters)'),
  dateOfBirth: z.string().min(1, 'Date of birth is required'),
  gender: z.string().min(1, 'Gender is required'),
  nationality: z.string().min(1, 'Nationality is required'),
  // Adults enter these themselves; children inherit the primary adult's values (see the
  // sync effect in the page component) rather than collecting their own.
  phone: z.string(),
  email: z.string(),
  nationalId: z.string().optional(),
  passportNumber: z.string().optional(),
  passportCountry: z.string().optional(),
  passportIssueDate: z.string().optional(),
  passportExpiryDate: z.string().optional(),
  passportIssuingAuthority: z.string().optional(),
  faydaVerified: z.boolean().optional(),
  faydaSub: z.string().optional(),
  // Set when the corresponding contact value was supplied by Fayda (vs typed by the user) —
  // a Fayda-supplied phone/email is locked; a field Fayda left blank stays editable.
  faydaEmailLocked: z.boolean().optional(),
  faydaPhoneLocked: z.boolean().optional(),
  formExpanded: z.boolean().optional(),
}).superRefine((data, ctx) => {
  if (data.gender !== 'Male' && data.gender !== 'Female') {
    ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Gender is required', path: ['gender'] });
  }
  const isNonEthiopian = data.nationality !== 'ETHIOPIAN' && data.nationality !== 'Ethiopian';
  if (isNonEthiopian) {
    const passportNum = data.passportNumber?.trim() ?? '';
    if (!passportNum) {
      ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Passport number is required', path: ['passportNumber'] });
    } else if (/[^A-Za-z0-9]/.test(passportNum)) {
      ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Passport number must not contain special characters', path: ['passportNumber'] });
    } else if (passportNum.length < 6 || passportNum.length > 12) {
      ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Passport number must be between 6 and 12 characters', path: ['passportNumber'] });
    }
    if (!data.passportCountry || data.passportCountry.trim().length === 0) {
      ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Issuing country is required', path: ['passportCountry'] });
    }
    if (data.passportIssueDate) {
      const issue = new Date(data.passportIssueDate);
      if (!isNaN(issue.getTime()) && issue > new Date()) {
        ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Passport issue date cannot be in the future', path: ['passportIssueDate'] });
      }
    }
    if (data.passportExpiryDate) {
      const expiry = new Date(data.passportExpiryDate);
      if (!isNaN(expiry.getTime()) && expiry <= new Date()) {
        ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Passport expiry date must be in the future', path: ['passportExpiryDate'] });
      }
    }
  }
});

function createFormSchema(adultCount: number) {
  return z.object({
    passengers: z.array(passengerSchema),
    createAccount: z.boolean(),
  }).superRefine((data, ctx) => {
    data.passengers.forEach((p, i) => {
      const isAdult = i < adultCount;

      // Contact fields are only collected from — and validated against — adults.
      // Children's phone/email are inherited from the primary adult, not user-entered.
      if (isAdult) {
        // Email is optional — only validate its format when the user actually provides one.
        if (p.email && p.email.trim().length > 0) {
          const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
          if (!emailRegex.test(p.email)) {
            ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Invalid email format', path: ['passengers', i, 'email'] });
          }
        }
        const phoneError = validatePhone(p.phone, p.nationality);
        if (phoneError) {
          ctx.addIssue({ code: z.ZodIssueCode.custom, message: phoneError, path: ['passengers', i, 'phone'] });
        }
      }

      const age = calculateAge(p.dateOfBirth);
      if (age === null) return;
      if (isAdult && age <= 5) {
        ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Adult passengers must be older than 5 years', path: ['passengers', i, 'dateOfBirth'] });
      } else if (!isAdult && age > 5) {
        ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Child passengers must be 5 years old or younger', path: ['passengers', i, 'dateOfBirth'] });
      }
    });
  });
}

type FormData = z.infer<ReturnType<typeof createFormSchema>>;

function PassengersForm() {
  const router = useRouter();
  const { searchCriteria, passengers: storedPassengers, setPassengers, setCreateAccount, packageId } = useBookingStore();
  const { user, isAuthenticated, updateUser } = useAuthStore();
  const isInitialized = useAuthStore((s) => s.isInitialized);
  const [faydaEnabled, setFaydaEnabled] = useState(true);
  // "Skip for now" (bypasses Fayda verification) is only offered on local dev and the
  // staging/test domain — never on an unrecognized host, which would include production.
  // Starts false (matches SSR, where window isn't available) and is only ever flipped to
  // true client-side after mount, so there's no server/client hydration mismatch.
  const [allowSkipFaydaVerification, setAllowSkipFaydaVerification] = useState(false);
  useEffect(() => {
    const hostname = window.location.hostname;
    setAllowSkipFaydaVerification(
      hostname === "localhost" ||
        hostname === "127.0.0.1" ||
        hostname === "edrpassenger.triaplc.com",
    );
  }, []);
  const [verificationStatus, setVerificationStatus] = useState<Record<number, 'pending' | 'success' | 'error'>>({});
  const [faydaErrors, setFaydaErrors] = useState<Record<number, string>>({});
  // The passenger currently mid-verification (popup open / awaiting callback). Only one
  // passenger can verify at a time so a stray callback can never be misapplied to the
  // wrong passenger's form.
  const [verifyingIndex, setVerifyingIndex] = useState<number | null>(null);
  const [saving, setSaving] = useState(false);
  const [submitError, setSubmitError] = useState<string | null>(null);
  const [formInitialized, setFormInitialized] = useState(false);
  const [faydaParams, setFaydaParams] = useState<{ code: string; state: string } | null>(null);
  const [faydaCompleting, setFaydaCompleting] = useState(false);


  const totalPassengers = (searchCriteria?.adultCount || 1) + (searchCriteria?.childCount || 0);
  const adultCount = searchCriteria?.adultCount || 1;

  const { register, control, handleSubmit, setValue, watch, formState: { errors } } = useForm<FormData>({
    resolver: zodResolver(createFormSchema(adultCount) as any),
    mode: 'onChange',
    defaultValues: {
      passengers: Array.from({ length: totalPassengers }, (_, i) => {
        // Returning from a Fayda redirect: restore the exact in-progress form we snapshotted
        // before leaving, so no passenger's typed data is lost. The completion effect then
        // applies the verified attributes on top for the passenger who initiated it.
        const snap = getFaydaFormSnapshot()?.passengers?.[i];
        if (snap) return snap;
        const stored = storedPassengers[i];
        if (stored?.name) {
          return {
            name: stored.name,
            dateOfBirth: stored.dateOfBirth || '',
            gender: (stored.gender as any) || undefined,
            nationality: stored.nationality || searchCriteria?.nationality || 'ETHIOPIAN',
            phone: (i >= adultCount ? storedPassengers[0]?.phone : stored.phone) || '',
            email: (i >= adultCount ? storedPassengers[0]?.email : stored.email) || '',
            nationalId: stored.nationalId || '',
            passportNumber: stored.passportNumber || '',
            passportCountry: stored.passportCountry || (searchCriteria?.nationality === 'DJIBOUTIAN' ? 'Djibouti' : ''),
            passportIssueDate: stored.passportIssueDate || '',
            passportExpiryDate: stored.passportExpiryDate || '',
            passportIssuingAuthority: stored.passportIssuingAuthority || '',
            faydaVerified: stored.faydaVerified || false,
            formExpanded: true,
          };
        }
        return {
          name: '',
          dateOfBirth: '',
          gender: undefined,
          nationality: searchCriteria?.nationality || 'ETHIOPIAN',
          // Children start out mirroring whatever the primary adult already has on file;
          // the sync effect below keeps this current as the primary adult's info changes.
          phone: (i >= adultCount ? storedPassengers[0]?.phone : '') || '',
          email: (i >= adultCount ? storedPassengers[0]?.email : '') || '',
          nationalId: '',
          passportNumber: '',
          passportCountry: searchCriteria?.nationality === 'DJIBOUTIAN' ? 'Djibouti' : '',
          passportIssueDate: '',
          passportExpiryDate: '',
          passportIssuingAuthority: '',
          faydaVerified: false,
          formExpanded: i >= adultCount,
        };
      }),
      createAccount: getFaydaFormSnapshot()?.createAccount ?? false,
    },
  });

  const { fields } = useFieldArray({ control, name: 'passengers' });
  const passengers = watch('passengers');

  // Children don't collect their own contact info — keep their phone/email mirrored to
  // whatever the primary adult (index 0) currently has, so it's always in sync.
  const primaryPhone = passengers[0]?.phone;
  const primaryEmail = passengers[0]?.email;
  useEffect(() => {
    for (let i = adultCount; i < passengers.length; i++) {
      if (passengers[i]?.phone !== (primaryPhone || '')) {
        setValue(`passengers.${i}.phone`, primaryPhone || '', { shouldValidate: true });
      }
      if (passengers[i]?.email !== (primaryEmail || '')) {
        setValue(`passengers.${i}.email`, primaryEmail || '', { shouldValidate: true });
      }
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [primaryPhone, primaryEmail, adultCount, passengers.length]);

  useEffect(() => {
    const checkFaydaStatus = async () => {
      try {
        const response: any = await apiClient.get('/config/fayda-status');
        setFaydaEnabled(response?.enabled ?? true);
      } catch {
        setFaydaEnabled(true);
      }
    };
    checkFaydaStatus();
  }, []);

  // Read Fayda callback params from the URL on mount
  useEffect(() => {
    if (typeof window === 'undefined') return;
    const params = new URLSearchParams(window.location.search);
    const code = params.get('code');
    const state = params.get('state');
    if (code && state) {
      setFaydaParams({ code, state });
      const pendingIndex = getPendingFaydaIndex();
      if (pendingIndex !== null) setVerifyingIndex(pendingIndex);
    }
  }, []);

  // The redirect snapshot is consumed once, during the form's defaultValues at mount. Clear it
  // afterwards so a later visit to this page doesn't restore stale data.
  useEffect(() => {
    clearFaydaFormSnapshot();
  }, []);

  // Show the green "verified" banner for any passenger restored from a snapshot as already
  // Fayda-verified (verificationStatus is React state and doesn't survive the redirect).
  useEffect(() => {
    if (!formInitialized) return;
    setVerificationStatus((prev) => {
      const next = { ...prev };
      passengers.forEach((p, i) => {
        if ((p as any)?.faydaVerified && !next[i]) next[i] = 'success';
      });
      return next;
    });
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [formInitialized]);

  // Complete Fayda verification once the form is ready and callback params are present.
  // This effect runs whenever this route reloads with ?code&state — which happens either
  // inside the verification popup, or, if the browser refused to open a popup, as a full
  // navigation of this same tab. Either way, the index of the passenger who started the
  // verification was stashed in sessionStorage before redirecting, so it survives the reload.
  useEffect(() => {
    if (!faydaParams || !formInitialized) return;

    const complete = async () => {
      setFaydaCompleting(true);
      const targetIndex = getPendingFaydaIndex() ?? 0;
      try {
        const response: any = await apiClient.get(
          `/fayda/verification/complete?code=${encodeURIComponent(faydaParams.code)}&state=${encodeURIComponent(faydaParams.state)}`
        );

        // apiClient already unwraps the { success, data } envelope, so `response` is the
        // verification result itself.
        const d = response;
        if (d?.verified) {
          const faydaSub: string | undefined = d.sub || d.faydaSub || d.fin;

          // A single Fayda identity can't be reused across two different passengers.
          const usedByOther = faydaSub && passengers.some(
            (p, i) => i !== targetIndex && (p as any).faydaSub === faydaSub,
          );

          if (usedByOther) {
            setFaydaErrors((prev) => ({ ...prev, [targetIndex]: 'This Fayda identity is already linked to another passenger on this booking.' }));
            setVerificationStatus((prev) => ({ ...prev, [targetIndex]: 'error' }));
          } else {
            // Convert "1980/12/01" → "1980-12-01"
            const dob = d.birthdate ? (d.birthdate as string).replace(/\//g, '-') : '';

            setValue(`passengers.${targetIndex}.name`, d.fullName || '', { shouldValidate: true });
            if (dob) setValue(`passengers.${targetIndex}.dateOfBirth`, dob, { shouldValidate: true });
            const normalizedGender = normalizeFaydaGender(d.gender);
            if (normalizedGender) setValue(`passengers.${targetIndex}.gender`, normalizedGender, { shouldValidate: true });
            if (faydaSub) setValue(`passengers.${targetIndex}.faydaSub`, faydaSub);
            // Only fill in this passenger's own contact fields if they haven't entered them yet.
            if (d.email && !watch(`passengers.${targetIndex}.email`)) {
              setValue(`passengers.${targetIndex}.email`, d.email, { shouldValidate: true });
              setValue(`passengers.${targetIndex}.faydaEmailLocked`, true);
            }
            if (d.phoneNumber && !watch(`passengers.${targetIndex}.phone`)) {
              setValue(`passengers.${targetIndex}.phone`, d.phoneNumber, { shouldValidate: true });
              setValue(`passengers.${targetIndex}.faydaPhoneLocked`, true);
            }
            setValue(`passengers.${targetIndex}.faydaVerified`, true);
            setValue(`passengers.${targetIndex}.formExpanded`, true);
            setVerificationStatus((prev) => ({ ...prev, [targetIndex]: 'success' }));
            setFaydaErrors((prev) => { const next = { ...prev }; delete next[targetIndex]; return next; });

            if (targetIndex === 0 && isAuthenticated) {
              updateUser({ fullName: d.fullName, faydaVerified: true });
            }
          }
        } else {
          setVerificationStatus((prev) => ({ ...prev, [targetIndex]: 'error' }));
          setFaydaErrors((prev) => ({ ...prev, [targetIndex]: 'Fayda verification could not be completed. Please try again or enter details manually.' }));
        }

        // Remove code/state from the URL so a refresh doesn't re-trigger
        router.replace('/booking/passengers');
      } catch (error) {
        setVerificationStatus((prev) => ({ ...prev, [targetIndex]: 'error' }));
        setFaydaErrors((prev) => ({ ...prev, [targetIndex]: 'Fayda verification failed. Please try again or enter details manually.' }));
      } finally {
        setFaydaCompleting(false);
        setFaydaParams(null);
        setVerifyingIndex(null);
        clearPendingFaydaIndex();
      }
    };

    complete();
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [faydaParams, formInitialized]);

  useEffect(() => {
    if (isAuthenticated && user?.faydaVerified) {
      setVerificationStatus({ 0: 'success' });
    }
  }, [isAuthenticated, user?.faydaVerified]);

  useEffect(() => {
    const populateForm = async () => {
      if (!isInitialized) return;
      // Returning from a Fayda redirect (?code&state): the snapshot restore + completion effect
      // own the form here — don't overwrite passenger 0 with the profile fetch.
      if (typeof window !== 'undefined') {
        const params = new URLSearchParams(window.location.search);
        if (params.get('code') && params.get('state')) {
          setFormInitialized(true);
          return;
        }
      }
      if (!isAuthenticated || !user?.id || !searchCriteria) {
        setFormInitialized(true);
        return;
      }

      try {
        // Fetch passenger profile from backend. This may be null (e.g. no Passenger row linked
        // yet) — in that case fall back to the `user` object, which /auth/profile hydrates from
        // the same IAM record (name, gender, DOB, nationality, Fayda status). Merging the two
        // means an already-verified passenger's form still prefills from whichever source has
        // the data, rather than being left blank.
        const passengerData: any = (await apiClient.get(`/passengers/me`)) || {};

        const pick = (a: any, b: any) => (a !== undefined && a !== null && a !== '' ? a : b);

        // Nationality for THIS booking is the one chosen at search — the passengers-page
        // nationality field is read-only. It, not the account's stored nationality, decides
        // whether the Fayda gate applies, so a logged-in user who picked "Other"/"Djiboutian"
        // isn't wrongly forced into Fayda (Fayda is only for Ethiopian nationals).
        const nationality = searchCriteria?.nationality || pick(passengerData.nationality, user.nationality) || 'ETHIOPIAN';
        const isEthiopian = String(nationality).toUpperCase() === 'ETHIOPIAN';
        const isVerified = Boolean(pick(passengerData.faydaVerified, user.faydaVerified));

        // A logged-in but NOT Fayda-verified Ethiopian must pass the Fayda gate exactly like a
        // guest. Prefilling their identity and expanding the form would let them submit the
        // booking without ever verifying — only a verified passenger may pass. When Fayda is
        // globally disabled there is no gate, so the restriction doesn't apply.
        const mustVerifyFayda = isEthiopian && !isVerified && faydaEnabled;

        // Nationality + contact aren't identity-verifying, so they're safe to prefill either way.
        setValue('passengers.0.nationality', nationality);
        const phoneVal = pick(passengerData.phone, user.phone);
        if (phoneVal) setValue('passengers.0.phone', phoneVal);
        const emailVal = pick(passengerData.email, user.email);
        if (emailVal) setValue('passengers.0.email', emailVal);

        if (mustVerifyFayda) {
          // Force the Fayda gate: leave name/DOB/gender empty and keep the form collapsed so the
          // "Verify with Fayda" screen is shown instead of an editable, pre-filled form.
          setValue('passengers.0.faydaVerified', false);
          setValue('passengers.0.formExpanded', false);
          setFormInitialized(true);
          return;
        }

        // Verified Ethiopian, or a non-Ethiopian (passport flow): prefill everything and expand.
        setValue('passengers.0.name', pick(passengerData.fullName, user.fullName) || '');
        setValue('passengers.0.dateOfBirth', pick(passengerData.dateOfBirth, user.dateOfBirth) || '');
        const genderVal = pick(passengerData.gender, user.gender);
        if (genderVal) setValue('passengers.0.gender', genderVal as any);
        const passportNumberVal = pick(passengerData.passportNumber, user.passportNumber);
        if (passportNumberVal) setValue('passengers.0.passportNumber', passportNumberVal);
        setValue('passengers.0.passportCountry', pick(passengerData.passportCountry, user.passportCountry) || (searchCriteria?.nationality === 'DJIBOUTIAN' ? 'Djibouti' : ''));
        const passportIssueVal = pick(passengerData.passportIssueDate, user.passportIssueDate);
        if (passportIssueVal) setValue('passengers.0.passportIssueDate', passportIssueVal);
        const passportExpiryVal = pick(passengerData.passportExpiryDate, user.passportExpiryDate);
        if (passportExpiryVal) setValue('passengers.0.passportExpiryDate', passportExpiryVal);
        const passportAuthVal = pick(passengerData.passportIssuingAuthority, user.passportIssuingAuthority);
        if (passportAuthVal) setValue('passengers.0.passportIssuingAuthority', passportAuthVal);
        setValue('passengers.0.faydaVerified', isVerified);
        setValue('passengers.0.formExpanded', true);

        setFormInitialized(true);
      } catch (error) {
        setFormInitialized(true);
      }
    };

    populateForm();
  }, [isInitialized, isAuthenticated, user, searchCriteria, setValue]);

  const openFaydaVerification = async (index: number) => {
    if (typeof window === 'undefined') return;
    // Only one passenger can verify at a time so the returning ?code&state is unambiguously
    // applied to the passenger who started it.
    if (verifyingIndex !== null) return;

    setVerifyingIndex(index);
    setVerificationStatus((prev) => ({ ...prev, [index]: 'pending' }));
    setFaydaErrors((prev) => { const next = { ...prev }; delete next[index]; return next; });
    // Stash the verifying passenger index and a full snapshot of the in-progress form. Both live
    // in sessionStorage, which survives the same-tab round trip out to Fayda and back — so no
    // typed data is lost and the callback is applied to the right passenger. Identical flow on
    // desktop and mobile: a full-page redirect, no popup and no window.opener dependency.
    setPendingFaydaIndex(index);
    saveFaydaFormSnapshot({ passengers: watch('passengers'), createAccount: watch('createAccount') });

    try {
      const response: any = await apiClient.post('/fayda/verification/start', {
        purpose: 'VERIFY',
        platform: 'WEB',
        saveToAccount: index === 0 && isAuthenticated,
      });
      // Redirect the whole tab to eSignet. Fayda returns the browser to this same route
      // (FAYDA_WEB_REDIRECT_URI = <portal>/booking/passengers) with ?code&state, which the
      // completion effect above picks up on mount.
      window.location.href = response.authorizationUrl;
    } catch (error) {
      setVerificationStatus((prev) => ({ ...prev, [index]: 'error' }));
      setFaydaErrors((prev) => ({ ...prev, [index]: 'Failed to start verification. Please try again.' }));
      setVerifyingIndex(null);
      clearPendingFaydaIndex();
      clearFaydaFormSnapshot();
    }
  };

  const toggleForm = (index: number) => {
    setValue(`passengers.${index}.formExpanded`, !passengers[index].formExpanded);
  };

  const onInvalid = () => {
    // Sections still behind the Fayda verify screen stay collapsed here — they only expand
    // when the user explicitly clicks "Enter details manually" (shown only when Fayda is
    // unavailable). Their name/DOB/gender fields are still empty at this point, which would
    // otherwise surface as a generic "fix the highlighted errors" message that doesn't point
    // at the actual cause — tell the user to verify with Fayda instead.
    const needsFaydaVerification = passengers.some((p, i) => {
      const isEthiopian = p?.nationality === 'ETHIOPIAN';
      const isChildPassenger = i >= adultCount;
      const isLoggedInAndVerified = i === 0 && isAuthenticated && user?.faydaVerified;
      return isEthiopian && faydaEnabled && !p?.formExpanded && !isLoggedInAndVerified && !isChildPassenger;
    });
    setSubmitError(
      needsFaydaVerification
        ? 'Please verify your identity with Fayda before continuing — tap "Verify with Fayda" above to proceed.'
        : 'Please fix the highlighted errors before continuing.'
    );
  };

  const onSubmit = async (data: FormData) => {
    setSaving(true);
    setSubmitError(null);
    try {
      let passengerId = '';
      
      // For authenticated users, fetch the passenger profile to get the passengerId
      if (isAuthenticated && user?.id) {
        try {
          const passengerProfile: any = await apiClient.get('/passengers/me');
          passengerId = passengerProfile?.id || '';
        } catch (error) {
        }
      }

      const passengerDetails = data.passengers.map((p, i) => ({
        name: p.name,
        dateOfBirth: p.dateOfBirth,
        gender: p.gender,
        nationality: p.nationality,
        nationalId: p.nationalId,
        passportNumber: p.passportNumber,
        passportCountry: p.passportCountry,
        passportIssueDate: p.passportIssueDate,
        passportExpiryDate: p.passportExpiryDate,
        passportIssuingAuthority: p.passportIssuingAuthority,
        phone: p.phone,
        email: p.email,
        isPrimaryPassenger: i === 0,
        passengerId: i === 0 && passengerId ? passengerId : undefined,
      }))

      const deviceId = typeof window !== 'undefined'
        ? (localStorage.getItem('deviceId') || crypto.randomUUID())
        : crypto.randomUUID();

      await apiClient.post('/passengers/save-details', {
        passengers: passengerDetails,
        userId: user?.id,
        deviceId,
      });

      setPassengers(passengerDetails);
      setCreateAccount(data.createAccount);
      
      // Save passengerId to booking store for later use
      if (isAuthenticated && passengerId) {
        const { setPassengerId } = useBookingStore.getState();
        setPassengerId(passengerId);
      }
      
      router.push('/booking/seats');
    } catch (error) {
      alert('Failed to save passenger details. Please try again.');
    } finally {
      setSaving(false);
    }
  };

  // searchCriteria is guaranteed present here — the PassengersPage gate below only mounts this
  // component after the persisted booking store has rehydrated and confirmed a booking exists.
  if (!searchCriteria) return null;

  if (!formInitialized || faydaCompleting) {
    return (
      <div className="booking-page">
        <div className="container mx-auto px-4">
          <div className="max-w-lg mx-auto text-center">
            <Loader2 className="w-8 h-8 animate-spin mx-auto text-blue-600" />
            <p className="text-gray-600 dark:text-gray-400 mt-4">
              {faydaCompleting
                ? `Completing Fayda verification for Passenger ${(verifyingIndex ?? 0) + 1}...`
                : 'Loading passenger details...'}
            </p>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-gray-50 dark:bg-gray-900 py-12">
      <div className="container mx-auto px-4">
        <div className="max-w-6xl mx-auto">
          <h1 className="section-title">Passenger details</h1>

          <form onSubmit={handleSubmit(onSubmit, onInvalid)} className="space-y-6">
            {fields.map((field, index) => {
              const isEthiopian = passengers[index]?.nationality === 'ETHIOPIAN';
              const isFormExpanded = passengers[index]?.formExpanded;
              const status = verificationStatus[index];
              const isPrimaryPassenger = index === 0;
              const isChildPassenger = index >= adultCount;
              const isLoggedInAndVerified = isPrimaryPassenger && isAuthenticated && user?.faydaVerified;
              const isLoggedInNotVerified = isPrimaryPassenger && isAuthenticated && !user?.faydaVerified;
              const showVerifyButton = isEthiopian && faydaEnabled && !isFormExpanded && !isLoggedInAndVerified && !isChildPassenger;
              const showManualEntryLink = isEthiopian && !faydaEnabled && !isFormExpanded && !isChildPassenger;
              const isVerifyingThis = verifyingIndex === index;
              const isVerifyingOther = verifyingIndex !== null && verifyingIndex !== index;
              const faydaError = faydaErrors[index];
              // Identity fields sourced from a completed Fayda verification are locked — the
              // passenger can't edit the verified name / date of birth / gender.
              const isFaydaLocked = !!passengers[index]?.faydaVerified;
              // ...but lock each field only when it actually carries a value. A verified profile
              // can be missing a field (e.g. a Fayda *login* record whose metadata has no date of
              // birth) — locking an empty, required input would strand the user with no way to
              // fill it or submit. A missing field stays editable so they can complete it.
              const isNameLocked = isFaydaLocked && !!passengers[index]?.name;
              const isDobLocked = isFaydaLocked && !!passengers[index]?.dateOfBirth;
              const isGenderLocked = isFaydaLocked && !!passengers[index]?.gender;
              // Contact fields lock only when Fayda actually supplied them; a value Fayda left
              // blank stays editable so the passenger can add their own phone/email.
              // A logged-in, already-verified primary passenger's contact details also come from
              // their verified profile — lock those too, alongside name/DOB/gender. Only lock a
              // field that actually has a value, so an incomplete profile can't strand the user
              // on an unfillable required field.
              const isPhoneLocked = !!passengers[index]?.faydaPhoneLocked || (isLoggedInAndVerified && !!passengers[index]?.phone);
              const isEmailLocked = !!passengers[index]?.faydaEmailLocked || (isLoggedInAndVerified && !!passengers[index]?.email);

              return (
                <div key={field.id} className="card">
                  <h3 className="text-lg font-semibold mb-4 text-gray-900 dark:text-gray-100">
                    Passenger {index + 1} {index === 0 && '(Primary)'}
                    {isChildPassenger ? ' - Child' : ' - Adult'}
                    <span className="ml-2 text-sm font-normal text-gray-600 dark:text-gray-400">
                      ({isEthiopian ? 'Ethiopian' : searchCriteria.nationality === 'DJIBOUTIAN' ? 'Djiboutian' : 'Other'})
                    </span>
                  </h3>

                  {showVerifyButton ? (
                    <div className="text-center py-8">
                      {isLoggedInNotVerified && (
                        <div className="mb-4 p-3 bg-blue-50 dark:bg-blue-900/30 border border-blue-200 dark:border-blue-800 rounded-lg">
                          <p className="text-sm text-blue-700 dark:text-blue-300">
                            Please verify your identity with Fayda to complete your profile
                          </p>
                        </div>
                      )}
                      {faydaError && (
                        <div className="mb-4 p-3 bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-800 rounded-lg flex items-center gap-2">
                          <AlertCircle className="w-4 h-4 text-red-600 dark:text-red-400 flex-shrink-0" />
                          <p className="text-sm text-red-700 dark:text-red-300">{faydaError}</p>
                        </div>
                      )}
                      <button
                        type="button"
                        onClick={() => openFaydaVerification(index)}
                        disabled={isVerifyingThis || isVerifyingOther}
                        className="btn-primary flex items-center justify-center gap-2 mx-auto disabled:opacity-50 disabled:cursor-not-allowed"
                      >
                        {isVerifyingThis ? (
                          <>
                            <Loader2 className="w-5 h-5 animate-spin" />
                            Waiting for verification...
                          </>
                        ) : (
                          <>
                            <ExternalLink className="w-5 h-5" />
                            Verify with Fayda
                          </>
                        )}
                      </button>
                      {isVerifyingOther && (
                        <p className="text-xs text-gray-400 dark:text-gray-500 mt-2">
                          Finish verifying Passenger {(verifyingIndex ?? 0) + 1} first
                        </p>
                      )}
                      {allowSkipFaydaVerification && (
                        <button
                          type="button"
                          onClick={() => toggleForm(index)}
                          disabled={isVerifyingThis}
                          className="text-sm text-gray-500 dark:text-gray-400 hover:underline mt-3 block mx-auto disabled:opacity-50 disabled:cursor-not-allowed"
                        >
                          Skip for now
                        </button>
                      )}
                    </div>
                  ) : showManualEntryLink ? (
                    <div className="text-center py-8">
                      <p className="text-sm text-gray-600 dark:text-gray-400 mb-4">
                        Fayda verification is currently unavailable
                      </p>
                      <button
                        type="button"
                        onClick={() => toggleForm(index)}
                        className="btn-primary"
                      >
                        Enter details manually
                      </button>
                    </div>
                  ) : (
                    <div className="space-y-4">
                      {isEthiopian ? (
                        <>
                          {status === 'success' && (
                            <div className="p-3 bg-green-50 dark:bg-green-900/30 border border-green-200 dark:border-green-800 rounded-lg mb-4">
                              <p className="text-green-700 dark:text-green-300 text-sm flex items-center gap-2">
                                <CheckCircle className="w-4 h-4" /> Verified with Fayda — verified details are locked below
                              </p>
                            </div>
                          )}
                          {status === 'error' && faydaError && (
                            <div className="p-3 bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-800 rounded-lg mb-4 flex items-center gap-2">
                              <AlertCircle className="w-4 h-4 text-red-600 dark:text-red-400 flex-shrink-0" />
                              <p className="text-red-700 dark:text-red-300 text-sm">{faydaError}</p>
                            </div>
                          )}

                          <div className="grid md:grid-cols-2 gap-4">
                            {/* Full Name */}
                            <div>
                              <label className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300">Full Name *</label>
                              <input
                                {...register(`passengers.${index}.name`)}
                                readOnly={isNameLocked}
                                className={`input-field ${isNameLocked ? 'bg-gray-100 dark:bg-gray-700 cursor-not-allowed' : ''} ${errors.passengers?.[index]?.name ? 'border-red-500' : ''}`}
                                placeholder="Full name as per ID"
                              />
                              {errors.passengers?.[index]?.name && (
                                <p className="text-red-500 text-xs mt-1">{errors.passengers[index]?.name?.message}</p>
                              )}
                            </div>

                            {/* Date of Birth */}
                            <div>
                              <label className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300">Date of Birth *</label>
                              <DobPickerModal
                                value={passengers[index]?.dateOfBirth || ''}
                                onChange={(iso) => setValue(`passengers.${index}.dateOfBirth`, iso, { shouldValidate: true })}
                                error={errors.passengers?.[index]?.dateOfBirth?.message}
                                passengerType={isChildPassenger ? 'CHILD' : 'ADULT'}
                                disabled={isDobLocked}
                              />
                            </div>

                            {/* Gender */}
                            <div>
                              <label className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300">Gender *</label>
                              {isGenderLocked ? (
                                <input
                                  value={passengers[index]?.gender || ''}
                                  readOnly
                                  className="input-field bg-gray-100 dark:bg-gray-700 cursor-not-allowed"
                                />
                              ) : (
                                <select
                                  {...register(`passengers.${index}.gender`)}
                                  className={`input-field ${errors.passengers?.[index]?.gender ? 'border-red-500' : ''}`}
                                >
                                  <option value="">Select gender</option>
                                  <option value="Male">Male</option>
                                  <option value="Female">Female</option>
                                </select>
                              )}
                              {errors.passengers?.[index]?.gender && (
                                <p className="text-red-500 text-xs mt-1">{errors.passengers[index]?.gender?.message}</p>
                              )}
                            </div>

                            {/* Nationality (read-only) */}
                            <div>
                              <label className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300">Nationality</label>
                              <input
                                {...register(`passengers.${index}.nationality`)}
                                className="input-field bg-gray-100 dark:bg-gray-700 cursor-not-allowed"
                                readOnly
                                disabled
                              />
                            </div>

                            {isChildPassenger ? (
                              <div className="md:col-span-2 p-3 bg-gray-50 dark:bg-gray-800 rounded-lg text-sm text-gray-600 dark:text-gray-400">
                                Contact details (phone &amp; email) are shared with the primary passenger and don&apos;t need to be entered separately.
                              </div>
                            ) : (
                              <>
                                {/* Phone */}
                                <div>
                                  <label className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300">Phone Number *</label>
                                  <PhoneInput
                                    nationality={passengers[index]?.nationality || 'ETHIOPIAN'}
                                    storedValue={passengers[index]?.phone || ''}
                                    onInterimChange={(v) => setValue(`passengers.${index}.phone`, v)}
                                    onNormalized={(v) => setValue(`passengers.${index}.phone`, v, { shouldValidate: true })}
                                    error={errors.passengers?.[index]?.phone?.message}
                                    disabled={isPhoneLocked}
                                  />
                                </div>

                                {/* Email */}
                                <div>
                                  <label className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300">Email (optional)</label>
                                  <input
                                    type="email"
                                    {...register(`passengers.${index}.email`)}
                                    readOnly={isEmailLocked}
                                    className={`input-field ${isEmailLocked ? 'bg-gray-100 dark:bg-gray-700 cursor-not-allowed' : ''} ${errors.passengers?.[index]?.email ? 'border-red-500' : ''}`}
                                    placeholder="email@example.com"
                                  />
                                  {errors.passengers?.[index]?.email && (
                                    <p className="text-red-500 text-xs mt-1">{errors.passengers[index]?.email?.message}</p>
                                  )}
                                </div>
                              </>
                            )}
                          </div>
                        </>
                      ) : (
                        <>
                          <div className="grid md:grid-cols-2 gap-4">
                            {/* Full Name */}
                            <div>
                              <label className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300">Full Name *</label>
                              <input
                                {...register(`passengers.${index}.name`)}
                                className={`input-field ${errors.passengers?.[index]?.name ? 'border-red-500' : ''}`}
                                placeholder="Full name as per passport"
                              />
                              {errors.passengers?.[index]?.name && (
                                <p className="text-red-500 text-xs mt-1">{errors.passengers[index]?.name?.message}</p>
                              )}
                            </div>

                            {/* Date of Birth */}
                            <div>
                              <label className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300">Date of Birth *</label>
                              <DobPickerModal
                                value={passengers[index]?.dateOfBirth || ''}
                                onChange={(iso) => setValue(`passengers.${index}.dateOfBirth`, iso, { shouldValidate: true })}
                                error={errors.passengers?.[index]?.dateOfBirth?.message}
                                passengerType={isChildPassenger ? 'CHILD' : 'ADULT'}
                                disabled={isDobLocked}
                              />
                            </div>

                            {/* Gender */}
                            <div>
                              <label className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300">Gender *</label>
                              {isGenderLocked ? (
                                <input
                                  value={passengers[index]?.gender || ''}
                                  readOnly
                                  className="input-field bg-gray-100 dark:bg-gray-700 cursor-not-allowed"
                                />
                              ) : (
                                <select
                                  {...register(`passengers.${index}.gender`)}
                                  className={`input-field ${errors.passengers?.[index]?.gender ? 'border-red-500' : ''}`}
                                >
                                  <option value="">Select gender</option>
                                  <option value="Male">Male</option>
                                  <option value="Female">Female</option>
                                </select>
                              )}
                              {errors.passengers?.[index]?.gender && (
                                <p className="text-red-500 text-xs mt-1">{errors.passengers[index]?.gender?.message}</p>
                              )}
                            </div>

                            {/* Nationality (read-only) */}
                            <div>
                              <label className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300">Nationality</label>
                              <input
                                {...register(`passengers.${index}.nationality`)}
                                className="input-field bg-gray-100 dark:bg-gray-700 cursor-not-allowed"
                                readOnly
                                disabled
                              />
                            </div>

                            {isChildPassenger ? (
                              <div className="md:col-span-2 p-3 bg-gray-50 dark:bg-gray-800 rounded-lg text-sm text-gray-600 dark:text-gray-400">
                                Contact details (phone &amp; email) are shared with the primary passenger and don&apos;t need to be entered separately.
                              </div>
                            ) : (
                              <>
                                {/* Phone */}
                                <div>
                                  <label className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300">Phone Number *</label>
                                  <PhoneInput
                                    nationality={passengers[index]?.nationality || 'OTHER'}
                                    storedValue={passengers[index]?.phone || ''}
                                    onInterimChange={(v) => setValue(`passengers.${index}.phone`, v)}
                                    onNormalized={(v) => setValue(`passengers.${index}.phone`, v, { shouldValidate: true })}
                                    error={errors.passengers?.[index]?.phone?.message}
                                    disabled={isPhoneLocked}
                                  />
                                </div>

                                {/* Email */}
                                <div>
                                  <label className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300">Email (optional)</label>
                                  <input
                                    type="email"
                                    {...register(`passengers.${index}.email`)}
                                    readOnly={isEmailLocked}
                                    className={`input-field ${isEmailLocked ? 'bg-gray-100 dark:bg-gray-700 cursor-not-allowed' : ''} ${errors.passengers?.[index]?.email ? 'border-red-500' : ''}`}
                                    placeholder="email@example.com"
                                  />
                                  {errors.passengers?.[index]?.email && (
                                    <p className="text-red-500 text-xs mt-1">{errors.passengers[index]?.email?.message}</p>
                                  )}
                                </div>
                              </>
                            )}
                          </div>

                          {/* Passport fields */}
                          <div className="border-t dark:border-gray-700 pt-4 mt-4">
                            <h4 className="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-3">Passport Details</h4>
                            <div className="grid md:grid-cols-2 gap-4">
                              <div>
                                <label className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300">Passport Number *</label>
                                <input
                                  {...register(`passengers.${index}.passportNumber`)}
                                  className={`input-field ${errors.passengers?.[index]?.passportNumber ? 'border-red-500' : ''}`}
                                  placeholder="P1234567"
                                />
                                {errors.passengers?.[index]?.passportNumber && (
                                  <p className="text-red-500 text-xs mt-1">{errors.passengers[index]?.passportNumber?.message}</p>
                                )}
                              </div>

                              <div>
                                <label className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300">Issuing Country *</label>
                                <select
                                  {...register(`passengers.${index}.passportCountry`)}
                                  className={`input-field ${errors.passengers?.[index]?.passportCountry ? 'border-red-500' : ''}`}
                                >
                                  <option value="">Select country</option>
                                  {COUNTRIES.map((c) => (
                                    <option key={c} value={c}>{c}</option>
                                  ))}
                                </select>
                                {errors.passengers?.[index]?.passportCountry && (
                                  <p className="text-red-500 text-xs mt-1">{errors.passengers[index]?.passportCountry?.message}</p>
                                )}
                              </div>

                              <div>
                                <label className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300">Issue Date</label>
                                <input
                                  type="date"
                                  {...register(`passengers.${index}.passportIssueDate`)}
                                  className={`input-field ${errors.passengers?.[index]?.passportIssueDate ? 'border-red-500' : ''}`}
                                  max={new Date().toISOString().split('T')[0]}
                                />
                                {errors.passengers?.[index]?.passportIssueDate && (
                                  <p className="text-red-500 text-xs mt-1">{errors.passengers[index]?.passportIssueDate?.message}</p>
                                )}
                              </div>

                              <div>
                                <label className="block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300">Expiry Date</label>
                                <input
                                  type="date"
                                  {...register(`passengers.${index}.passportExpiryDate`)}
                                  className={`input-field ${errors.passengers?.[index]?.passportExpiryDate ? 'border-red-500' : ''}`}
                                  min={new Date().toISOString().split('T')[0]}
                                />
                                {errors.passengers?.[index]?.passportExpiryDate && (
                                  <p className="text-red-500 text-xs mt-1">{errors.passengers[index]?.passportExpiryDate?.message}</p>
                                )}
                              </div>
                            </div>
                          </div>
                        </>
                      )}
                    </div>
                  )}
                </div>
              );
            })}

            {!isAuthenticated && (
              <div className="card">
                <label className="flex items-center gap-2 cursor-pointer">
                  <input type="checkbox" {...register('createAccount')} className="w-4 h-4" />
                  <span className="text-sm text-gray-700 dark:text-gray-300">Create an account to save my profile for future bookings</span>
                </label>
              </div>
            )}

            {submitError && (
              <div className="p-3 bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-800 rounded-lg flex items-center gap-2">
                <AlertCircle className="w-4 h-4 text-red-600 dark:text-red-400 flex-shrink-0" />
                <p className="text-sm text-red-700 dark:text-red-300">{submitError}</p>
              </div>
            )}

            <div className="flex gap-4">
              <button type="button" onClick={() => {
                // Package bookings skip results/seats entirely — they land here directly
                // from /packages/[id] via a plain router.push. Hardcoding a return to
                // /booking/results would be wrong for that flow (it was never visited), so
                // use real browser back navigation instead, which lands exactly back on the
                // package page with its original URL/state intact.
                if (packageId) {
                  router.back();
                  return;
                }
                const params = new URLSearchParams({
                  origin: searchCriteria.originStationId,
                  destination: searchCriteria.destinationStationId,
                  date: searchCriteria.departureDate,
                  adults: String(searchCriteria.adultCount),
                  children: String(searchCriteria.childCount),
                  nationality: searchCriteria.nationality,
                  ...(searchCriteria.promoCode && { promoCode: searchCriteria.promoCode }),
                });
                router.push(`/booking/results?${params}`);
              }} className="btn-secondary flex-1 flex items-center justify-center gap-2" disabled={saving}>
                <ChevronLeft className="w-4 h-4" />
                Back
              </button>
              <button type="submit" className="btn-primary flex-1 flex items-center justify-center gap-2" disabled={saving}>
                {saving
                  ? <Loader2 className="w-4 h-4 animate-spin" />
                  : 'Continue to seat selection'}
              </button>
            </div>
          </form>
        </div>
      </div>
    </div>
  );
}

/**
 * Gate that waits for the persisted booking store to finish rehydrating from localStorage before
 * mounting the form. This matters on a full page load — notably returning from the Fayda redirect
 * (`/booking/passengers?code&state`) — where reading searchCriteria too early would (a) bounce to
 * home and (b) initialise react-hook-form with the wrong passenger count. Once hydrated: no
 * booking → redirect home; booking present → render the form with correct defaults.
 */
export default function PassengersPage() {
  const searchCriteria = useBookingStore((s) => s.searchCriteria);
  const [hydrated, setHydrated] = useState(false);

  useEffect(() => {
    if (useBookingStore.persist.hasHydrated()) {
      setHydrated(true);
      return;
    }
    const unsub = useBookingStore.persist.onFinishHydration(() => setHydrated(true));
    return unsub;
  }, []);

  useEffect(() => {
    if (hydrated && !searchCriteria) {
      window.location.href = '/';
    }
  }, [hydrated, searchCriteria]);

  if (!hydrated || !searchCriteria) {
    return (
      <div className="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900">
        <Loader2 className="w-8 h-8 animate-spin text-primary" />
      </div>
    );
  }

  return <PassengersForm />;
}
