import type { Trip } from '~/server/utils/flightics' export type SortKey = 'price' | 'duration' | 'departure' | 'stops' interface Filters { maxPrice: number | null maxStops: number | null airlines: string[] departureTimeRange: [number, number] // hours 0-24 } function getTripDuration(trip: Trip): number { let total = 0 for (const leg of trip.legs) { for (const seg of leg.segments) { total += (seg.arrivalUtcTimestamp ?? 0) - (seg.departureUtcTimestamp ?? 0) } } return total } function getTripStops(trip: Trip): number { return trip.legs.reduce((sum, leg) => sum + Math.max(0, leg.segments.length - 1), 0) } function getTripAirlines(trip: Trip): string[] { const codes = new Set() for (const leg of trip.legs) { for (const seg of leg.segments) { if (seg.company?.code) codes.add(seg.company.code) } } return [...codes] } function getDepartureHour(trip: Trip): number { const dep = trip.legs[0]?.segments[0]?.departureDate return dep ? new Date(dep).getHours() : 0 } export function useResultFilters(trips: Ref) { const sortBy = ref('price') const filters = reactive({ maxPrice: null, maxStops: null, airlines: [], departureTimeRange: [0, 24] }) const viewMode = ref<'full' | 'compact'>('full') // Extract available airlines from results const { resolve: resolveAirline } = useAirlineNames() const availableAirlines = computed(() => { const codes = new Set() for (const trip of trips.value) { for (const leg of trip.legs) { for (const seg of leg.segments) { if (seg.company?.code) codes.add(seg.company.code) } } } return [...codes].sort().map(code => ({ code, name: resolveAirline(code) })) }) // Price range in results const priceRange = computed(() => { if (!trips.value.length) return { min: 0, max: 1000 } const prices = trips.value.map(t => t.totalCost) return { min: Math.floor(Math.min(...prices)), max: Math.ceil(Math.max(...prices)) } }) const filtered = computed(() => { let result = [...trips.value] // Filter by price if (filters.maxPrice != null) { result = result.filter(t => t.totalCost <= filters.maxPrice!) } // Filter by stops if (filters.maxStops != null) { result = result.filter(t => getTripStops(t) <= filters.maxStops!) } // Filter by airlines (exclusive: all airlines in the trip must be in the selected set) if (filters.airlines.length > 0) { result = result.filter(t => { const tripAirlines = getTripAirlines(t) return tripAirlines.every(a => filters.airlines.includes(a)) }) } // Filter by departure time if (filters.departureTimeRange[0] > 0 || filters.departureTimeRange[1] < 24) { result = result.filter(t => { const hour = getDepartureHour(t) return hour >= filters.departureTimeRange[0] && hour <= filters.departureTimeRange[1] }) } // Sort if (sortBy.value === 'price') { result.sort((a, b) => a.totalCost - b.totalCost) } else if (sortBy.value === 'departure') { result.sort((a, b) => { const aTime = a.legs[0]?.segments[0]?.departureTimestamp ?? 0 const bTime = b.legs[0]?.segments[0]?.departureTimestamp ?? 0 return aTime - bTime }) } else if (sortBy.value === 'duration') { result.sort((a, b) => getTripDuration(a) - getTripDuration(b)) } else if (sortBy.value === 'stops') { result.sort((a, b) => getTripStops(a) - getTripStops(b)) } return result }) function resetFilters() { filters.maxPrice = null filters.maxStops = null filters.airlines = [] filters.departureTimeRange = [0, 24] } const hasActiveFilters = computed(() => filters.maxPrice != null || filters.maxStops != null || filters.airlines.length > 0 || filters.departureTimeRange[0] > 0 || filters.departureTimeRange[1] < 24 ) return { sortBy, filters, viewMode, filtered, availableAirlines, priceRange, hasActiveFilters, resetFilters } }