"use client";

import { useSearchParams, useRouter } from "next/navigation";
import { useQuery } from "@tanstack/react-query";
import { apiClient } from "@/lib/api-client";
import { useBookingStore } from "@/lib/booking-store";
import { Schedule } from "@/types";
import {
  ArrowRight,
  Clock,
  Calendar,
  Users,
  ChevronLeft,
  Check,
  X,
  MapPin,
  Gift,
  Train,
  Bed,
  Armchair,
  Star,
} from "lucide-react";
import { format } from "date-fns";
import { formatTime, getTimePeriod, toZonedDate } from "@/utils/format";
import { formatFare } from "@/utils/fare-utils";
import { useState, useEffect } from "react";
import AlternativeDatesCalendar from "@/components/AlternativeDatesCalendar";
import { Passenger } from "@edr/types";

// Shared by the compact schedule card's coach-type badges and the "Choose Your Coach"
// modal, so both pick the same icon for a given coach type name.
const getCoachIcon = (typeName: string) => {
  const lower = typeName.toLowerCase();
  if (lower.includes("soft") || lower.includes("vip")) return Star;
  if (lower.includes("bed")) return Bed;
  return Armchair;
};

function formatSearchDate(dateStr: string): string {
  if (!dateStr) return "your selected date";
  try {
    return format(new Date(`${dateStr}T00:00:00`), "MMM d, yyyy");
  } catch {
    return dateStr;
  }
}

// Turns the /search response's outboundReason/inboundReason (absent on older responses,
// or when the emptiness cause couldn't be classified) into copy for the empty-state cards
// below. `showAlternatives` gates whether an alternative-dates calendar makes sense — a
// station pair EDR never serves can't be fixed by picking a different date.
function emptyReasonCopy(
  reason: Passenger.ISearchEmptyReason | undefined,
  dateStr: string,
): { title: string; message: string; showAlternatives: boolean } {
  const date = formatSearchDate(dateStr);
  if (!reason) {
    return {
      title: "No trains available",
      message: `No trains available on ${date}. Please choose another date below.`,
      showAlternatives: true,
    };
  }
  const { code, originStationName, destinationStationName } = reason;
  switch (code) {
    case Passenger.SearchEmptyReasonCode.NoRoute:
      return {
        title: "Route not available",
        message: `EDR doesn't currently run trains between ${originStationName} and ${destinationStationName}.`,
        showAlternatives: false,
      };
    case Passenger.SearchEmptyReasonCode.FullyBooked:
      return {
        title: "Fully booked",
        message: `This train is fully booked on ${date}. Please choose another date below.`,
        showAlternatives: true,
      };
    case Passenger.SearchEmptyReasonCode.Cancelled:
      return {
        title: "Departure cancelled",
        message: `The ${date} departure between ${originStationName} and ${destinationStationName} was cancelled. Please choose another date below.`,
        showAlternatives: true,
      };
    case Passenger.SearchEmptyReasonCode.CheckinClosed:
      return {
        title: "Booking closed for today",
        message: `Booking for the ${date} departure has closed. Please choose another date below.`,
        showAlternatives: true,
      };
    case Passenger.SearchEmptyReasonCode.PackageOnly:
      return {
        title: "Only a travel package is available",
        message: `The only train between ${originStationName} and ${destinationStationName} on ${date} is bookable as part of a travel package, not as a standalone ticket. Please choose another date below.`,
        showAlternatives: true,
      };
    case Passenger.SearchEmptyReasonCode.NoScheduleOnDate:
    default:
      return {
        title: "No trains available",
        message: `No trains available on ${date}. Please choose another date below.`,
        showAlternatives: true,
      };
  }
}

export default function ResultsPage() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const { setSelectedSchedule, setOutboundSchedule, setInboundSchedule } =
    useBookingStore();
  const [selectedCoachTypes, setSelectedCoachTypes] = useState<
    Record<string, { id: string; code: string; name: string }>
  >({});
  const [outboundScheduleData, setOutboundScheduleData] = useState<any>(
    () => useBookingStore.getState().outboundSchedule,
  );
  const [effectiveDepartureDate, setEffectiveDepartureDate] = useState<string>('');
  const [effectiveReturnDate, setEffectiveReturnDate] = useState<string>('');
  // Round-trip "both legs empty" dual-calendar: holds picks until both outbound
  // and return dates are chosen, then a single search fires for the pair — see
  // the effect below, right after searchData/pushResultsWithDates are defined.
  const [pendingOutboundDate, setPendingOutboundDate] = useState<Date | undefined>();
  const [pendingInboundDate, setPendingInboundDate] = useState<Date | undefined>();
  const [classModal, setClassModal] = useState<Schedule | null>(null);
  const [promoData, setPromoData] = useState<{
    code: string;
    discount: string;
    message: string;
  } | null>(null);
  const [roundTripStep, setRoundTripStep] = useState<"outbound" | "inbound">(
    () => {
      const { outboundSchedule, searchCriteria: sc } =
        useBookingStore.getState();
      return outboundSchedule && sc?.tripType === "ROUND_TRIP"
        ? "inbound"
        : "outbound";
    },
  );

  const searchCriteria = useBookingStore((s) => s.searchCriteria);
  const setSearchCriteria = useBookingStore((s) => s.setSearchCriteria);

  const searchData = {
    originStationId:
      searchParams.get("origin") || searchCriteria?.originStationId || "",
    destinationStationId:
      searchParams.get("destination") ||
      searchCriteria?.destinationStationId ||
      "",
    date: searchParams.get("date") || searchCriteria?.departureDate || "",
    returnDate: searchParams.get("returnDate") || searchCriteria?.returnDate,
    journeyType:
      (searchParams.get("tripType") ??
        searchCriteria?.tripType ??
        "ONE_WAY") === "ROUND_TRIP"
        ? "ROUND_TRIP"
        : "ONE_WAY",
    adultCount:
      parseInt(searchParams.get("adults") || "") ||
      searchCriteria?.adultCount ||
      1,
    childCount:
      parseInt(searchParams.get("children") || "") ||
      searchCriteria?.childCount ||
      0,
    nationality:
      searchParams.get("nationality") ||
      searchCriteria?.nationality ||
      "ETHIOPIAN",
    promoCode: searchParams.get("promoCode") || searchCriteria?.promoCode || "",
  };

  // Keep the displayed effective dates in sync with the URL-driven search
  // criteria — not just on first load, but every time searchData.date/returnDate
  // actually changes (e.g. picking a new date on the alternative-dates calendar
  // re-runs the search with a different date; the heading must follow it, not
  // stay frozen on whatever was first requested).
  useEffect(() => {
    if (searchData.date) setEffectiveDepartureDate(searchData.date);
    if (searchData.returnDate) setEffectiveReturnDate(searchData.returnDate);
  }, [searchData.date, searchData.returnDate]);

  const nat = (searchData.nationality ?? '').toUpperCase();
  const displayCurrencyCode = nat === 'DJIBOUTIAN' ? 'DJF' : nat === 'ETHIOPIAN' ? 'ETB' : 'USD';

  useEffect(() => {
    if (searchParams.get("origin")) {
      setSearchCriteria({
        tripType: (searchParams.get("tripType") || "ONE_WAY") as
          | "ONE_WAY"
          | "ROUND_TRIP",
        originStationId: searchParams.get("origin")!,
        destinationStationId: searchParams.get("destination")!,
        departureDate: searchParams.get("date")!,
        returnDate: searchParams.get("returnDate") || undefined,
        adultCount: parseInt(searchParams.get("adults") || "1"),
        childCount: parseInt(searchParams.get("children") || "0"),
        nationality: (searchParams.get("nationality") || "ETHIOPIAN") as
          | "ETHIOPIAN"
          | "DJIBOUTIAN"
          | "OTHER",
        promoCode: searchParams.get("promoCode") || "",
      });
    }
  }, [searchParams, setSearchCriteria]);

  useEffect(() => {
    if (searchData.promoCode) {
      apiClient
        .post("/promos/validate", { code: searchData.promoCode })
        .then((response: any) => {
          if (response.applicable || response.valid) {
            setPromoData({
              code: searchData.promoCode,
              discount: response.message || "Discount applied",
              message: response.message || "Promo code applied successfully!",
            });
          }
        })
        .catch(() => {
          // Promo validation failed - silently ignore
        });
    }
  }, [searchData.promoCode]);

  const buildSearchUrl = () => {
    const params = new URLSearchParams({
      tripType: searchData.journeyType,
      origin: searchData.originStationId,
      destination: searchData.destinationStationId,
      date: searchData.date,
      adults: searchData.adultCount.toString(),
      children: searchData.childCount.toString(),
      nationality: searchData.nationality,
      ...(searchData.returnDate && { returnDate: searchData.returnDate }),
      ...(searchData.promoCode && { promoCode: searchData.promoCode }),
    });
    return `/booking/search?${params}`;
  };

  // Pushes a new date onto the CURRENT results route (not back to the search form,
  // unlike buildSearchUrl) — the query's queryKey is derived from these URL params
  // (see searchData/useQuery below), so this alone re-triggers a search with the
  // new date(s) while preserving route/passengers/nationality/promo unchanged.
  const pushResultsWithDates = (overrides: { date?: string; returnDate?: string }) => {
    const params = new URLSearchParams({
      tripType: searchData.journeyType,
      origin: searchData.originStationId,
      destination: searchData.destinationStationId,
      date: overrides.date ?? searchData.date,
      adults: searchData.adultCount.toString(),
      children: searchData.childCount.toString(),
      nationality: searchData.nationality,
      ...(searchData.promoCode && { promoCode: searchData.promoCode }),
    });
    const returnDate = overrides.returnDate ?? searchData.returnDate;
    if (returnDate) params.set("returnDate", returnDate);
    router.push(`/booking/results?${params}`);
  };

  // Round-trip dual calendar: fire the search only once both legs have a pick —
  // picking outbound alone must not trigger a search on its own.
  useEffect(() => {
    if (pendingOutboundDate && pendingInboundDate) {
      pushResultsWithDates({
        date: format(pendingOutboundDate, "yyyy-MM-dd"),
        returnDate: format(pendingInboundDate, "yyyy-MM-dd"),
      });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [pendingOutboundDate, pendingInboundDate]);

  // Clear stale picks once the URL-driven search criteria actually changes (i.e.
  // after a real navigation completes), so a previous failed attempt's picks don't
  // leak into the next "still no results" render.
  useEffect(() => {
    setPendingOutboundDate(undefined);
    setPendingInboundDate(undefined);
  }, [searchData.date, searchData.returnDate]);

  const {
    data: results,
    isLoading,
    error,
  } = useQuery<any>({
    queryKey: ["search", searchData],
    queryFn: async (): Promise<any> => {
      const payload: any = {
        originStationId: searchData.originStationId,
        destinationStationId: searchData.destinationStationId,
        date: searchData.date,
        adultCount: searchData.adultCount,
        childCount: searchData.childCount,
        nationality: searchData.nationality,
        journeyType: searchData.journeyType,
      };

      if (searchData.journeyType === "ROUND_TRIP" && searchData.returnDate) {
        payload.returnDate = searchData.returnDate;
      }

      const response = (await apiClient.post("/search", payload)) as any;

      return response;
    },
    enabled: !!searchData.originStationId && !!searchData.destinationStationId,
    staleTime: 0,
    gcTime: 0,
  });

  const isRoundTrip = searchData.journeyType === "ROUND_TRIP";

  // Handle both response formats:
  // 1. One-way: response can be array of schedules OR object with journeyType and outbound
  // 2. Round-trip: response has journeyType, outbound, inbound properties
  let outboundSchedules: Schedule[] = [];
  let inboundSchedules: Schedule[] = [];

  if (results) {
    if (results.journeyType === "ROUND_TRIP") {
      // Round trip response format
      outboundSchedules = results.outbound || [];
      inboundSchedules = results.inbound || [];
    } else if (results.journeyType === "ONE_WAY" && results.outbound) {
      // One-way response format with outbound array
      outboundSchedules = results.outbound || [];
    } else if (Array.isArray(results)) {
      // One-way response format (direct array of schedules)
      outboundSchedules = results;
    } else if (results.data && Array.isArray(results.data)) {
      // Fallback: wrapped in data property
      outboundSchedules = results.data;
    }
  }

  // Alternatives are surfaced whenever a leg returns no exact-date results.
  const alternativeOutbound: Schedule[] =
    !!results && outboundSchedules.length === 0
      ? results?.alternativeOutbound || results?.outboundAlternatives || []
      : [];
  const alternativeInbound: Schedule[] =
    isRoundTrip && !!results && inboundSchedules.length === 0
      ? results?.alternativeInbound || results?.inboundAlternatives || []
      : [];
  const isOneWayNoOutbound =
    !isRoundTrip && !!results && outboundSchedules.length === 0;
  // Round-trip: show results view if either leg has exact results OR alternatives.
  // One-way: need at least one outbound result.
  const hasResults = isRoundTrip
    ? outboundSchedules.length > 0 ||
      alternativeOutbound.length > 0 ||
      inboundSchedules.length > 0 ||
      alternativeInbound.length > 0
    : outboundSchedules.length > 0;

  const handleSelectCoachType = (
    scheduleId: string,
    coachTypeId: string,
    coachTypeCode: string,
    coachTypeName: string,
    seatClassName: string,
  ) => {
    setSelectedCoachTypes((prev) => ({
      ...prev,
      [scheduleId]: {
        id: coachTypeId,
        code: coachTypeCode,
        name: coachTypeName,
        seatClassName,
      },
    }));
  };

  const handleSelect = (schedule: Schedule, isOutbound: boolean = false) => {
    const scheduleId = schedule.scheduleId || schedule.id || "";
    const selectedCoachType = selectedCoachTypes[scheduleId];

    if (!selectedCoachType) {
      alert("Please select a coach type before continuing");
      return;
    }

    // Find the coach type to get pricing info
    const coachType = schedule.coachTypes?.find(
      (ct) => ct.coachTypeCode === selectedCoachType.code,
    );
    // Use displayAmountMinor (passenger's currency) so stored fare matches what the card showed.
    const minFare = coachType?.classes.length
      ? Math.min(...coachType.classes.map((c) => c.displayAmountMinor ?? c.baseFareMinor))
      : 0;
    const fareCurrency = displayCurrencyCode;

    const hours = Math.floor((schedule.durationMinutes || 0) / 60);
    const minutes = (schedule.durationMinutes || 0) % 60;
    const durationStr = `${hours}h ${minutes}m`;

    const scheduleData = {
      id: scheduleId,
      trainNumber: schedule.trainNumber,
      origin: schedule.origin?.name || "Origin",
      destination: schedule.destination?.name || "Destination",
      originStationId: schedule.origin?.id || schedule.originStationId || "",
      destinationStationId:
        schedule.destination?.id || schedule.destinationStationId || "",
      departureTime: schedule.departureAt || schedule.departureTime || "",
      arrivalTime: schedule.arrivalAt || schedule.arrivalTime || "",
      duration: durationStr,
      baseFareAdult: minFare,
      baseFareChild: minFare,
      displayCurrency: fareCurrency,
      selectedSeatClass: selectedCoachType.name,
      selectedSeatClassName: selectedCoachType.name,
      selectedCoachTypeId: selectedCoachType.id,
      selectedCoachTypeCode: selectedCoachType.code,
      selectedCoachTypeName: selectedCoachType.name,
      seatClassName:
        (selectedCoachType as any).seatClassName || selectedCoachType.name,
      // Retained so the seat map's coach preview can price a switch to a different
      // coach type without needing a fresh API call.
      coachTypes: schedule.coachTypes || [],
    };

    // Extract the actual date from the schedule (YYYY-MM-DD)
    const scheduleDate = schedule.departureAt
      ? schedule.departureAt.slice(0, 10)
      : null;

    // For round trip, store outbound and advance to inbound step
    if (isRoundTrip && isOutbound) {
      setOutboundScheduleData(scheduleData);
      setOutboundSchedule(scheduleData);
      if (scheduleDate) {
        setEffectiveDepartureDate(scheduleDate);
        if (searchCriteria && scheduleDate !== searchCriteria.departureDate) {
          setSearchCriteria({ ...searchCriteria, departureDate: scheduleDate });
        }
      }
      setClassModal(null);
      setRoundTripStep("inbound");
      window.scrollTo({ top: 0, behavior: "smooth" });
      return;
    }

    // For round trip inbound, proceed with both schedules
    if (isRoundTrip && !isOutbound) {
      if (scheduleDate) {
        setEffectiveReturnDate(scheduleDate);
        if (searchCriteria && scheduleDate !== searchCriteria.returnDate) {
          setSearchCriteria({ ...searchCriteria, returnDate: scheduleDate });
        }
      }
      // Mirror the outbound's coachTypes (fares) onto the inbound schedule so the
      // return seat selection page shows the same prices as the outbound leg.
      const inboundScheduleData = outboundScheduleData
        ? {
            ...scheduleData,
            baseFareAdult: outboundScheduleData.baseFareAdult,
            baseFareChild: outboundScheduleData.baseFareChild,
            coachTypes: outboundScheduleData.coachTypes,
          }
        : scheduleData;
      setInboundSchedule(inboundScheduleData);
      setSelectedSchedule(outboundScheduleData); // Set primary as outbound
    } else {
      // For one-way
      if (scheduleDate) {
        setEffectiveDepartureDate(scheduleDate);
        if (searchCriteria && scheduleDate !== searchCriteria.departureDate) {
          setSearchCriteria({ ...searchCriteria, departureDate: scheduleDate });
        }
      }
      setSelectedSchedule(scheduleData);
    }

    router.push("/booking/auth-check");
  };

  // Shared "Choose Your Coach" drawer — used by both the normal results view and the
  // Alternative Travel Options fallback, so selecting an alternative opens the exact
  // same coach-type picker as a normal schedule.
  const renderClassModal = () => {
    if (!classModal) return null;

    const scheduleId = classModal.scheduleId || classModal.id || "";
    const selectedCoachType = selectedCoachTypes[scheduleId];
    const isOutbound = (classModal as any).isOutbound;
    // Dining coaches aren't bookable seat/bed classes — exclude them from selection.
    const coachTypes = (classModal.coachTypes || []).filter(
      (ct: any) => ct.coachTypeCode !== "DPC",
    );

    return (
      <>
        <div
          className="fixed inset-0 z-[99] bg-black/50 backdrop-blur-sm"
          onClick={() => setClassModal(null)}
        />
        <div
          className="fixed inset-y-0 right-0 z-[100] w-full sm:w-[680px] lg:w-[95vw] xl:w-[90vw] 2xl:w-[85vw] max-w-[1400px] bg-white dark:bg-gray-900 shadow-2xl flex flex-col"
          style={{
            animation: "drawer-slide-in 0.3s cubic-bezier(0.22,1,0.36,1)",
          }}
        >
          <div className="flex items-center justify-between px-6 py-5 border-b border-gray-100 dark:border-gray-800 flex-shrink-0">
            <div>
              <h2 className="text-lg font-bold text-gray-900 dark:text-white">
                Choose Your Coach
              </h2>
              <p className="text-xs text-gray-500 dark:text-gray-400 mt-1 flex items-center gap-1.5">
                <Train className="w-3.5 h-3.5" />
                <span className="font-medium">{classModal.trainNumber}</span>
                <span className="text-gray-400">·</span>
                <span>
                  {classModal.origin?.name} → {classModal.destination?.name}
                </span>
              </p>
            </div>
            <button
              type="button"
              onClick={() => setClassModal(null)}
              className="w-10 h-10 flex items-center justify-center rounded-full hover:bg-gray-100 dark:hover:bg-gray-800 transition-all"
              aria-label="Close"
            >
              <X className="w-5 h-5 text-gray-500" />
            </button>
          </div>

          <div className="flex-1 overflow-y-auto px-6 py-4">
            {coachTypes.length > 0 ? (
              <div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-4 pt-2">
                {coachTypes.map((coachType: any, index: number) => {
                  const isSelected =
                    selectedCoachType?.id === coachType.coachTypeId;
                  const minPrice = coachType.classes.length
                    ? Math.min(
                        ...coachType.classes.map((c: any) => c.displayAmountMinor ?? c.baseFareMinor),
                      )
                    : 0;
                  const coachCurrency = displayCurrencyCode;
                  const CoachIcon = getCoachIcon(coachType.coachTypeName);

                  const selectThisCoach = () =>
                    handleSelectCoachType(
                      scheduleId,
                      coachType.coachTypeId,
                      coachType.coachTypeCode,
                      coachType.coachTypeName,
                      coachType.classes?.[0]?.name ||
                        coachType.coachTypeName,
                    );

                  return (
                    <div
                      key={coachType.coachId}
                      data-testid="coach-option"
                      role="button"
                      tabIndex={0}
                      onClick={selectThisCoach}
                      onKeyDown={(e) => {
                        if (e.key === "Enter" || e.key === " ") {
                          e.preventDefault();
                          selectThisCoach();
                        }
                      }}
                      className={`group relative w-full p-5 rounded-2xl border-2 text-left transition-all duration-200 cursor-pointer ${
                        isSelected
                          ? "border-primary bg-gradient-to-br from-primary/8 to-primary/3 dark:from-primary/15 dark:to-primary/5 shadow-lg shadow-primary/20 scale-[1.02]"
                          : "border-gray-200 dark:border-gray-700 shadow-sm hover:border-primary/40 hover:shadow-md hover:scale-[1.01] bg-white dark:bg-gray-800/50"
                      }`}
                      style={{
                        animation: `fade-in-up 0.3s ease-out ${index * 0.1}s both`,
                      }}
                    >
                      {/* Radio indicator — top-right, persistent (not hover-only) so the
                          card's selection state is clear on touch too. */}
                      <span
                        className={`absolute top-4 right-4 w-5 h-5 rounded-full border-2 flex items-center justify-center flex-shrink-0 transition-all ${
                          isSelected
                            ? "border-primary"
                            : "border-gray-300 dark:border-gray-600 group-hover:border-primary/50"
                        }`}
                      >
                        {isSelected && (
                          <span className="w-2.5 h-2.5 rounded-full bg-primary animate-scale-in" />
                        )}
                      </span>

                      <div className="flex flex-col">
                        <div className="flex items-start gap-4 pr-2">
                          <div
                            className={`w-12 h-12 rounded-xl flex items-center justify-center flex-shrink-0 transition-all ${
                              isSelected
                                ? "bg-primary/15 dark:bg-primary/25 shadow-inner"
                                : "bg-gray-100 dark:bg-gray-700 group-hover:bg-primary/10"
                            }`}
                          >
                            <CoachIcon
                              className={`w-6 h-6 transition-colors ${
                                isSelected
                                  ? "text-primary"
                                  : "text-gray-600 dark:text-gray-400 group-hover:text-primary"
                              }`}
                            />
                          </div>

                          <div className="flex-1 min-w-0">
                            <div className="flex items-start justify-between gap-2 mb-2">
                              <div>
                                <h3 className="font-bold text-base text-gray-900 dark:text-white leading-tight">
                                  {coachType.coachTypeName}
                                </h3>
                              </div>
                            </div>

                            <div className="mt-3">
                              <div className="flex items-baseline gap-1">
                                <span className="text-xs text-gray-500 dark:text-gray-400 font-medium">
                                  From
                                </span>
                                <span
                                  className={`text-2xl font-bold tracking-tight ${
                                    isSelected
                                      ? "text-primary"
                                      : "text-gray-900 dark:text-white"
                                  }`}
                                >
                                  {formatFare(minPrice, coachCurrency)}
                                </span>
                              </div>
                            </div>
                          </div>
                        </div>

                        {coachType.classes.length > 0 && (
                          <div className="mt-4 pt-4 border-t border-gray-200/60 dark:border-gray-700/60">
                            <div className="flex items-center justify-between mb-3">
                              <p className="text-xs font-bold text-gray-700 dark:text-gray-300 uppercase tracking-wider">
                                Class Options
                              </p>
                              {coachType.classes.some((c: any) => c.available != null) && (
                                <span className="text-xs text-gray-500 dark:text-gray-400 font-medium">
                                  {coachType.classes.reduce((sum: number, c: any) => sum + (c.available ?? 0), 0)} seats left
                                </span>
                              )}
                            </div>
                            <div className="space-y-2.5">
                              {coachType.classes.map(
                                (cls: any, idx: number) => (
                                  <div
                                    key={idx}
                                    className="flex items-center justify-between py-2 px-3 rounded-lg bg-gray-50/80 dark:bg-gray-800/40"
                                  >
                                    <div className="flex items-center gap-2.5">
                                      <CoachIcon className="w-3.5 h-3.5 text-gray-500 dark:text-gray-400" />
                                      <div className="flex flex-col">
                                        <span className="text-sm font-medium text-gray-700 dark:text-gray-300">
                                          {cls.name}
                                        </span>
                                        {cls.available != null && (
                                          <span
                                            className={`text-[11px] font-medium ${
                                              cls.available === 0
                                                ? "text-red-500"
                                                : cls.available <= 3
                                                  ? "text-amber-600 dark:text-amber-400"
                                                  : "text-gray-400 dark:text-gray-500"
                                            }`}
                                          >
                                            {cls.available === 0
                                              ? "Fully booked"
                                              : `${cls.available} seat${cls.available === 1 ? "" : "s"} left`}
                                          </span>
                                        )}
                                      </div>
                                    </div>
                                    <div className="flex items-baseline gap-1">
                                      <span className="text-base font-bold tabular-nums text-gray-900 dark:text-white">
                                        {((cls.displayAmountMinor ?? cls.baseFareMinor) / 100).toFixed(2)}
                                      </span>
                                      <span className="text-xs text-gray-500 dark:text-gray-400 font-medium ml-1">
                                        {coachCurrency}
                                      </span>
                                    </div>
                                  </div>
                                ),
                              )}
                            </div>
                          </div>
                        )}

                        {/* Note — only shown while unselected; once picked, the Continue
                            button below takes its place. */}
                        {!isSelected && (
                          <p className="mt-4 pt-3 border-t border-gray-200/60 dark:border-gray-700/60 text-xs text-gray-400 dark:text-gray-500 italic text-center">
                            Click to select this coach
                          </p>
                        )}

                        {/* Continue only appears on the card the user has actually picked —
                            a real nested button (the outer card is a div, not a button, so
                            this doesn't create invalid/ambiguous nested-button behavior). */}
                        {isSelected && (
                          <button
                            type="button"
                            data-testid="continue-passenger-details"
                            onClick={(e) => {
                              e.stopPropagation();
                              handleSelect(classModal, isOutbound);
                            }}
                            className="btn-primary w-full mt-3 text-sm active:scale-[0.98]"
                          >
                            <span>
                              {isRoundTrip && isOutbound
                                ? "Continue to Return Journey"
                                : "Continue to Passenger Details"}
                            </span>
                            <ArrowRight className="w-4 h-4" />
                          </button>
                        )}
                      </div>
                    </div>
                  );
                })}
              </div>
            ) : (
              <div className="flex flex-col items-center justify-center py-16 text-center">
                <div className="w-16 h-16 bg-gray-100 dark:bg-gray-800 rounded-full flex items-center justify-center mb-4">
                  <Train className="w-8 h-8 text-gray-400" />
                </div>
                <p className="text-gray-500 dark:text-gray-400 text-sm">
                  No coach types available for this journey
                </p>
              </div>
            )}
          </div>
        </div>
        <style>{`
          @keyframes drawer-slide-in{from{transform:translateX(100%)}to{transform:translateX(0)}}
          @keyframes fade-in-up{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}
          @keyframes scale-in{from{transform:scale(0)}to{transform:scale(1)}}
        `}</style>
      </>
    );
  };

  const renderScheduleCard = (
    schedule: Schedule,
    isOutbound: boolean = false,
    isAlternative: boolean = false,
  ) => {
    const scheduleId = schedule.scheduleId || schedule.id || "";
    const selectedCoachType = selectedCoachTypes[scheduleId];

    // Calculate lowest fare and display currency from coach types / faresByClass.
    // Prefer displayAmountMinor (passenger's own currency) over baseFareMinor (ETB internal).
    let lowestFare = null;
    const displayCurrency = displayCurrencyCode;
    if (schedule.coachTypes?.length) {
      const allClasses = schedule.coachTypes.flatMap((ct) => ct.classes);
      const allFares = allClasses
        .map((c) => c.displayAmountMinor ?? c.baseFareMinor)
        .filter((f) => f > 0);
      lowestFare = allFares.length ? Math.min(...allFares) : null;
    } else if (schedule.faresByClass?.length) {
      lowestFare = Math.min(
        ...schedule.faresByClass
          .map((f) => f.baseFareMinor)
          .filter((f) => f > 0),
      );
    } else if (schedule.combinedMinFareDisplay) {
      lowestFare = schedule.combinedMinFareDisplay;
    }
    const hours = Math.floor((schedule.durationMinutes || 0) / 60);
    const minutes = (schedule.durationMinutes || 0) % 60;
    const durationStr = `${hours}h ${minutes}m`;
    const departureDate = schedule.departureAt
      ? new Date(schedule.departureAt)
      : null;
    const arrivalDate = schedule.arrivalAt
      ? new Date(schedule.arrivalAt)
      : null;
    const isNextDay =
      departureDate &&
      arrivalDate &&
      departureDate.toDateString() !== arrivalDate.toDateString();

    return (
      <div
        key={scheduleId}
        className={`card ${isAlternative ? "border-2 border-amber-200 dark:border-amber-800/60" : ""}`}
      >
        {isAlternative && (
          <div className="flex flex-wrap items-center gap-2 mb-4">
            <span className="inline-flex items-center gap-1.5 text-xs font-semibold px-2.5 py-1 rounded-full bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-300">
              <Calendar className="w-3.5 h-3.5" />
              Different date —{" "}
              {schedule.departureAt
                ? format(toZonedDate(new Date(schedule.departureAt)), "EEEE, MMMM d, yyyy")
                : "N/A"}
            </span>
            <span
              className={`inline-flex items-center gap-1.5 text-xs font-semibold px-2.5 py-1 rounded-full ${
                schedule.hasAvailability
                  ? "bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300"
                  : "bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300"
              }`}
            >
              {schedule.hasAvailability ? "Seats available" : "Fully booked"}
            </span>
          </div>
        )}
        <div className="flex flex-col lg:flex-row lg:items-center gap-6">
          <div className="flex-1">
            <div className="flex items-center gap-3 mb-4">
              <div className="w-10 h-10 bg-blue-100 dark:bg-blue-900/30 rounded-lg flex items-center justify-center flex-shrink-0">
                <Clock className="w-5 h-5 text-primary" />
              </div>
              <div>
                <div className="font-bold text-lg text-gray-900 dark:text-gray-100">
                  {schedule.trainNumber}
                </div>
                <div className="text-sm text-gray-600 dark:text-gray-400">
                  {schedule.trainName || "Express Service"}
                </div>
              </div>
            </div>

            <div className="flex items-center gap-2 md:gap-4">
              <div className="text-center">
                <div className="text-xl md:text-3xl font-bold text-gray-900 dark:text-gray-100 whitespace-nowrap">
                  {schedule.departureAt
                    ? formatTime(schedule.departureAt)
                    : "--:--"}
                </div>
                <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
                  {schedule.departureAt
                    ? `${format(toZonedDate(new Date(schedule.departureAt)), "MMM d")} · ${getTimePeriod(schedule.departureAt)}`
                    : ""}
                </div>
                <div className="text-sm text-gray-600 dark:text-gray-400 mt-1">
                  {schedule.origin?.name || "Origin"}
                </div>
              </div>

              <div className="flex-1 min-w-0 flex flex-col items-center">
                <div className="flex items-center gap-1 md:gap-2 mb-2 text-xs md:text-sm text-gray-600 dark:text-gray-400 whitespace-nowrap">
                  <Clock className="w-3.5 h-3.5 md:w-4 md:h-4 flex-shrink-0" />
                  <span>{durationStr}</span>
                </div>
                <div className="w-full h-0.5 bg-gray-200 dark:bg-gray-700 relative">
                  <div className="absolute left-0 top-1/2 -translate-y-1/2 w-2 h-2 bg-primary rounded-full" />
                  <div className="absolute right-0 top-1/2 -translate-y-1/2 w-2 h-2 bg-primary rounded-full" />
                </div>
                {schedule.stops && schedule.stops.length > 0 && (
                  <div className="flex items-center gap-1 mt-2 text-xs md:text-sm text-gray-600 dark:text-gray-400 whitespace-nowrap">
                    <MapPin className="w-3.5 h-3.5 md:w-4 md:h-4 flex-shrink-0" />
                    <span>{schedule.stops.length - 2} stops</span>
                  </div>
                )}
              </div>

              <div className="text-center">
                <div className="text-xl md:text-3xl font-bold text-gray-900 dark:text-gray-100 whitespace-nowrap">
                  {schedule.arrivalAt
                    ? formatTime(schedule.arrivalAt)
                    : "--:--"}
                </div>
                <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5 flex items-center justify-center gap-1">
                  <span>
                    {schedule.arrivalAt
                      ? `${format(toZonedDate(new Date(schedule.arrivalAt)), "MMM d")} · ${getTimePeriod(schedule.arrivalAt)}`
                      : ""}
                  </span>
                  {isNextDay && (
                    <span className="text-orange-500 font-medium">(+1)</span>
                  )}
                </div>
                <div className="text-sm text-gray-600 dark:text-gray-400 mt-1">
                  {schedule.destination?.name || "Destination"}
                </div>
              </div>
            </div>
          </div>

          <div className="lg:border-l dark:border-gray-700 lg:pl-6 lg:min-w-[220px]">
            <div className="text-center lg:text-right">
              <div className="text-sm text-gray-600 dark:text-gray-400 mb-1">
                Starting from
              </div>
              <div className="text-3xl font-bold text-primary">
                {lowestFare ? formatFare(lowestFare, displayCurrency) : "N/A"}
              </div>
              <div className="text-xs text-gray-500 dark:text-gray-400 mt-1 mb-4">
                per adult
              </div>
              {selectedCoachType && (
                <p className="text-xs text-primary font-semibold mb-2">
                  {selectedCoachType.name} selected
                </p>
              )}
              <button
                data-testid="result-select-btn"
                onClick={() =>
                  setClassModal({ ...schedule, isOutbound } as any)
                }
                disabled={isAlternative && schedule.hasAvailability === false}
                className="btn-secondary w-full flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
              >
                {isAlternative && schedule.hasAvailability === false
                  ? "Unavailable"
                  : selectedCoachType
                    ? "Change"
                    : "Select"}
              </button>
            </div>
          </div>
        </div>

        {schedule.coachTypes && schedule.coachTypes.length > 0 && (
          <div className="mt-4 pt-4 border-t border-gray-100 dark:border-gray-800 flex flex-wrap gap-2">
            {schedule.coachTypes
              .filter((ct: any) => ct.coachTypeCode !== "DPC")
              .map((ct: any, idx: number) => {
                const CoachIcon = getCoachIcon(ct.coachTypeName);
                // Only classes that actually reported a count contribute — if none of
                // them did (API didn't return `available` for this coach type), there's
                // nothing honest to show, so the count is omitted rather than shown as 0.
                const hasAvailabilityData = ct.classes.some(
                  (c: any) => c.available != null,
                );
                const available = ct.classes.reduce(
                  (sum: number, c: any) => sum + (c.available ?? 0),
                  0,
                );
                return (
                  <span
                    key={idx}
                    className={`inline-flex items-center gap-1.5 text-xs font-medium px-2.5 py-1 rounded-full ${
                      !hasAvailabilityData
                        ? "bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400"
                        : available === 0
                          ? "bg-red-50 dark:bg-red-900/20 text-red-500 dark:text-red-400"
                          : available <= 3
                            ? "bg-amber-50 dark:bg-amber-900/20 text-amber-600 dark:text-amber-400"
                            : "bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400"
                    }`}
                  >
                    <CoachIcon className="w-3.5 h-3.5 flex-shrink-0" />
                    {ct.coachTypeName}
                    {hasAvailabilityData && (
                      <span className="font-semibold">
                        {available === 0 ? "Full" : `${available} left`}
                      </span>
                    )}
                  </span>
                );
              })}
          </div>
        )}
      </div>
    );
  };

  if (isLoading) {
    return (
      <div className="booking-page">
        <div className="container mx-auto px-4">
          <div className="max-w-6xl mx-auto">
            {/* Progress Header */}
            <div className="mb-8">
              <div className="card p-6">
                <div className="flex items-center gap-4">
                  <div className="relative">
                    <div className="w-12 h-12 rounded-full border-4 border-primary/20 border-t-primary animate-spin" />
                  </div>
                  <div className="flex-1">
                    <h2 className="text-xl font-bold text-gray-900 dark:text-white mb-1">
                      Searching for trains...
                    </h2>
                    <p className="text-sm text-gray-600 dark:text-gray-400">
                      Finding the best options for your journey
                    </p>
                  </div>
                </div>
                {/* Progress bar */}
                <div className="mt-4 h-2 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
                  <div
                    className="h-full bg-primary rounded-full"
                    style={{
                      animation: "progressBar 2s ease-in-out infinite",
                    }}
                  />
                </div>
              </div>
            </div>

            {/* Skeleton Cards */}
            <div className="space-y-4">
              {[1, 2, 3].map((i) => (
                <div key={i} className="card animate-pulse">
                  <div className="flex flex-col lg:flex-row lg:items-center gap-6">
                    <div className="flex-1">
                      {/* Train info skeleton */}
                      <div className="flex items-center gap-3 mb-4">
                        <div
                          className="w-10 h-10 bg-gray-200 dark:bg-gray-700 rounded-lg"
                          style={{
                            animation: "shimmer 1.5s ease-in-out infinite",
                          }}
                        />
                        <div className="flex-1 space-y-2">
                          <div
                            className="h-5 bg-gray-200 dark:bg-gray-700 rounded w-24"
                            style={{
                              animation: "shimmer 1.5s ease-in-out infinite",
                            }}
                          />
                          <div
                            className="h-4 bg-gray-200 dark:bg-gray-700 rounded w-32"
                            style={{
                              animation: "shimmer 1.5s ease-in-out infinite",
                            }}
                          />
                        </div>
                      </div>

                      {/* Time and route skeleton */}
                      <div className="flex items-center gap-4">
                        <div className="text-center space-y-2">
                          <div
                            className="h-8 bg-gray-200 dark:bg-gray-700 rounded w-16"
                            style={{
                              animation: "shimmer 1.5s ease-in-out infinite",
                            }}
                          />
                          <div
                            className="h-3 bg-gray-200 dark:bg-gray-700 rounded w-12"
                            style={{
                              animation: "shimmer 1.5s ease-in-out infinite",
                            }}
                          />
                          <div
                            className="h-4 bg-gray-200 dark:bg-gray-700 rounded w-20"
                            style={{
                              animation: "shimmer 1.5s ease-in-out infinite",
                            }}
                          />
                        </div>

                        <div className="flex-1 flex flex-col items-center">
                          <div
                            className="h-4 bg-gray-200 dark:bg-gray-700 rounded w-16 mb-2"
                            style={{
                              animation: "shimmer 1.5s ease-in-out infinite",
                            }}
                          />
                          <div
                            className="w-full h-0.5 bg-gray-200 dark:bg-gray-700 relative"
                            style={{
                              animation: "shimmer 1.5s ease-in-out infinite",
                            }}
                          >
                            <div className="absolute left-0 top-1/2 -translate-y-1/2 w-2 h-2 bg-gray-300 dark:bg-gray-600 rounded-full" />
                            <div className="absolute right-0 top-1/2 -translate-y-1/2 w-2 h-2 bg-gray-300 dark:bg-gray-600 rounded-full" />
                          </div>
                          <div
                            className="h-4 bg-gray-200 dark:bg-gray-700 rounded w-12 mt-2"
                            style={{
                              animation: "shimmer 1.5s ease-in-out infinite",
                            }}
                          />
                        </div>

                        <div className="text-center space-y-2">
                          <div
                            className="h-8 bg-gray-200 dark:bg-gray-700 rounded w-16"
                            style={{
                              animation: "shimmer 1.5s ease-in-out infinite",
                            }}
                          />
                          <div
                            className="h-3 bg-gray-200 dark:bg-gray-700 rounded w-12"
                            style={{
                              animation: "shimmer 1.5s ease-in-out infinite",
                            }}
                          />
                          <div
                            className="h-4 bg-gray-200 dark:bg-gray-700 rounded w-20"
                            style={{
                              animation: "shimmer 1.5s ease-in-out infinite",
                            }}
                          />
                        </div>
                      </div>
                    </div>

                    <div className="lg:border-l dark:border-gray-700 lg:pl-6 lg:min-w-[220px]">
                      <div className="text-center lg:text-right space-y-3">
                        <div
                          className="h-4 bg-gray-200 dark:bg-gray-700 rounded w-24 mx-auto lg:ml-auto"
                          style={{
                            animation: "shimmer 1.5s ease-in-out infinite",
                          }}
                        />
                        <div
                          className="h-10 bg-gray-200 dark:bg-gray-700 rounded w-32 mx-auto lg:ml-auto"
                          style={{
                            animation: "shimmer 1.5s ease-in-out infinite",
                          }}
                        />
                        <div
                          className="h-3 bg-gray-200 dark:bg-gray-700 rounded w-16 mx-auto lg:ml-auto"
                          style={{
                            animation: "shimmer 1.5s ease-in-out infinite",
                          }}
                        />
                        <div
                          className="h-10 bg-gray-200 dark:bg-gray-700 rounded w-full"
                          style={{
                            animation: "shimmer 1.5s ease-in-out infinite",
                          }}
                        />
                      </div>
                    </div>
                  </div>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    );
  }

  if (error) {
    return (
      <div className="min-h-screen bg-gray-50 dark:bg-gray-900 flex items-center justify-center p-4">
        <div className="card max-w-md text-center">
          <div className="w-16 h-16 bg-red-100 dark:bg-red-900/30 rounded-full flex items-center justify-center mx-auto mb-4">
            <span className="text-3xl">⚠️</span>
          </div>
          <h2 className="text-xl font-bold mb-2 text-gray-900 dark:text-gray-100">
            Search Error
          </h2>
          <p className="text-gray-600 dark:text-gray-400 mb-6">
            Unable to load results. Please try again.
          </p>
          <button
            onClick={() => router.push(buildSearchUrl())}
            className="btn-primary"
          >
            Back to Search
          </button>
        </div>
      </div>
    );
  }

  if (!hasResults) {
    const isRoundTripNoResults =
      isRoundTrip &&
      !!results &&
      outboundSchedules.length === 0 &&
      inboundSchedules.length === 0 &&
      (results?.alternativeOutbound || []).length === 0 &&
      (results?.alternativeInbound || []).length === 0;
    if (isRoundTripNoResults) {
      const outboundCopy = emptyReasonCopy(results?.outboundReason, searchData.date);
      const inboundCopy = emptyReasonCopy(results?.inboundReason, searchData.returnDate || searchData.date);
      const sameReason =
        !!results?.outboundReason &&
        results?.outboundReason?.code === results?.inboundReason?.code;
      return (
        <div className="booking-page">
          <div className="container mx-auto px-4">
            <div className="max-w-6xl mx-auto">
              <div className="flex flex-col gap-2 px-4 py-3 rounded-xl bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800">
                <div className="flex items-center justify-between gap-4">
                  <div className="flex items-center gap-2.5 text-sm text-red-800 dark:text-red-300">
                    <Calendar className="w-4 h-4 flex-shrink-0" />
                    <span>
                      {sameReason
                        ? outboundCopy.message
                        : "No trains found for your selected dates or route."}
                    </span>
                  </div>
                  <button onClick={() => router.push(buildSearchUrl())} className="text-sm font-semibold text-primary hover:underline flex-shrink-0">
                    Modify search
                  </button>
                </div>
                {!sameReason && (results?.outboundReason || results?.inboundReason) && (
                  <div className="pl-6 space-y-1 text-sm text-red-800 dark:text-red-300">
                    <p>Outbound: {outboundCopy.message}</p>
                    <p>Return: {inboundCopy.message}</p>
                  </div>
                )}
              </div>
            </div>
          </div>
        </div>
      );
    }

    // Round trip, both legs empty, but at least one leg has alternative dates to
    // offer — show both date pickers together instead of forcing the user through
    // the outbound-then-return step wizard for a case we already know is doubly empty.
    const isRoundTripBothLegsEmpty =
      isRoundTrip && outboundSchedules.length === 0 && inboundSchedules.length === 0;
    if (isRoundTripBothLegsEmpty) {
      const bothCalendarsAvailable = alternativeOutbound.length > 0 && alternativeInbound.length > 0;
      const outboundValue = pendingOutboundDate ?? (searchData.date ? new Date(`${searchData.date}T00:00:00`) : undefined);
      const inboundValue = pendingInboundDate ?? (searchData.returnDate ? new Date(`${searchData.returnDate}T00:00:00`) : undefined);
      const outboundCopy = emptyReasonCopy(results?.outboundReason, searchData.date);
      const inboundCopy = emptyReasonCopy(results?.inboundReason, searchData.returnDate || searchData.date);

      return (
        <div className="booking-page">
          <div className="container mx-auto px-4">
            <div className="max-w-6xl mx-auto">
              <div className="card max-w-lg mx-auto text-center py-10 px-6">
                <div className="w-16 h-16 bg-red-100 dark:bg-red-900/30 rounded-full flex items-center justify-center mx-auto mb-5">
                  <Calendar className="w-8 h-8 text-red-500 dark:text-red-400" />
                </div>
                <h2 className="text-xl font-bold text-gray-900 dark:text-white mb-2">
                  No trains available
                </h2>
                <div className="space-y-5 text-left">
                  <div>
                    <p className="text-sm font-semibold text-gray-800 dark:text-gray-200 mb-1">
                      Outbound — {outboundCopy.title}
                    </p>
                    <p className="text-sm text-gray-600 dark:text-gray-400 mb-3">{outboundCopy.message}</p>
                    {outboundCopy.showAlternatives ? (
                      alternativeOutbound.length > 0 ? (
                        <AlternativeDatesCalendar
                          label="Outbound date"
                          alternatives={alternativeOutbound}
                          value={outboundValue}
                          minDate={new Date()}
                          onChange={(date) => {
                            if (!bothCalendarsAvailable) {
                              pushResultsWithDates({ date: format(date, "yyyy-MM-dd") });
                              return;
                            }
                            setPendingOutboundDate(date);
                            if (pendingInboundDate && pendingInboundDate < date) setPendingInboundDate(undefined);
                          }}
                        />
                      ) : (
                        <p className="text-xs text-gray-500 dark:text-gray-400">
                          No alternative outbound dates found nearby.
                        </p>
                      )
                    ) : null}
                  </div>
                  <div>
                    <p className="text-sm font-semibold text-gray-800 dark:text-gray-200 mb-1">
                      Return — {inboundCopy.title}
                    </p>
                    <p className="text-sm text-gray-600 dark:text-gray-400 mb-3">{inboundCopy.message}</p>
                    {inboundCopy.showAlternatives ? (
                      alternativeInbound.length > 0 ? (
                        <AlternativeDatesCalendar
                          label="Return date"
                          alternatives={alternativeInbound}
                          value={inboundValue}
                          minDate={pendingOutboundDate ?? (searchData.date ? new Date(`${searchData.date}T00:00:00`) : new Date())}
                          onChange={(date) => {
                            if (!bothCalendarsAvailable) {
                              pushResultsWithDates({ returnDate: format(date, "yyyy-MM-dd") });
                              return;
                            }
                            setPendingInboundDate(date);
                          }}
                        />
                      ) : (
                        <p className="text-xs text-gray-500 dark:text-gray-400">
                          No alternative return dates found nearby.
                        </p>
                      )
                    ) : null}
                  </div>
                </div>
                {bothCalendarsAvailable && pendingOutboundDate && !pendingInboundDate && (
                  <p className="text-xs text-gray-500 dark:text-gray-400 mt-4">
                    Now choose a return date to search.
                  </p>
                )}
                <button
                  onClick={() => router.push(buildSearchUrl())}
                  className="text-sm font-semibold text-primary hover:underline mt-6"
                >
                  Modify search instead
                </button>
              </div>
            </div>
          </div>
        </div>
      );
    }

    if (isOneWayNoOutbound) {
      const { title, message, showAlternatives } = emptyReasonCopy(
        results?.outboundReason,
        searchData.date,
      );
      return (
        <div className="booking-page">
          {renderClassModal()}
          <div className="container mx-auto px-4">
            <div className="max-w-6xl mx-auto">
              <div className="card max-w-lg mx-auto text-center py-10 px-6 mb-8">
                <div className="w-16 h-16 bg-red-100 dark:bg-red-900/30 rounded-full flex items-center justify-center mx-auto mb-5">
                  <Calendar className="w-8 h-8 text-red-500 dark:text-red-400" />
                </div>
                <h2 className="text-xl font-bold text-gray-900 dark:text-white mb-2">
                  {title}
                </h2>
                <p className="text-sm text-gray-600 dark:text-gray-400 mb-6">
                  {message}
                </p>
                {showAlternatives ? (
                  alternativeOutbound.length > 0 ? (
                    <AlternativeDatesCalendar
                      alternatives={alternativeOutbound}
                      value={searchData.date ? new Date(`${searchData.date}T00:00:00`) : undefined}
                      minDate={new Date()}
                      onChange={(date) => pushResultsWithDates({ date: format(date, "yyyy-MM-dd") })}
                    />
                  ) : (
                    <button
                      onClick={() => router.push(buildSearchUrl())}
                      className="btn-primary inline-flex items-center gap-2"
                    >
                      <Calendar className="w-4 h-4" />
                      Change Date
                    </button>
                  )
                ) : (
                  <button
                    onClick={() => router.push(buildSearchUrl())}
                    className="btn-primary inline-flex items-center gap-2"
                  >
                    Modify search
                  </button>
                )}
              </div>
            </div>
          </div>
        </div>
      );
    }

    return (
      <div className="booking-page">
        <div className="container mx-auto px-4">
          <div className="max-w-6xl mx-auto">
            <div className="flex items-center justify-between gap-4 px-4 py-3 rounded-xl bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700">
              <div className="flex items-center gap-2.5 text-sm text-gray-600 dark:text-gray-400">
                <Calendar className="w-4 h-4 flex-shrink-0 text-gray-400" />
                <span>No trains found matching your search. Try adjusting your dates or route.</span>
              </div>
              <button onClick={() => router.push(buildSearchUrl())} className="text-sm font-semibold text-primary hover:underline flex-shrink-0">
                Modify search
              </button>
            </div>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div className="booking-page">
      <div className="container mx-auto px-4">
        <div className="max-w-6xl mx-auto">
          {renderClassModal()}

          {promoData && (
            <div className="mb-6 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg p-4 flex items-start gap-3">
              <Check className="w-5 h-5 text-green-600 dark:text-green-400 flex-shrink-0 mt-0.5" />
              <div className="flex-1">
                <h3 className="font-semibold text-green-900 dark:text-green-200">
                  Promo code applied!
                </h3>
                <p className="text-sm text-green-800 dark:text-green-300 mt-1">
                  <span className="font-mono font-bold">{promoData.code}</span>{" "}
                  — {promoData.message}
                </p>
              </div>
            </div>
          )}

          <div className="mb-8">
            <button
              onClick={() => router.push(buildSearchUrl())}
              className="btn-ghost px-0 py-4 flex items-center gap-2"
            >
              <ChevronLeft className="w-4 h-4" />
              Modify search
            </button>
            <h1 className="section-title">Available schedules</h1>
            {isRoundTrip && (
              <div className="flex items-center gap-3 mt-4">
                <div
                  className={`flex items-center gap-2 px-4 py-2 rounded-full text-sm font-semibold transition-all ${
                    roundTripStep === "inbound"
                      ? "bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300"
                      : "bg-primary text-white shadow-md shadow-primary/30"
                  }`}
                >
                  {roundTripStep === "inbound" ? (
                    <Check className="w-3.5 h-3.5" />
                  ) : (
                    <span className="text-xs leading-none">1</span>
                  )}
                  <span>Outbound</span>
                </div>
                <div className="flex items-center gap-1">
                  <div className="w-4 h-0.5 bg-gray-300 dark:bg-gray-600" />
                  <ArrowRight className="w-3 h-3 text-gray-400" />
                  <div className="w-4 h-0.5 bg-gray-300 dark:bg-gray-600" />
                </div>
                <div
                  className={`flex items-center gap-2 px-4 py-2 rounded-full text-sm font-semibold transition-all ${
                    roundTripStep === "inbound"
                      ? "bg-primary text-white shadow-md shadow-primary/30"
                      : "bg-gray-100 dark:bg-gray-800 text-gray-400 dark:text-gray-500"
                  }`}
                >
                  <span className="text-xs leading-none">2</span>
                  <span>Return</span>
                </div>
              </div>
            )}
            <div className="hidden sm:flex flex-wrap items-center gap-4 text-gray-600 dark:text-gray-400 mt-3">
              <div className="flex items-center gap-2">
                <Calendar className="w-4 h-4" />
                <span>
                  {effectiveDepartureDate
                    ? format(new Date(`${effectiveDepartureDate}T00:00:00`), "EEEE, MMMM d, yyyy")
                    : "Date not specified"}
                </span>
              </div>
              <div className="flex items-center gap-2">
                <Users className="w-4 h-4" />
                <span>
                  {searchData.adultCount} adult(s), {searchData.childCount}{" "}
                  child(ren)
                </span>
              </div>
              {searchData.promoCode && (
                <div className="flex items-center gap-2 bg-green-50 dark:bg-green-900/30 text-green-700 dark:text-green-300 px-3 py-1 rounded-full text-sm">
                  <Gift className="w-4 h-4" />
                  <span>{searchData.promoCode}</span>
                </div>
              )}
            </div>
          </div>

          <div className="space-y-8">
            {isRoundTrip ? (
              roundTripStep === "outbound" ? (
                <div>
                  <div className="mb-4">
                    <h2 className="text-xl font-bold text-gray-900 dark:text-white flex items-center gap-2">
                      <ArrowRight className="w-5 h-5 text-primary" />
                      Select Outbound Journey
                    </h2>
                    <p className="text-sm text-gray-500 dark:text-gray-400 mt-1">
                      {effectiveDepartureDate
                        ? format(new Date(`${effectiveDepartureDate}T00:00:00`), "EEEE, MMMM d, yyyy")
                        : ""}
                    </p>
                  </div>
                  <div className="space-y-4">
                    {outboundSchedules.map((schedule: Schedule) =>
                      renderScheduleCard(schedule, true),
                    )}
                  </div>
                  {outboundSchedules.length === 0 && (
                    <div className="mt-6">
                      <div className="flex items-center gap-2.5 text-sm text-red-800 dark:text-red-300 px-4 py-3 rounded-xl bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 mb-4">
                        <Calendar className="w-4 h-4 flex-shrink-0" />
                        <span>No trains on <span className="font-semibold">{searchData.date ? format(new Date(`${searchData.date}T00:00:00`), "EEEE, MMMM d") : "your selected date"}</span>.</span>
                      </div>
                      {alternativeOutbound.length > 0 ? (
                        <AlternativeDatesCalendar
                          alternatives={alternativeOutbound}
                          value={searchData.date ? new Date(`${searchData.date}T00:00:00`) : undefined}
                          minDate={new Date()}
                          onChange={(date) => pushResultsWithDates({ date: format(date, "yyyy-MM-dd") })}
                        />
                      ) : (
                        <button onClick={() => router.push(buildSearchUrl())} className="btn-primary inline-flex items-center gap-2">
                          <Calendar className="w-4 h-4" />
                          Change dates
                        </button>
                      )}
                    </div>
                  )}
                </div>
              ) : (
                <div>
                  {outboundScheduleData && (
                    <div className="mb-6 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-xl p-4 flex items-center justify-between">
                      <div className="flex items-center gap-3">
                        <div className="w-8 h-8 bg-green-100 dark:bg-green-900/40 rounded-full flex items-center justify-center flex-shrink-0">
                          <Check className="w-4 h-4 text-green-600 dark:text-green-400" />
                        </div>
                        <div>
                          <p className="text-sm font-semibold text-green-900 dark:text-green-200">
                            Outbound journey selected
                          </p>
                          <p className="text-xs text-green-700 dark:text-green-400 mt-0.5">
                            {outboundScheduleData.origin} →{" "}
                            {outboundScheduleData.destination}
                            {outboundScheduleData.departureTime
                              ? ` · ${format(toZonedDate(new Date(outboundScheduleData.departureTime)), "EEE, MMM d, yyyy")}`
                              : ""}
                            {outboundScheduleData.selectedSeatClassName
                              ? ` · ${outboundScheduleData.selectedSeatClassName}`
                              : ""}
                          </p>
                        </div>
                      </div>
                      <button
                        onClick={() => {
                          setRoundTripStep("outbound");
                          const prevId = outboundScheduleData?.id;
                          setOutboundScheduleData(null);
                          if (prevId) {
                            setSelectedCoachTypes((prev) => {
                              const next = { ...prev };
                              delete next[prevId];
                              return next;
                            });
                          }
                        }}
                        className="text-xs font-semibold text-primary hover:underline flex-shrink-0 ml-4"
                      >
                        Change
                      </button>
                    </div>
                  )}
                  <div className="mb-4">
                    <h2 className="text-xl font-bold text-gray-900 dark:text-white flex items-center gap-2">
                      <ArrowRight className="w-5 h-5 text-primary rotate-180" />
                      Select Return Journey
                    </h2>
                    <p className="text-sm text-gray-500 dark:text-gray-400 mt-1">
                      {effectiveReturnDate
                        ? format(new Date(`${effectiveReturnDate}T00:00:00`), "EEEE, MMMM d, yyyy")
                        : ""}
                    </p>
                  </div>
                  <div className="space-y-4" id="inbound-section">
                    {inboundSchedules.map((schedule: Schedule) =>
                      renderScheduleCard(schedule, false),
                    )}
                  </div>
                  {inboundSchedules.length === 0 && (
                    <div className="mt-6">
                      <div className="flex items-center gap-2.5 text-sm text-red-800 dark:text-red-300 px-4 py-3 rounded-xl bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 mb-4">
                        <Calendar className="w-4 h-4 flex-shrink-0" />
                        <span>No trains on <span className="font-semibold">{searchData.returnDate ? format(new Date(`${searchData.returnDate}T00:00:00`), "EEEE, MMMM d") : "your selected return date"}</span>.</span>
                      </div>
                      {alternativeInbound.length > 0 ? (
                        <AlternativeDatesCalendar
                          alternatives={alternativeInbound}
                          value={searchData.returnDate ? new Date(`${searchData.returnDate}T00:00:00`) : undefined}
                          minDate={new Date(`${searchData.date}T00:00:00`)}
                          onChange={(date) => pushResultsWithDates({ returnDate: format(date, "yyyy-MM-dd") })}
                        />
                      ) : (
                        <button onClick={() => router.push(buildSearchUrl())} className="btn-primary inline-flex items-center gap-2">
                          <Calendar className="w-4 h-4" />
                          Change dates
                        </button>
                      )}
                    </div>
                  )}
                </div>
              )
            ) : (
              <div className="space-y-4">
                {outboundSchedules.map((schedule: Schedule) =>
                  renderScheduleCard(schedule, true),
                )}
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}
