import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';

export interface SearchCriteria {
  originStationId: string;
  destinationStationId: string;
  departureDate: string;
  returnDate?: string;
  tripType: 'ONE_WAY' | 'ROUND_TRIP';
  adultCount: number;
  childCount: number;
  nationality: 'ETHIOPIAN' | 'DJIBOUTIAN' | 'OTHER';
  promoCode?: string;
}

export interface PassengerDetail {
  name: string;
  dateOfBirth: string;
  nationality: string;
  faydaVerified?: boolean;
  nationalId?: string;
  faydaSub?: string;
  passportNumber?: string;
  passportCountry?: string;
  passportIssueDate?: string;
  passportExpiryDate?: string;
  passportIssuingAuthority?: string;
  idDocumentType?: string;
  isPrimaryPassenger: boolean;
  seatId?: string;
  seatNumber?: string;
  coachNumber?: string;
  // Fare for this passenger's actual assigned seat (minor units). Bed coaches price
  // Upper/Middle/Lower differently, so this can differ from the schedule's flat
  // baseFareAdult (which is only the coach type's cheapest class) — review/payment
  // should prefer this per-seat fare when it's available.
  seatFareMinor?: number;
  // Raw bed position ("lower"/"middle"/"upper") of the assigned seat, if it's a berth —
  // used to resolve this passenger's actual seat class server-side (see review page's
  // fare-breakdown request), since a shared coach-level class can't distinguish berths.
  bedPosition?: string;
  phone?: string;
  email?: string;
  gender?: string;
  // Round-trip specific seat assignments
  outboundSeatId?: string;
  outboundSeatNumber?: string;
  outboundCoachNumber?: string;
  outboundSeatFareMinor?: number;
  outboundBedPosition?: string;
  inboundSeatId?: string;
  inboundSeatNumber?: string;
  inboundCoachNumber?: string;
  inboundSeatFareMinor?: number;
  inboundBedPosition?: string;
  returnSeatId?: string;
  returnSeatNumber?: string;
}

export interface SelectedSchedule {
  id: string;
  trainNumber: string;
  origin: string;
  destination: string;
  originStationId?: string;
  destinationStationId?: string;
  departureTime: string;
  arrivalTime: string;
  duration: string;
  baseFareAdult: number;
  baseFareChild: number;
  displayCurrency: string;
  selectedSeatClass?: string;
  selectedSeatClassName?: string;
  seatClassName?: string;
  selectedCoachTypeId?: string;
  selectedCoachTypeCode?: string;
  selectedCoachTypeName?: string;
  // All coach types (with per-class fares) offered on this schedule at selection time —
  // kept so the seat map's coach preview can compute the fare difference before letting
  // a passenger switch to a different coach type.
  coachTypes?: Array<{
    coachId: string;
    coachTypeId: string;
    coachTypeName: string;
    coachTypeCode: string;
    classes: Array<{
      name: string;
      baseFareMinor: number;
      displayCurrency?: string;
      displayAmountMinor?: number;
    }>;
  }>;
}

export interface SeatHold {
  holdId: string;
  expiresAt: string;
  returnHoldId?: string;
  returnExpiresAt?: string;
}

interface BookingState {
  searchCriteria: SearchCriteria | null;
  selectedSchedule: SelectedSchedule | null;
  outboundSchedule: SelectedSchedule | null;
  inboundSchedule: SelectedSchedule | null;
  passengers: PassengerDetail[];
  seatHold: SeatHold | null;
  bookingId: string | null;
  pnr: string | null;
  // The hold id(s) the current bookingId was actually created with — lets the review
  // page detect "user came back from the payment gateway with the same booking still
  // valid" and reuse it instead of creating a duplicate booking.
  bookingHoldId: string | null;
  bookingReturnHoldId: string | null;
  selectedPaymentMethod: string | null;
  createAccount: boolean;
  passengerId: string | null;
  packageId: string | null;
  packageName: string | null;
  priceTierId: string | null;
  packageTierPriceMinor: number | null;
  packageDepartureStationId: string | null;
  packageDepartureStationName: string | null;
  // The exact total (minor units, ETB) computed on the review page — used as the
  // single source of truth on payment and confirmation pages to prevent drift.
  reviewedTotalMinor: number | null;
  // Per-passenger fare breakdown computed on the review page — guarantees line items
  // on the payment page sum to exactly reviewedTotalMinor.
  reviewedPassengerFares: Array<{ fareMinor: number; isFree: boolean; outboundFareMinor?: number; inboundFareMinor?: number }> | null;

  setSearchCriteria: (criteria: SearchCriteria) => void;
  setSelectedSchedule: (schedule: SelectedSchedule) => void;
  setOutboundSchedule: (schedule: SelectedSchedule) => void;
  setInboundSchedule: (schedule: SelectedSchedule) => void;
  setPassengers: (passengers: PassengerDetail[]) => void;
  setSeatHold: (hold: SeatHold | null) => void;
  setBookingId: (id: string) => void;
  setPNR: (pnr: string) => void;
  setBookingHoldReference: (holdId: string | null, returnHoldId?: string | null) => void;
  setPaymentMethod: (method: string) => void;
  setCreateAccount: (create: boolean) => void;
  setPassengerId: (id: string | null) => void;
  setPackageContext: (packageId: string, priceTierId: string, priceMinor: number, packageName?: string, departureStationId?: string, departureStationName?: string) => void;
  setReviewedTotal: (totalMinor: number, passengerFares: Array<{ fareMinor: number; isFree: boolean; outboundFareMinor?: number; inboundFareMinor?: number }>) => void;
  clearBooking: () => void;
}

export const useBookingStore = create<BookingState>()(persist(
  (set) => (({
      searchCriteria: null,
      selectedSchedule: null,
      outboundSchedule: null,
      inboundSchedule: null,
      passengers: [],
      seatHold: null,
      bookingId: null,
      pnr: null,
      bookingHoldId: null,
      bookingReturnHoldId: null,
      selectedPaymentMethod: null,
      createAccount: false,
      passengerId: null,
      packageId: null,
      packageName: null,
      priceTierId: null,
      packageTierPriceMinor: null,
      packageDepartureStationId: null,
      packageDepartureStationName: null,
      reviewedTotalMinor: null,
      reviewedPassengerFares: null,

      setSearchCriteria: (criteria) => set({ searchCriteria: criteria }),
      setPackageContext: (packageId, priceTierId, priceMinor, packageName, departureStationId, departureStationName) => set({ packageId, packageName: packageName ?? null, priceTierId, packageTierPriceMinor: priceMinor, packageDepartureStationId: departureStationId ?? null, packageDepartureStationName: departureStationName ?? null }),
      setSelectedSchedule: (schedule) => set({ selectedSchedule: schedule }),
      setOutboundSchedule: (schedule) => set({ outboundSchedule: schedule }),
      setInboundSchedule: (schedule) => set({ inboundSchedule: schedule }),
      setPassengers: (passengers) => set({ passengers }),
      setSeatHold: (hold) => set({ seatHold: hold }),
      setBookingId: (id) => set({ bookingId: id }),
      setPNR: (pnr) => set({ pnr }),
      setBookingHoldReference: (holdId, returnHoldId) => set({ bookingHoldId: holdId, bookingReturnHoldId: returnHoldId ?? null }),
      setPaymentMethod: (method) => set({ selectedPaymentMethod: method }),
      setCreateAccount: (create) => set({ createAccount: create }),
      setPassengerId: (id) => set({ passengerId: id }),
      setReviewedTotal: (totalMinor, passengerFares) => set({ reviewedTotalMinor: totalMinor, reviewedPassengerFares: passengerFares }),
      clearBooking: () => set({
        searchCriteria: null,
        selectedSchedule: null,
        outboundSchedule: null,
        inboundSchedule: null,
        passengers: [],
        seatHold: null,
        bookingId: null,
        pnr: null,
        bookingHoldId: null,
        bookingReturnHoldId: null,
        selectedPaymentMethod: null,
        createAccount: false,
        passengerId: null,
        packageId: null,
        packageName: null,
        priceTierId: null,
        packageTierPriceMinor: null,
        packageDepartureStationId: null,
        packageDepartureStationName: null,
        reviewedTotalMinor: null,
        reviewedPassengerFares: null,
      }),
  } as BookingState)),
  {
    name: 'booking-storage',
    storage: createJSONStorage(() => {
      if (typeof window !== 'undefined') {
        return localStorage;
      }
      return {
        getItem: () => null,
        setItem: () => {},
        removeItem: () => {},
      };
    }),
  }
));
