interface BookingParams { airlineCode: string origin: string destination: string date: string // ISO date string passengers?: number } // Direct booking URL templates for major airlines // date format helpers applied per-airline const BOOKING_TEMPLATES: Record string> = { FR: p => `https://www.ryanair.com/es/es/trip/flights/select?adults=${p.passengers}&teens=0&children=0&infants=0&dateOut=${p.ymd}&originIata=${p.origin}&destinationIata=${p.destination}&isReturn=false`, U2: p => `https://www.easyjet.com/es/search?origin=${p.origin}&destination=${p.destination}&outboundDate=${p.ymd}&adults=${p.passengers}`, VY: () => `https://www.vueling.com/es/reserva-tu-vuelo/busca-tu-vuelo`, LH: p => `https://www.lufthansa.com/es/es/offer/search?origin=${p.origin}&destination=${p.destination}&departureDate=${p.ymd}&paxAdult=${p.passengers}&cabinClass=ECONOMY&tripType=O`, IB: p => `https://www.iberia.com/es/?language=es&market=ES&origin=${p.origin}&destination=${p.destination}&outbound=${p.ymd}&adults=${p.passengers}&cabin=ECONOMY`, W6: p => `https://wizzair.com/es-es#/booking/select-flight/${p.origin}/${p.destination}/${p.ymd}/null/${p.passengers}/0/0/null`, NK: p => `https://www.spirit.com/book/flights?origStation=${p.origin}&destStation=${p.destination}&date=${p.ymd}&adt=${p.passengers}&chd=0&inf=0&promoCode=&tripType=OW`, KL: p => `https://www.klm.es/search?pax=${p.passengers}:0:0:0:0:0:0:0&cabinClass=ECONOMY&connections=${p.origin}:C%3E${p.destination}:C&bookingFlow=LEISURE`, AF: p => `https://www.airfrance.es/search?pax=${p.passengers}:0:0:0:0:0:0:0&cabinClass=ECONOMY&connections=${p.origin}:C%3E${p.destination}:C&bookingFlow=LEISURE`, TK: p => `https://www.turkishairlines.com/es-es/flights/?origin=${p.origin}&destination=${p.destination}&departureDate=${p.ymd}&adult=${p.passengers}&child=0&infant=0&tripType=O`, AA: p => `https://www.aa.com/booking/find-flights?origin=${p.origin}&destination=${p.destination}&departureDate=${p.ymd}&pax=${p.passengers}&tripType=OneWay&locale=es_ES`, } interface AirlineData { website: string | null bookingUrl: string | null bookingUrlTemplate: string | null } // Airline data cache (loaded once from API) const airlineData = ref | null>(null) let loadingPromise: Promise | null = null async function loadAirlineData() { if (airlineData.value) return if (loadingPromise) return loadingPromise loadingPromise = $fetch<{ airlines: { iata: string; website: string | null; booking_url: string | null; booking_url_template: string | null }[] }>('/api/airlines') .then(res => { const map = new Map() for (const a of res.airlines) { map.set(a.iata, { website: a.website, bookingUrl: a.booking_url, bookingUrlTemplate: a.booking_url_template, }) } airlineData.value = map }) .catch(() => { airlineData.value = new Map() }) return loadingPromise } function applyTemplate(template: string, params: BookingParams, pax: number, ymd: string): string { return template .replace(/\{origin\}/gi, params.origin) .replace(/\{destination\}/gi, params.destination) .replace(/\{date\}/gi, ymd) .replace(/\{passengers\}/gi, String(pax)) } function buildGoogleFlightsUrl(p: BookingParams): string { const ymd = p.date.slice(0, 10) return `https://www.google.com/travel/flights?hl=es&curr=EUR&q=flights+from+${p.origin}+to+${p.destination}+on+${ymd}+one+way+${p.passengers}+passenger` } export function useBookingUrl() { // Start loading on first use loadAirlineData() function getBookingUrl(params: BookingParams): string { const pax = params.passengers || 1 const ymd = params.date.slice(0, 10) const d = ymd.replace(/-/g, '') // 1. Hardcoded templates (most reliable, manually verified) const hardcoded = BOOKING_TEMPLATES[params.airlineCode] if (hardcoded) { return hardcoded({ ...params, passengers: pax, d, ymd }) } const data = airlineData.value?.get(params.airlineCode) // 2. Auto-discovered template with placeholders if (data?.bookingUrlTemplate) { return applyTemplate(data.bookingUrlTemplate, params, pax, ymd) } // 3. Discovered booking page URL (no params, but lands on the right page) if (data?.bookingUrl) { return data.bookingUrl } // 4. Google Flights as universal fallback return buildGoogleFlightsUrl({ ...params, passengers: pax }) } function getAirlineWebsite(code: string): string | null { return airlineData.value?.get(code)?.website || null } return { getBookingUrl, getAirlineWebsite } }