'use client';

import { useRouter } from 'next/navigation';
import { useBookingStore } from '@/lib/booking-store';
import { useAuthStore } from '@/lib/auth-store';
import { useMutation } from '@tanstack/react-query';
import { apiClient } from '@/lib/api-client';
import { format } from 'date-fns';
import { formatTime, getTimePeriod, toZonedDate } from '@/utils/format';
import { useState, useEffect, useRef } from 'react';
import { ChevronLeft } from 'lucide-react';
import { isChild, isFirstChild, formatFare } from '@/utils/fare-utils';

// Helper function to decode JWT token and extract passengerId
function getPassengerIdFromToken(token: string): string | null {
  try {
    if (!token) {
      return null;
    }

    const parts = token.split('.');
    if (parts.length !== 3) {
      return null;
    }
    
    // Decode JWT payload with proper base64 padding
    const payload = parts[1];
    const padded = payload + '='.repeat((4 - payload.length % 4) % 4);
    
    let decoded;
    try {
      decoded = JSON.parse(atob(padded));
    } catch (e) {
      return null;
    }
    
    
    if (!decoded.passengerId) {
      return null;
    }
    
    return decoded.passengerId;
  } catch (error) {
    return null;
  }
}

export default function ReviewPage() {
  const router = useRouter();
  const { selectedSchedule, outboundSchedule, inboundSchedule, passengers, seatHold, bookingId, pnr, bookingHoldId, bookingReturnHoldId, reviewedTotalMinor, setBookingId, setPNR, setBookingHoldReference, setReviewedTotal, createAccount, passengerId: storedPassengerId, searchCriteria, packageId, priceTierId, packageTierPriceMinor, packageName } = useBookingStore();
  const { user, isAuthenticated } = useAuthStore();
  const [timeLeft, setTimeLeft] = useState<string>('');
  const [seatDetails, setSeatDetails] = useState<Record<string, string>>({});
  const [fareBreakdown, setFareBreakdown] = useState<any>(null);
  const [returnFareBreakdown, setReturnFareBreakdown] = useState<any>(null);
  const [computedTotal, setComputedTotal] = useState<number>(0);

  const isRoundTrip = searchCriteria?.tripType === 'ROUND_TRIP';

  // Use the display currency stored on the schedule (set at search/selection time).
  // Fall back to nationality-based derivation only if the schedule has no displayCurrency.
  const scheduleCurrency = isRoundTrip
    ? outboundSchedule?.displayCurrency
    : selectedSchedule?.displayCurrency;
  const nat = (searchCriteria?.nationality ?? '').toUpperCase();
  const displayCurrencyCode = scheduleCurrency || (nat === 'DJIBOUTIAN' ? 'DJF' : nat === 'ETHIOPIAN' ? 'ETB' : 'USD');

  useEffect(() => {
    if (!seatHold?.expiresAt) return;

    const interval = setInterval(() => {
      const now = new Date().getTime();
      const expiry = new Date(seatHold.expiresAt).getTime();
      const diff = expiry - now;

      if (diff <= 0) {
        setTimeLeft('Expired');
        clearInterval(interval);
      } else {
        const minutes = Math.floor(diff / 60000);
        const seconds = Math.floor((diff % 60000) / 1000);
        setTimeLeft(`${minutes}:${seconds.toString().padStart(2, '0')}`);
      }
    }, 1000);

    return () => clearInterval(interval);
  }, [seatHold]);

  const buildSeatLabel = (seat: any): string => {
    const base: string = seat.number || seat.label || seat.seatNumber || '';
    if (!base) return 'N/A';
    const posMap: Record<string, string> = { lower: 'L', middle: 'M', upper: 'U' };
    const suffix = seat.bedPosition ? (posMap[seat.bedPosition] ?? '') : '';
    return suffix ? `${base}${suffix}` : base;
  };

  useEffect(() => {
    const fetchSeatDetails = async () => {
      try {
        const details: Record<string, string> = {};

        // Fetch outbound seat details
        if (isRoundTrip && outboundSchedule?.id) {
          const outboundSeatMap: any = await apiClient.get(`/seats/seatmap/${outboundSchedule.id}`);
          const outboundSeats = (outboundSeatMap?.coaches || []).flatMap((coach: any) => coach.seats || []);

          passengers.forEach(p => {
            if ((p as any).outboundSeatId) {
              const seat = outboundSeats.find((s: any) => s.id === (p as any).outboundSeatId);
              if (seat) details[`outbound-${(p as any).outboundSeatId}`] = buildSeatLabel(seat);
            }
          });
        }

        // Fetch inbound seat details
        if (isRoundTrip && inboundSchedule?.id) {
          const inboundSeatMap: any = await apiClient.get(`/seats/seatmap/${inboundSchedule.id}`);
          const inboundSeats = (inboundSeatMap?.coaches || []).flatMap((coach: any) => coach.seats || []);

          passengers.forEach(p => {
            if ((p as any).inboundSeatId) {
              const seat = inboundSeats.find((s: any) => s.id === (p as any).inboundSeatId);
              if (seat) details[`inbound-${(p as any).inboundSeatId}`] = buildSeatLabel(seat);
            }
          });
        }

        // Fetch one-way seat details
        if (!isRoundTrip && selectedSchedule?.id) {
          const seatMapData: any = await apiClient.get(`/seats/seatmap/${selectedSchedule.id}`);
          const allSeats = (seatMapData?.coaches || []).flatMap((coach: any) => coach.seats || []);

          passengers.forEach(p => {
            if (p.seatId) {
              const seat = allSeats.find((s: any) => s.id === p.seatId);
              if (seat) details[p.seatId] = buildSeatLabel(seat);
            }
          });
        }
        
        setSeatDetails(details);
      } catch (error) {
      }
    };
    
    fetchSeatDetails();
  }, [selectedSchedule?.id, outboundSchedule?.id, inboundSchedule?.id, passengers, isRoundTrip]);

  const isPackageBooking = packageTierPriceMinor !== null || !!packageName;

const adultPassengerCount = searchCriteria?.adultCount ?? passengers.filter(p => !isChild(p)).length;
  const pkgPriceMultiplier = isRoundTrip ? 2 : 1;
  const pkgAdultFare = isPackageBooking && packageTierPriceMinor != null ? packageTierPriceMinor * pkgPriceMultiplier : 0;
  const pkgChildFare = pkgAdultFare;

  const isPackageChild = (index: number) =>
    isPackageBooking ? index >= adultPassengerCount : isChild(passengers[index]);

  const isPkgFreeChild = (index: number) => {
    if (!isPackageBooking) return false;
    if (!isPackageChild(index)) return false;
    const childIndex = index - adultPassengerCount;
    return childIndex < adultPassengerCount;
  };

  // Returns the fare for a passenger in the display currency.
  // Prefers displayFareMinor (converted) from the fare breakdown API when available.
  // Falls back to raw ETB seat fares (which are always in minor units).
  const getPassengerSeatFare = (p: any, index?: number): number | null => {
    if (isRoundTrip) {
      // Seat-specific fares (set during seat selection) cover each leg separately — use them first.
      if (p.outboundSeatFareMinor != null || p.inboundSeatFareMinor != null) {
        if (isPackageBooking) return (p.outboundSeatFareMinor ?? 0) * 2;
        return (p.outboundSeatFareMinor ?? 0) + (p.inboundSeatFareMinor ?? 0);
      }
      // No seat-specific fares: fall back to the per-leg fare-breakdown totals for both legs.
      if (!isPackageBooking && fareBreakdown?.passengers && returnFareBreakdown?.passengers && index != null) {
        const obLine = fareBreakdown.passengers[index];
        const retLine = returnFareBreakdown.passengers[index];
        const obFare = obLine?.displayFareMinor ?? obLine?.fareMinor;
        const retFare = retLine?.displayFareMinor ?? retLine?.fareMinor;
        if (obFare != null && retFare != null) return obFare + retFare;
      }
      return null;
    }
    // One-way: seat-specific fare (set at seat selection) is the authoritative price —
    // it is exactly what was shown to the user. Use the fare-breakdown API only as fallback
    // for cases where seatFareMinor was not captured (e.g. auto-assign without seat map).
    if (p.seatFareMinor != null) {
      return (isPackageBooking && isRoundTrip) ? p.seatFareMinor * 2 : p.seatFareMinor;
    }
    if (!isPackageBooking && fareBreakdown?.passengers && index != null) {
      const line = fareBreakdown.passengers[index];
      const displayFare = line?.displayFareMinor ?? line?.fareMinor;
      if (displayFare != null) return displayFare;
    }
    return null;
  };

  const createBookingMutation = useMutation({
    mutationFn: (data: any) => {
      const endpoint = isAuthenticated ? '/bookings' : '/bookings/guest';
      return apiClient.post(endpoint, data);
    },
    onSuccess: (data: any) => {
      const bookingIdValue = data.bookingId || data.id;
      const pnrValue = data.pnr || data.bookingReference || data.bookingRef;
      setBookingId(bookingIdValue);
      setPNR(pnrValue);
      // Remember which hold(s) this booking was created from, so if the user comes back
      // here (e.g. hitting "back" from the payment gateway) with the same hold still in
      // the store, we can detect it's the same booking and reuse it instead of creating
      // another one.
      setBookingHoldReference(seatHold?.holdId || null, seatHold?.returnHoldId || null);
      const totalAmount = data.totalMinor || data.totalAmount || 0;
      setTimeout(() => {
        if (totalAmount > 0) {
          router.push('/booking/payment');
        } else {
          router.push('/booking/confirmation');
        }
      }, 100);
    },
    onError: (error: any) => {
      const errorMessage = error?.response?.data?.message || error?.message || 'Failed to create booking. Please try again.';
      alert(errorMessage);
    },
  });

  const handleConfirm = async () => {
    try {
      const { searchCriteria } = useBookingStore.getState();

      // A booking already exists for the exact hold(s) currently in the store — e.g. the
      // user was sent to the payment gateway and hit "back". Reuse it instead of creating
      // a duplicate booking; just resume the payment step.
      const sameHoldAsExistingBooking =
        !!bookingId &&
        !!pnr &&
        !!seatHold?.holdId &&
        seatHold.holdId === bookingHoldId &&
        (isRoundTrip ? (seatHold.returnHoldId || null) === bookingReturnHoldId : true);
      if (sameHoldAsExistingBooking) {
        router.push((reviewedTotalMinor ?? 0) > 0 ? '/booking/payment' : '/booking/confirmation');
        return;
      }

      if (!seatHold?.holdId) {
        alert('Please select seats before continuing.');
        router.push('/booking/seats');
        return;
      }

      if (isRoundTrip && !seatHold.returnHoldId) {
        alert('Please select return seats before continuing.');
        router.push('/booking/seats');
        return;
      }
      
      if (!searchCriteria?.originStationId || !searchCriteria?.destinationStationId) {
        alert('Missing search criteria. Please start over.');
        window.location.href = '/';
        return;
      }
      
      // Get seat class ID by name-matching against the /seat-classes list
      let seatClassId = '';
      let returnSeatClassId = '';
      try {
        const seatClasses: any[] = await apiClient.get('/seat-classes');
        if (seatClasses && seatClasses.length > 0) {
          const outboundClassName = isRoundTrip
            ? (outboundSchedule as any)?.seatClassName
            : (selectedSchedule as any)?.seatClassName;
          const returnClassName = isRoundTrip
            ? (inboundSchedule as any)?.seatClassName
            : outboundClassName;

          const findByName = (name: string) =>
            seatClasses.find((sc: any) => sc.name === name)?.id || seatClasses[0].id;

          seatClassId = outboundClassName ? findByName(outboundClassName) : seatClasses[0].id;
          returnSeatClassId = returnClassName ? findByName(returnClassName) : seatClasses[0].id;
        }
      } catch (err) {
      }

      if (!seatClassId) {
        alert('Unable to determine seat class. Please go back and re-select your seats.');
        return;
      }
      
      let bookingData: any;
      if (isAuthenticated) {
        // For authenticated users: get passengerId from multiple sources
        const token = typeof window !== 'undefined' ? localStorage.getItem('auth_token') : null;
        
        if (!token) {
          throw new Error('Authentication token not found. Please log in again.');
        }


        let passengerId = getPassengerIdFromToken(token);
        
        // Fallback 1: Use passengerId from booking store
        if (!passengerId && storedPassengerId) {
          passengerId = storedPassengerId;
        }
        
        // Fallback 2: Use passengerId from localStorage
        if (!passengerId && typeof window !== 'undefined') {
          const localStoragePassengerId = localStorage.getItem('booking_passengerId');
          if (localStoragePassengerId) passengerId = localStoragePassengerId;
        }
        
        // Fallback 3: Use passengerId from user object. The profile response nests
        // it under `passenger.id`, while the login response exposes it top-level as
        // `passengerId` — accept either shape so a cached profile user still resolves.
        if (!passengerId && user) {
          passengerId = (user as any).passengerId || (user as any).passenger?.id;
        }

        // Fallback 4: last resort — fetch the passenger profile directly.
        if (!passengerId) {
          try {
            const me: any = await apiClient.get('/passengers/me');
            passengerId = me?.id || me?.passengerId || '';
          } catch (err) {
          }
        }

        if (!passengerId) {
          throw new Error('Passenger ID not found in authentication token. Please log in again.');
        }

        // Build booking request for authenticated users
        // Free children (first child per adult) never go through seat selection and have no
        // seatId — true for package bookings AND regular ones (see booking/seats/page.tsx's
        // seatEligibility: "First adultCount children are free (no seat)... same rule applies"
        // for regular bookings too). Submitting one anyway sends seatId: undefined, which the
        // backend's `seat: { connect: { id } }` rejects — hence excluding them here for both
        // cases. (Their absence from adultCount/childCount on the confirmed booking is a
        // separate, backend-side gap — not something the frontend can paper over by sending
        // an unseated passenger.)
        const bookingPassengers = passengers.filter((p, i) => !(isChild(p) && isFirstChild(passengers, i)));

        bookingData = {
          passengerId: passengerId,
          scheduleId: isRoundTrip ? outboundSchedule?.id : selectedSchedule?.id,
          holdId: seatHold?.holdId || '',
          originStationId: searchCriteria.originStationId,
          destinationStationId: searchCriteria.destinationStationId,
          seatClassId: seatClassId,
          bookingType: isRoundTrip ? 'ROUND_TRIP' : 'ONE_WAY',
          displayCurrency: displayCurrencyCode,
          passengers: bookingPassengers.map((p) => {
            const isEthiopian = p.nationality === 'ETHIOPIAN' || p.nationality === 'Ethiopian';
            const seatId = isRoundTrip ? (p as any).outboundSeatId : p.seatId;
            return {
              ...(seatId ? { seatId } : {}),
              ...(isRoundTrip && (p as any).inboundSeatId ? { returnSeatId: (p as any).inboundSeatId } : {}),
              passengerName: p.name,
              dateOfBirth: p.dateOfBirth,
              idDocumentType: isEthiopian ? 'NATIONAL_ID' : 'PASSPORT',
              idDocumentNumber: isEthiopian ? (p.nationalId || '') : '',
              passportNumber: !isEthiopian ? (p.passportNumber || '') : '',
              passportCountry: !isEthiopian ? (p.passportCountry || '') : '',
              nationality: p.nationality,
              ...(isRoundTrip
                ? { seatFareMinor: (p as any).outboundSeatFareMinor ?? undefined, returnSeatFareMinor: (p as any).inboundSeatFareMinor ?? undefined }
                : { seatFareMinor: p.seatFareMinor ?? undefined }),
            };
          }),
        };
        
        // Add round trip specific fields
        if (isRoundTrip && inboundSchedule) {
          bookingData.returnScheduleId = inboundSchedule.id;
          bookingData.returnOriginStationId = searchCriteria.destinationStationId;
          bookingData.returnDestinationStationId = searchCriteria.originStationId;
          bookingData.returnHoldId = seatHold.returnHoldId || seatHold.holdId;
          bookingData.returnSeatClassId = returnSeatClassId;
        }
        
        // Add promo code if exists
        if (searchCriteria.promoCode) {
          bookingData.promoCode = searchCriteria.promoCode;
        }

        // Add package fields if this is a package booking
        if (packageId) bookingData.packageId = packageId;
        if (priceTierId) bookingData.priceTierId = priceTierId;
      } else {
        // For guests: send full passenger details array
        // Free children (first child per adult) never go through seat selection and have no
        // seatId — true for package bookings AND regular ones (see booking/seats/page.tsx's
        // seatEligibility comment). Submitting one anyway sends seatId: undefined, which the
        // backend's `seat: { connect: { id } }` rejects — hence excluding them here for both
        // cases.
        const guestBookingPassengers = passengers.filter((p, i) => !(isChild(p) && isFirstChild(passengers, i)));

        bookingData = {
          scheduleId: isRoundTrip ? outboundSchedule?.id : selectedSchedule?.id,
          holdId: seatHold?.holdId || '',
          originStationId: searchCriteria.originStationId,
          destinationStationId: searchCriteria.destinationStationId,
          seatClassId: seatClassId,
          bookingType: isRoundTrip ? 'ROUND_TRIP' : 'ONE_WAY',
          displayCurrency: displayCurrencyCode,
          passengers: guestBookingPassengers.map(p => {
            const isEthiopian = p.nationality === 'ETHIOPIAN' || p.nationality === 'Ethiopian';
            const seatId = isRoundTrip ? (p as any).outboundSeatId : p.seatId;
            return {
              ...(seatId ? { seatId } : {}),
              ...(isRoundTrip && (p as any).inboundSeatId ? { returnSeatId: (p as any).inboundSeatId } : {}),
              passengerName: p.name,
              dateOfBirth: p.dateOfBirth,
              idDocumentType: isEthiopian ? 'NATIONAL_ID' : 'PASSPORT',
              idDocumentNumber: isEthiopian ? (p.nationalId || '') : '',
              passportNumber: !isEthiopian ? (p.passportNumber || '') : '',
              passportCountry: !isEthiopian ? (p.passportCountry || '') : '',
              nationality: p.nationality,
              // Forward the contact details collected on the passengers page. The backend
              // stores the first passenger's phone/email as the booking's contactPhone/
              // contactEmail, which the notifications service uses to send the booking SMS
              // and email. Omitting these leaves contactPhone null → "No SMS phone" warning.
              ...(p.phone ? { phone: p.phone } : {}),
              ...(p.email ? { email: p.email } : {}),
              ...(isRoundTrip
                ? { seatFareMinor: (p as any).outboundSeatFareMinor ?? undefined, returnSeatFareMinor: (p as any).inboundSeatFareMinor ?? undefined }
                : { seatFareMinor: p.seatFareMinor ?? undefined }),
            };
          }),
          createAccount: createAccount || false,
          savePassengerDetails: true,
          deviceId: typeof window !== 'undefined' ? (localStorage.getItem('deviceId') || `device-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`) : undefined,
        };
        
        // Add round trip specific fields
        if (isRoundTrip && inboundSchedule) {
          bookingData.returnScheduleId = inboundSchedule.id;
          bookingData.returnOriginStationId = searchCriteria.destinationStationId;
          bookingData.returnDestinationStationId = searchCriteria.originStationId;
          bookingData.returnHoldId = seatHold.returnHoldId || seatHold.holdId;
          bookingData.returnSeatClassId = returnSeatClassId;
        }
        
        // Add promo code if exists
        if (searchCriteria.promoCode) {
          bookingData.promoCode = searchCriteria.promoCode;
        }

        // Add package fields if this is a package booking
        if (packageId) bookingData.packageId = packageId;
        if (priceTierId) bookingData.priceTierId = priceTierId;
      }

      if (typeof window !== 'undefined' && !isAuthenticated && bookingData.deviceId && !localStorage.getItem('deviceId')) {
        localStorage.setItem('deviceId', bookingData.deviceId);
      }

      // Persist the review-page total before navigating so payment/confirmation use the same figure
      const passengerFares = passengers.map((p, i) => {
        const isChildPassenger = isPackageBooking ? i >= adultPassengerCount : isChild(p);
        const line = fareBreakdown?.passengers?.[i];
        const isFreeChild = isPackageBooking
          ? (isChildPassenger && (i - adultPassengerCount) < adultPassengerCount)
          : (line?.isFree ?? (isChild(p) && isFirstChild(passengers, i)));
        const seatFare = getPassengerSeatFare(p, i);
        const pkgFallback = isChildPassenger ? pkgChildFare : pkgAdultFare;
        const fareMinor = isPackageBooking
          ? (isFreeChild ? 0 : (seatFare ?? pkgFallback))
          : (isFreeChild ? 0 : (seatFare ?? line?.fareMinor ?? 0));
        const halfFare = seatFare != null ? Math.round(seatFare / 2) : undefined;
        const outboundFareMinor = isRoundTrip ? (halfFare ?? (p as any).outboundSeatFareMinor ?? undefined) : undefined;
        const inboundFareMinor = isRoundTrip ? (halfFare ?? (p as any).inboundSeatFareMinor ?? undefined) : undefined;
        return { fareMinor, isFree: isFreeChild, outboundFareMinor, inboundFareMinor };
      });
      setReviewedTotal(computedTotal, passengerFares);

      // Pass the exact total shown on this page to the backend so it stores the
      // correct berth-specific amount regardless of what the fare engine calculates.
      bookingData.reviewedTotalMinor = computedTotal;

      await createBookingMutation.mutateAsync(bookingData);
    } catch (error) {
      alert(error instanceof Error ? error.message : 'An unexpected error occurred. Please try again.');
    }
  };

  useEffect(() => {
    if (isRoundTrip) {
      if (!outboundSchedule || !inboundSchedule || !passengers.length) {
        if (!createBookingMutation.isPending && !createBookingMutation.isSuccess) {
          window.location.href = '/';
        }
      }
    } else {
      if (!selectedSchedule || !passengers.length) {
        if (!createBookingMutation.isPending && !createBookingMutation.isSuccess) {
          window.location.href = '/';
        }
      }
    }
  }, [isRoundTrip, selectedSchedule, outboundSchedule, inboundSchedule, passengers.length, createBookingMutation.isPending, createBookingMutation.isSuccess, router]);

  const fareBreakdownFetchedRef = useRef(false);
  const scheduleId = isRoundTrip ? outboundSchedule?.id : selectedSchedule?.id;

  useEffect(() => {
    if (fareBreakdownFetchedRef.current) return;
    if (!searchCriteria?.originStationId || !searchCriteria?.destinationStationId) return;
    if (!scheduleId) return;
    if (isPackageBooking) return;

    fareBreakdownFetchedRef.current = true;

    (async () => {
      try {
        const seatClasses: any[] = await apiClient.get('/seat-classes');
        const scheduleSeatClassName = isRoundTrip
          ? (outboundSchedule as any)?.seatClassName
          : (selectedSchedule as any)?.seatClassName;
        const fallbackSeatClassId = seatClasses.find((sc: any) => sc.name === scheduleSeatClassName)?.id || seatClasses[0]?.id;
        if (!fallbackSeatClassId) return;

        const resolveSeatClassId = (p: any): string => {
          const bedPosition: string | undefined = isRoundTrip ? (p as any).outboundBedPosition : (p as any).bedPosition;
          if (!bedPosition) return fallbackSeatClassId;
          const match = seatClasses.find((sc: any) => sc.name?.toLowerCase().includes(bedPosition));
          return match?.id || fallbackSeatClassId;
        };

        const passengersParam = JSON.stringify(
          passengers.map(p => ({
            passengerName: p.name,
            dateOfBirth: p.dateOfBirth,
            seatClassId: resolveSeatClassId(p),
            nationality: p.nationality,
          }))
        );

        const params = new URLSearchParams({
          scheduleId,
          originStationId: searchCriteria.originStationId,
          destinationStationId: searchCriteria.destinationStationId,
          passengers: passengersParam,
          displayCurrency: displayCurrencyCode,
          ...(searchCriteria.promoCode ? { promoCode: searchCriteria.promoCode } : {}),
        });

        const result: any = await apiClient.get(`/search/fare-breakdown?${params}`);
        setFareBreakdown(result);

        // For round-trips, also fetch the return leg's fare breakdown so the review page
        // can display and send the correct combined total (outbound + return per passenger).
        if (isRoundTrip && inboundSchedule) {
          const returnScheduleId = (inboundSchedule as any).id;
          const returnParams = new URLSearchParams({
            scheduleId: returnScheduleId,
            originStationId: searchCriteria.destinationStationId,
            destinationStationId: searchCriteria.originStationId,
            passengers: passengersParam,
            displayCurrency: displayCurrencyCode,
            ...(searchCriteria.promoCode ? { promoCode: searchCriteria.promoCode } : {}),
          });
          const returnResult: any = await apiClient.get(`/search/fare-breakdown?${returnParams}`);
          setReturnFareBreakdown(returnResult);
        }
      } catch (err) {
      }
    })();
  // Intentionally re-runs until store is hydrated (scheduleId/originStationId become
  // available), then the ref guard ensures it only fetches once.
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [searchCriteria?.originStationId, searchCriteria?.destinationStationId, scheduleId]);

  // For package bookings, passengers are initialized without dateOfBirth so isChild() is
  // unreliable. Use the stored adultCount from searchCriteria to determine category by index.
  const total = isPackageBooking
    ? passengers.reduce((sum, p, i) => {
        const isChild_ = isPackageChild(i);
        const isFreeChild = isChild_ && (i - adultPassengerCount) < adultPassengerCount;
        if (isFreeChild) return sum;
        const seatFare = getPassengerSeatFare(p, i);
        const pkgFallback = isChild_ ? pkgChildFare : pkgAdultFare;
        return sum + (seatFare ?? pkgFallback);
      }, 0)
    : passengers.reduce((sum, p, i) => {
        const isChildPassenger = isChild(p);
        const line = fareBreakdown?.passengers?.[i];
        const isFreeChild = line?.isFree ?? (isChildPassenger && isFirstChild(passengers, i));
        if (isFreeChild) return sum;
        const seatFare = getPassengerSeatFare(p, i);
        // For round-trips the fallback must combine both legs; for one-way it's the single-leg fare.
        const obFare = line?.displayFareMinor ?? line?.fareMinor;
        const retLine = returnFareBreakdown?.passengers?.[i];
        const retFare = retLine?.displayFareMinor ?? retLine?.fareMinor;
        const displayFare = isRoundTrip && retFare != null ? (obFare ?? 0) + retFare : obFare;
        return sum + (seatFare ?? displayFare ?? 0);
      }, 0);

  // Keep computedTotal in sync so handleConfirm can persist it to the store
  useEffect(() => { setComputedTotal(total); }, [total]);

  // Shared fare sidebar — rendered in right column (desktop) and inline (mobile)
  const FareSidebar = () => (
    <div className="card space-y-3">
      <h2 className="text-base font-bold text-gray-900 dark:text-gray-100 pb-2 border-b border-gray-100 dark:border-gray-800">
        Fare breakdown
      </h2>
      {passengers.map((p, i) => {
        const line = fareBreakdown?.passengers?.[i];
        const isChildPassenger = isPackageChild(i);
        const isFreeChild = isPackageBooking
          ? isPkgFreeChild(i)
          : (line?.isFree ?? (isChild(p) && isFirstChild(passengers, i)));

        // Per-leg fares for round trips — prefer seat-specific fares, then per-leg breakdowns.
        const retLine = returnFareBreakdown?.passengers?.[i];
        const obBreakdownFare = line?.displayFareMinor ?? line?.fareMinor;
        const retBreakdownFare = retLine?.displayFareMinor ?? retLine?.fareMinor;
        const outboundFare: number | null = isRoundTrip
          ? (isPackageBooking
              ? (packageTierPriceMinor ?? null)
              : ((p as any).outboundSeatFareMinor ?? obBreakdownFare ?? null))
          : null;
        const inboundFare: number | null = isRoundTrip
          ? (isPackageBooking
              ? (packageTierPriceMinor ?? null)
              : ((p as any).inboundSeatFareMinor ?? retBreakdownFare ?? null))
          : null;
        const seatFare = getPassengerSeatFare(p, i);
        const combinedDisplayFare = isRoundTrip && retBreakdownFare != null
          ? (obBreakdownFare ?? 0) + retBreakdownFare
          : obBreakdownFare;
        const passengerTotal = isPackageBooking
          ? (isFreeChild ? 0 : (seatFare ?? (isChildPassenger ? pkgChildFare : pkgAdultFare)))
          : (isFreeChild ? 0 : (seatFare ?? combinedDisplayFare ?? 0));

        return (
          <div key={i} className="border-b border-gray-100 dark:border-gray-800 pb-2 last:border-0">
            <div className="flex justify-between mb-0.5">
              <span className="text-sm font-medium text-gray-900 dark:text-gray-100 truncate max-w-[60%]">
                {p.name || `Passenger ${i + 1}`}
                {isChildPassenger && (
                  <span className={`text-xs font-semibold ml-1 ${
                    isFreeChild ? 'text-green-600' : 'text-blue-600'
                  }`}>
                    ({isFreeChild ? 'CHILD - FREE' : 'CHILD - FULL FARE'})
                  </span>
                )}
              </span>
              <span className="text-sm font-semibold text-gray-900 dark:text-gray-100">
                {formatFare(passengerTotal, displayCurrencyCode)}
              </span>
            </div>
            {/* Round-trip: show outbound + inbound breakdown */}
            {isRoundTrip && !isFreeChild && (
              <div className="mt-1 space-y-0.5 pl-2">
                <div className="flex justify-between text-xs text-gray-500 dark:text-gray-400">
                  <span>↗ Outbound</span>
                  <span>{outboundFare != null ? formatFare(outboundFare, displayCurrencyCode) : '—'}</span>
                </div>
                <div className="flex justify-between text-xs text-gray-500 dark:text-gray-400">
                  <span>↙ Return</span>
                  <span>{inboundFare != null ? formatFare(inboundFare, displayCurrencyCode) : '—'}</span>
                </div>
              </div>
            )}
          </div>
        );
      })}
      <div className="flex justify-between items-center pt-1 border-t border-gray-200 dark:border-gray-700">
        <span className="font-bold text-gray-900 dark:text-gray-100">Total</span>
        <span className="text-xl font-bold text-primary">{formatFare(total, displayCurrencyCode)}</span>
      </div>

      {/* Action buttons — visible only in desktop sidebar */}
      <div className="hidden lg:flex flex-col gap-2 pt-2">
        {createBookingMutation.isError && (
          <p className="text-red-600 dark:text-red-400 text-xs">
            ⚠️ {createBookingMutation.error instanceof Error ? createBookingMutation.error.message : 'An error occurred. Please try again.'}
          </p>
        )}
        <button
          onClick={handleConfirm}
          disabled={createBookingMutation.isPending}
          className="btn-primary w-full"
        >
          {createBookingMutation.isPending ? 'Creating booking...' : `Confirm ${isAuthenticated ? '' : 'and pay'}`}
        </button>
        <button onClick={() => router.back()} className="btn-secondary w-full flex items-center justify-center gap-2">
          <ChevronLeft className="w-4 h-4" />
          Back
        </button>
      </div>
    </div>
  );

  return (
    <div className="booking-page pb-28 lg:pb-10">
      <div className="container mx-auto px-4">
        <div className="max-w-6xl mx-auto">
          <h1 className="section-title">
            {packageName ? `Review your ${packageName} booking` : 'Review your booking'}
          </h1>

          {seatHold && (
            <div className="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg p-3 mb-4 flex items-center gap-2">
              <span className="text-yellow-800 dark:text-yellow-200 text-sm">
                ⏱️ Seats held for: <span className="font-bold">{timeLeft}</span>
              </span>
            </div>
          )}

          {/* Two-column layout on desktop */}
          <div className="lg:grid lg:grid-cols-3 lg:gap-6 lg:items-start">

            {/* Left column — trip details + passengers */}
            <div className="lg:col-span-2 space-y-4">
            {/* Outbound Trip Details */}
            {isRoundTrip && outboundSchedule && (
              <div className="card overflow-hidden">
                <div className="flex items-center gap-2 mb-6 pb-4 border-b border-gray-100 dark:border-gray-800">
                  <div className="w-2 h-2 bg-primary rounded-full" />
                  <h2 className="text-lg font-bold text-gray-900 dark:text-gray-100">Outbound Journey</h2>
                </div>
                
                {/* Flight-style timeline */}
                <div className="flex">
                  {/* Left column: Timeline with dots and line */}
                  <div className="flex flex-col items-center w-8 flex-shrink-0">
                    {/* Origin dot */}
                    <div className="w-4 h-4 rounded-full border-4 border-primary bg-white dark:bg-gray-900 z-10" />
                    {/* Vertical line */}
                    <div className="w-0.5 flex-1 bg-gradient-to-b from-primary via-gray-300 dark:via-gray-700 to-gray-300 dark:to-gray-700 my-2" />
                    {/* Destination dot */}
                    <div className="w-4 h-4 rounded-full border-4 border-gray-400 dark:border-gray-600 bg-white dark:bg-gray-900 z-10" />
                  </div>
                  
                  {/* Right column: Content */}
                  <div className="flex-1 flex flex-col">
                    {/* Origin */}
                    <div className="pb-8">
                      <div className="text-2xl font-bold text-gray-900 dark:text-white">
                        {outboundSchedule.departureTime ? formatTime(outboundSchedule.departureTime) : '--:--'}
                      </div>
                      <div className="text-sm text-gray-500 dark:text-gray-400 mt-0.5">
                        {outboundSchedule.departureTime
                          ? `${format(toZonedDate(new Date(outboundSchedule.departureTime)), 'EEE, MMM d')} · ${getTimePeriod(outboundSchedule.departureTime)}`
                          : 'N/A'}
                      </div>
                      <div className="text-base font-semibold text-gray-900 dark:text-white mt-2">
                        {outboundSchedule.origin}
                      </div>
                    </div>

                    {/* Journey Info */}
                    <div className="pb-8">
                      <div className="flex items-center gap-6 text-sm text-gray-600 dark:text-gray-400">
                        <div className="flex items-center gap-1.5">
                          <svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
                          </svg>
                          <span className="font-medium">{outboundSchedule.duration}</span>
                        </div>
                        <div className="flex items-center gap-1.5">
                          <svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
                          </svg>
                          <span className="font-medium">Train {outboundSchedule.trainNumber}</span>
                        </div>
                      </div>
                    </div>

                    {/* Destination */}
                    <div>
                      <div className="text-2xl font-bold text-gray-900 dark:text-white">
                        {outboundSchedule.arrivalTime ? formatTime(outboundSchedule.arrivalTime) : '--:--'}
                      </div>
                      <div className="text-sm text-gray-500 dark:text-gray-400 mt-0.5">
                        {outboundSchedule.arrivalTime
                          ? `${format(toZonedDate(new Date(outboundSchedule.arrivalTime)), 'EEE, MMM d')} · ${getTimePeriod(outboundSchedule.arrivalTime)}`
                          : 'N/A'}
                      </div>
                      <div className="text-base font-semibold text-gray-900 dark:text-white mt-2">
                        {outboundSchedule.destination}
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            )}

            {/* Inbound Trip Details */}
            {isRoundTrip && inboundSchedule && (
              <div className="card overflow-hidden">
                <div className="flex items-center gap-2 mb-6 pb-4 border-b border-gray-100 dark:border-gray-800">
                  <div className="w-2 h-2 bg-blue-500 rounded-full" />
                  <h2 className="text-lg font-bold text-gray-900 dark:text-gray-100">Return Journey</h2>
                </div>
                
                {/* Flight-style timeline */}
                <div className="flex">
                  {/* Left column: Timeline with dots and line */}
                  <div className="flex flex-col items-center w-8 flex-shrink-0">
                    {/* Origin dot */}
                    <div className="w-4 h-4 rounded-full border-4 border-blue-500 bg-white dark:bg-gray-900 z-10" />
                    {/* Vertical line */}
                    <div className="w-0.5 flex-1 bg-gradient-to-b from-blue-500 via-gray-300 dark:via-gray-700 to-gray-300 dark:to-gray-700 my-2" />
                    {/* Destination dot */}
                    <div className="w-4 h-4 rounded-full border-4 border-gray-400 dark:border-gray-600 bg-white dark:bg-gray-900 z-10" />
                  </div>
                  
                  {/* Right column: Content */}
                  <div className="flex-1 flex flex-col">
                    {/* Origin */}
                    <div className="pb-8">
                      <div className="text-2xl font-bold text-gray-900 dark:text-white">
                        {inboundSchedule.departureTime ? formatTime(inboundSchedule.departureTime) : '--:--'}
                      </div>
                      <div className="text-sm text-gray-500 dark:text-gray-400 mt-0.5">
                        {inboundSchedule.departureTime
                          ? `${format(toZonedDate(new Date(inboundSchedule.departureTime)), 'EEE, MMM d')} · ${getTimePeriod(inboundSchedule.departureTime)}`
                          : 'N/A'}
                      </div>
                      <div className="text-base font-semibold text-gray-900 dark:text-white mt-2">
                        {inboundSchedule.origin}
                      </div>
                    </div>

                    {/* Journey Info */}
                    <div className="pb-8">
                      <div className="flex items-center gap-6 text-sm text-gray-600 dark:text-gray-400">
                        <div className="flex items-center gap-1.5">
                          <svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
                          </svg>
                          <span className="font-medium">{inboundSchedule.duration}</span>
                        </div>
                        <div className="flex items-center gap-1.5">
                          <svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
                          </svg>
                          <span className="font-medium">Train {inboundSchedule.trainNumber}</span>
                        </div>
                      </div>
                    </div>

                    {/* Destination */}
                    <div>
                      <div className="text-2xl font-bold text-gray-900 dark:text-white">
                        {inboundSchedule.arrivalTime ? formatTime(inboundSchedule.arrivalTime) : '--:--'}
                      </div>
                      <div className="text-sm text-gray-500 dark:text-gray-400 mt-0.5">
                        {inboundSchedule.arrivalTime
                          ? `${format(toZonedDate(new Date(inboundSchedule.arrivalTime)), 'EEE, MMM d')} · ${getTimePeriod(inboundSchedule.arrivalTime)}`
                          : 'N/A'}
                      </div>
                      <div className="text-base font-semibold text-gray-900 dark:text-white mt-2">
                        {inboundSchedule.destination}
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            )}

            {/* One-Way Trip Details */}
            {!isRoundTrip && selectedSchedule && (
              <div className="card overflow-hidden">
                <div className="flex items-center gap-2 mb-6 pb-4 border-b border-gray-100 dark:border-gray-800">
                  <div className="w-2 h-2 bg-primary rounded-full" />
                  <h2 className="text-lg font-bold text-gray-900 dark:text-gray-100">Trip Details</h2>
                  <span className="ml-auto text-xs px-2.5 py-1 bg-primary/10 text-primary rounded-full font-semibold">
                    {selectedSchedule.selectedSeatClass?.replace(/_/g, ' ') || 'Standard'}
                  </span>
                </div>
                
                {/* Flight-style timeline */}
                <div className="flex">
                  {/* Left column: Timeline with dots and line */}
                  <div className="flex flex-col items-center w-8 flex-shrink-0">
                    {/* Origin dot */}
                    <div className="w-4 h-4 rounded-full border-4 border-primary bg-white dark:bg-gray-900 z-10" />
                    {/* Vertical line */}
                    <div className="w-0.5 flex-1 bg-gradient-to-b from-primary via-gray-300 dark:via-gray-700 to-gray-300 dark:to-gray-700 my-2" />
                    {/* Destination dot */}
                    <div className="w-4 h-4 rounded-full border-4 border-gray-400 dark:border-gray-600 bg-white dark:bg-gray-900 z-10" />
                  </div>
                  
                  {/* Right column: Content */}
                  <div className="flex-1 flex flex-col">
                    {/* Origin */}
                    <div className="pb-8">
                      <div className="text-2xl font-bold text-gray-900 dark:text-white">
                        {selectedSchedule.departureTime ? formatTime(selectedSchedule.departureTime) : '--:--'}
                      </div>
                      <div className="text-sm text-gray-500 dark:text-gray-400 mt-0.5">
                        {selectedSchedule.departureTime
                          ? `${format(toZonedDate(new Date(selectedSchedule.departureTime)), 'EEE, MMM d')} · ${getTimePeriod(selectedSchedule.departureTime)}`
                          : 'N/A'}
                      </div>
                      <div className="text-base font-semibold text-gray-900 dark:text-white mt-2">
                        {selectedSchedule.origin}
                      </div>
                    </div>

                    {/* Journey Info */}
                    <div className="pb-8">
                      <div className="flex items-center gap-6 text-sm text-gray-600 dark:text-gray-400">
                        <div className="flex items-center gap-1.5">
                          <svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
                          </svg>
                          <span className="font-medium">{selectedSchedule.duration}</span>
                        </div>
                        <div className="flex items-center gap-1.5">
                          <svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
                          </svg>
                          <span className="font-medium">Train {selectedSchedule.trainNumber}</span>
                        </div>
                      </div>
                    </div>

                    {/* Destination */}
                    <div>
                      <div className="text-2xl font-bold text-gray-900 dark:text-white">
                        {selectedSchedule.arrivalTime ? formatTime(selectedSchedule.arrivalTime) : '--:--'}
                      </div>
                      <div className="text-sm text-gray-500 dark:text-gray-400 mt-0.5">
                        {selectedSchedule.arrivalTime
                          ? `${format(toZonedDate(new Date(selectedSchedule.arrivalTime)), 'EEE, MMM d')} · ${getTimePeriod(selectedSchedule.arrivalTime)}`
                          : 'N/A'}
                      </div>
                      <div className="text-base font-semibold text-gray-900 dark:text-white mt-2">
                        {selectedSchedule.destination}
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            )}

            <div className="card">
              <h2 className="text-xl font-semibold mb-4 text-gray-900 dark:text-gray-100">Passengers</h2>
              <div className="space-y-3">
                {passengers.map((p, i) => (
                  <div key={i} className="border-b border-gray-200 dark:border-gray-700 pb-3 last:border-0">
                    <div className="flex items-center justify-between gap-4">
                      {/* Left — passenger info */}
                      <div className="min-w-0">
                        <p className="font-medium text-gray-900 dark:text-gray-100 truncate">{p.name}</p>
                        <p className="text-sm text-gray-600 dark:text-gray-400">
                          {p.dateOfBirth ? format(new Date(p.dateOfBirth), 'PP') : 'N/A'} • {p.nationality}
                        </p>
                      </div>
                      {/* Right — seat details */}
                      {isRoundTrip ? (
                        <div className="flex gap-2 flex-shrink-0">
                          <div className="bg-gray-50 dark:bg-gray-800 rounded-lg px-3 py-2 text-right">
                            <p className="text-xs text-gray-500 dark:text-gray-400">Outbound</p>
                            <p className="font-semibold text-sm text-gray-900 dark:text-gray-100">
                              {(p as any).outboundCoachNumber && <span className="text-gray-500 dark:text-gray-400">{(p as any).outboundCoachNumber} — </span>}
                              {(p as any).outboundSeatId ? (seatDetails[`outbound-${(p as any).outboundSeatId}`] || 'Loading...') : (isPkgFreeChild(i) || (!packageId && isChild(p) && isFirstChild(passengers, i)) ? '—' : 'Auto-assign')}
                            </p>
                          </div>
                          <div className="bg-gray-50 dark:bg-gray-800 rounded-lg px-3 py-2 text-right">
                            <p className="text-xs text-gray-500 dark:text-gray-400">Return</p>
                            <p className="font-semibold text-sm text-gray-900 dark:text-gray-100">
                              {(p as any).inboundCoachNumber && <span className="text-gray-500 dark:text-gray-400">{(p as any).inboundCoachNumber} — </span>}
                              {(p as any).inboundSeatId ? (seatDetails[`inbound-${(p as any).inboundSeatId}`] || 'Loading...') : (isPkgFreeChild(i) || (!packageId && isChild(p) && isFirstChild(passengers, i)) ? '—' : 'Auto-assign')}
                            </p>
                          </div>
                        </div>
                      ) : (
                        <div className="bg-gray-50 dark:bg-gray-800 rounded-lg px-3 py-2 text-right flex-shrink-0">
                          <p className="text-xs text-gray-500 dark:text-gray-400">Seat</p>
                          <p className="font-semibold text-sm text-gray-900 dark:text-gray-100">
                            {p.coachNumber && <span className="text-gray-500 dark:text-gray-400">{p.coachNumber} — </span>}
                            {p.seatId ? (seatDetails[p.seatId] || 'Loading...') : (isPkgFreeChild(i) || (!packageId && isChild(p) && isFirstChild(passengers, i)) ? '—' : 'Auto-assign')}
                          </p>
                        </div>
                      )}
                    </div>
                  </div>
                ))}
              </div>
            </div>

            {/* Fare breakdown — visible only on mobile (desktop shows it in right column) */}
            <div className="lg:hidden mt-4">
              <FareSidebar />
            </div>

            </div>{/* end left column */}

            {/* Right column — sticky fare card (desktop only) */}
            <div className="hidden lg:block">
              <div className="sticky top-6">
                <FareSidebar />
              </div>
            </div>

          </div>{/* end grid */}
        </div>
      </div>

      {/* Mobile sticky bottom bar */}
      <div className="lg:hidden fixed bottom-0 inset-x-0 bg-white dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700 px-4 py-3 z-40 shadow-lg">
        <div className="flex items-center justify-between mb-2.5">
          <span className="text-sm text-gray-600 dark:text-gray-400">Total</span>
          <span className="text-lg font-bold text-primary">{formatFare(total, displayCurrencyCode)}</span>
        </div>
        {createBookingMutation.isError && (
          <p className="text-red-600 dark:text-red-400 text-xs mb-2">
            ⚠️ {createBookingMutation.error instanceof Error ? createBookingMutation.error.message : 'An error occurred. Please try again.'}
          </p>
        )}
        <div className="flex gap-3">
          <button onClick={() => router.back()} className="btn-secondary flex-1 py-2.5 flex items-center justify-center gap-2">
            <ChevronLeft className="w-4 h-4" />
            Back
          </button>
          <button
            onClick={handleConfirm}
            disabled={createBookingMutation.isPending}
            className="btn-primary flex-1 py-2.5"
          >
            {createBookingMutation.isPending ? 'Creating...' : `Confirm ${isAuthenticated ? '' : '& pay'}`}
          </button>
        </div>
      </div>
    </div>
  );
}
