import { computed, ComputedRef } from 'vue' import { Flight } from '@/Types/types' export interface Continent { id: number name: string code: string internal_name: string } export interface ContinentPairEntry { key: string label: string flights: Flight[] } /** Stable undirected key — always alphabetically sorted so A|B === B|A */ export function undirectedKey(a: string, b: string): string { return [a, b].sort().join('|') } /** Directed key — order preserved */ export function directedKey(dep: string, arr: string): string { return `${dep}|${arr}` } export function labelFor(a: string, b: string): string { return `${a} ↔ ${b}` } export function continentNameOf(flight: Flight, side: 'departure' | 'arrival'): string | null { const airport = side === 'departure' ? flight.departure_airport : flight.arrival_airport return airport.region?.continent?.name ?? null } export function isInternational(flight: Flight): boolean { const depCountry = flight.departure_airport.region?.country_id const arrCountry = flight.arrival_airport.region?.country_id if (depCountry == null || arrCountry == null) return true return depCountry !== arrCountry } /** Filter flights to only those that qualify for continent-pair achievements */ export function qualifyingFlights(flights: Flight[]): Flight[] { return flights.filter(flight => { const dep = continentNameOf(flight, 'departure') const arr = continentNameOf(flight, 'arrival') if (!dep || !arr) return false if (dep === arr && !isInternational(flight)) return false return true }) } // ── One-way (undirected) pairs ───────────────────────────────────────────── export function useUndirectedContinentPairs( flights: ComputedRef, continents: ComputedRef, ) { const allKeys = computed(() => { const names = continents.value.map(c => c.name).sort() const keys: string[] = [] for (let i = 0; i < names.length; i++) { for (let j = i; j < names.length; j++) { keys.push(undirectedKey(names[i], names[j])) } } return keys.sort((a, b) => { const [a1, a2] = a.split('|') const [b1, b2] = b.split('|') return labelFor(a1, a2).localeCompare(labelFor(b1, b2)) }) }) const flightsByKey = computed>(() => { const map = new Map(allKeys.value.map(k => [k, [] as Flight[]])) for (const flight of qualifyingFlights(flights.value)) { const dep = continentNameOf(flight, 'departure')! const arr = continentNameOf(flight, 'arrival')! const key = undirectedKey(dep, arr) map.get(key)?.push(flight) } return map }) const entries = computed(() => allKeys.value.map(key => { const [a, b] = key.split('|') return { key, label: labelFor(a, b), flights: flightsByKey.value.get(key) ?? [] } }) ) const completedCount = computed(() => entries.value.filter(e => e.flights.length > 0).length) const totalCount = computed(() => entries.value.length) return { entries, completedCount, totalCount } } // ── Both-ways (directed) pairs ───────────────────────────────────────────── export function useDirectedContinentPairs( flights: ComputedRef, continents: ComputedRef, ) { /** All directed keys grouped by the departure continent name */ const keysByDeparture = computed>(() => { const names = continents.value.map(c => c.name).sort() const map = new Map() for (const dep of names) { map.set(dep, names.map(arr => directedKey(dep, arr)).sort((a, b) => { const [, a2] = a.split('|') const [, b2] = b.split('|') return a2.localeCompare(b2) })) } return map }) const flightsByKey = computed>(() => { const map = new Map() for (const keys of keysByDeparture.value.values()) { for (const key of keys) map.set(key, []) } for (const flight of qualifyingFlights(flights.value)) { const dep = continentNameOf(flight, 'departure')! const arr = continentNameOf(flight, 'arrival')! const key = directedKey(dep, arr) map.get(key)?.push(flight) } return map }) /** Entries grouped by departure continent, each sorted by arrival continent name */ const entriesByDeparture = computed>(() => { const map = new Map() for (const [dep, keys] of keysByDeparture.value) { map.set(dep, keys.map(key => { const [a, b] = key.split('|') return { key, label: `${a} → ${b}`, flights: flightsByKey.value.get(key) ?? [] } })) } return map }) const departureNames = computed(() => [...keysByDeparture.value.keys()]) const completedCount = computed(() => { let count = 0 for (const entries of entriesByDeparture.value.values()) { count += entries.filter(e => e.flights.length > 0).length } return count }) const totalCount = computed(() => { let count = 0 for (const entries of entriesByDeparture.value.values()) { count += entries.length } return count }) return { entriesByDeparture, departureNames, completedCount, totalCount } }