import SwiftUI
import SwiftData
import CoreLocation

struct LiveFlightDetailSheet: View {
    let aircraft: LiveAircraft
    let openSky: OpenSkyClient
    let routeExplorer: RouteExplorerClient
    let database: AirportDatabase

    @State private var recentFlights: [OpenSkyFlight] = []
    @State private var isLoadingRoute = false
    @State private var aircraftPhoto: AircraftPhotoService.Photo?
    @State private var showingAddToHistory = false

    /// The resolved route for the current selection. Built from a cascade:
    /// scheduled flight (via route-explorer) → OpenSky history → trail-based
    /// nearest-airport inference. See `resolveRoute()`.
    @State private var resolvedRoute: ResolvedRoute?

    enum ResolvedRoute {
        /// Inline data straight off the FR24 feed (departure + arrival
        /// IATA, plus the flight number). This is the fast path — no
        /// extra network call required because FR24 already gave us
        /// these in the feed.js response.
        case fromFR24(departureIATA: String?, arrivalIATA: String?, flightIATA: String?)
        /// Real schedule match from route-explorer. Best fidelity for
        /// flights that aren't FR24-sourced.
        case scheduled(RouteFlight)
        /// OpenSky historical flight. departure + arrival from FAA tracking.
        case fromOpenSky(OpenSkyFlight, ageHours: Int)
        /// Couldn't find a flight record — inferred departure from the
        /// aircraft's trail start. Arrival unknown.
        case inferred(departureIATA: String, departureName: String?)
    }

    @Environment(\.dismiss) private var dismiss
    @Environment(\.openURL) private var openURL
    @Environment(\.modelContext) private var modelContext

    var body: some View {
        NavigationStack {
            ScrollView {
                VStack(alignment: .leading, spacing: 16) {
                    header

                    // Depart → Arrival sits directly under the callsign
                    // header — it's the single most important thing the
                    // user opened the sheet to see.
                    routeSection

                    addToHistoryButton

                    // Aircraft photo follows the route. Negative
                    // horizontal padding lets the photo break out of the
                    // 16pt content padding to be full-bleed edge-to-edge.
                    photoBanner
                        .padding(.horizontal, -16)

                    if let photo = aircraftPhoto, let credit = photo.photographer {
                        photoCredit(name: credit, link: photo.detailLink)
                    }

                    Divider()

                    Text("LIVE STATE")
                        .font(FlightTheme.label())
                        .foregroundStyle(FlightTheme.textTertiary)
                        .tracking(1)

                    liveStateGrid

                    if recentFlights.count > 1 {
                        Text("RECENT FLIGHTS")
                            .font(FlightTheme.label())
                            .foregroundStyle(FlightTheme.textTertiary)
                            .tracking(1)
                            .padding(.top, 4)

                        ForEach(recentFlights.prefix(8), id: \.self) { flight in
                            recentFlightRow(flight)
                        }
                    }

                    Text("AIRCRAFT")
                        .font(FlightTheme.label())
                        .foregroundStyle(FlightTheme.textTertiary)
                        .tracking(1)
                        .padding(.top, 4)

                    aircraftCard
                }
                .padding(16)
            }
            .background(FlightTheme.background.ignoresSafeArea())
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button { dismiss() } label: {
                        Image(systemName: "xmark")
                            .font(.subheadline.weight(.semibold))
                    }
                }
            }
            .task {
                await resolveRoute()
            }
            .task(id: aircraft.icao24) {
                aircraftPhoto = await AircraftPhotoService.shared.photo(
                    registration: aircraft.enrichment?.registration,
                    icao24: aircraft.icao24
                )
            }
        }
    }

    // MARK: - Route resolution

    /// Cascade to find departure + arrival, in order of fidelity:
    ///   1. Scheduled lookup via route-explorer (carrier + flight number)
    ///      — this is the only path that gives a real arrival airport for
    ///      an in-progress flight.
    ///   2. OpenSky `/flights/aircraft` — only landed flights; useful if
    ///      the aircraft just landed or for "last flight" context.
    ///   3. Trail-based inference — first point of the OpenSky `/tracks/all`
    ///      response → nearest airport in our local DB → "Departed from X".
    private func resolveRoute() async {
        isLoadingRoute = true
        defer { isLoadingRoute = false }

        // 0) Fast path: FR24's feed gave us departure + arrival inline.
        //    This is the common case now that FR24 is the primary feed.
        //    Skips the route-explorer network call entirely.
        if let e = aircraft.enrichment,
           e.departureIATA != nil || e.arrivalIATA != nil {
            resolvedRoute = .fromFR24(
                departureIATA: e.departureIATA,
                arrivalIATA: e.arrivalIATA,
                flightIATA: e.flightIATA
            )
            // Fire OpenSky history in the background for "recent flights".
            recentFlights = await openSky.recentFlights(icao24: aircraft.icao24)
            return
        }

        // 1) Try the scheduled lookup if we have a parseable airline + flight.
        if let scheduled = await tryScheduledLookup() {
            resolvedRoute = .scheduled(scheduled)
            // Still fetch OpenSky history in the background for the "recent
            // flights" list — but we don't need to await it.
            recentFlights = await openSky.recentFlights(icao24: aircraft.icao24)
            return
        }

        // 2) Fall back to OpenSky history.
        let flights = await openSky.recentFlights(icao24: aircraft.icao24)
        recentFlights = flights
        if let mostRecent = flights.first {
            let hoursAgo = max(0, Int(
                (Date().timeIntervalSince1970 - Double(mostRecent.lastSeen)) / 3600
            ))
            resolvedRoute = .fromOpenSky(mostRecent, ageHours: hoursAgo)
            return
        }

        // 3) Last resort: nearest-airport from the trail start.
        if let track = await openSky.track(icao24: aircraft.icao24),
           let firstPoint = track.path.first {
            let coord = CLLocationCoordinate2D(
                latitude: firstPoint.latitude,
                longitude: firstPoint.longitude
            )
            if let nearest = database.nearestAirport(to: coord, maxMiles: 30) {
                resolvedRoute = .inferred(
                    departureIATA: nearest.iata,
                    departureName: nearest.name
                )
                return
            }
        }
        resolvedRoute = nil
    }

    /// Parse the ADS-B callsign (e.g. "AAL1234") into carrier + flight number
    /// and hit route-explorer's `/schedule` endpoint. Returns the day's
    /// operating record if route-explorer indexes the carrier; nil otherwise.
    private func tryScheduledLookup() async -> RouteFlight? {
        guard let icao = aircraft.airlineICAO,
              let airline = AircraftRegistry.shared.lookup(icao: icao),
              let iata = airline.iata,
              let flightStr = aircraft.flightNumber,
              let flightNum = Int(flightStr)
        else { return nil }

        // Look across today ± yesterday — handles late-running redeyes that
        // departed on D-1 but are still airborne on D.
        let today = Date()
        let yesterday = today.addingTimeInterval(-86400)
        let results = await routeExplorer.searchSchedule(
            carrierCode: iata,
            flightNumber: flightNum,
            startDate: yesterday,
            endDate: today
        )
        guard !results.isEmpty else { return nil }

        // Pick the entry whose departure is closest to "now" (typically
        // the in-progress flight).
        return results.min { a, b in
            abs(a.departure.dateTime.timeIntervalSinceNow) <
            abs(b.departure.dateTime.timeIntervalSinceNow)
        }
    }

    // MARK: - Add-to-history button
    //
    // Lives between the route card and the photo banner — the natural
    // "I'm on this plane right now, save it" spot. Opens AddFlightView
    // pre-populated from FR24 enrichment so the user can confirm any
    // detail before it lands in their log.

    private var addToHistoryButton: some View {
        Button {
            showingAddToHistory = true
        } label: {
            HStack(spacing: 8) {
                Image(systemName: "plus.circle.fill")
                Text("Add to my flights")
                    .font(.subheadline.weight(.semibold))
            }
            .frame(maxWidth: .infinity)
            .padding(.vertical, 12)
        }
        .background(FlightTheme.accent, in: RoundedRectangle(cornerRadius: 12))
        .foregroundStyle(.white)
        .sheet(isPresented: $showingAddToHistory) {
            let store = FlightHistoryStore(context: modelContext, airportDatabase: database)
            AddFlightView(
                routeExplorer: routeExplorer,
                database: database,
                store: store,
                prefill: AddFlightView.Prefill(
                    flightDate: Date(),
                    carrierICAO: aircraft.airlineICAO,
                    carrierIATA: AircraftRegistry.shared.lookup(icao: aircraft.airlineICAO)?.iata,
                    flightNumber: aircraft.flightNumber,
                    departureIATA: aircraft.enrichment?.departureIATA,
                    arrivalIATA: aircraft.enrichment?.arrivalIATA,
                    scheduledDeparture: nil,
                    scheduledArrival: nil,
                    aircraftType: aircraft.typeCode,
                    registration: aircraft.enrichment?.registration,
                    icao24: aircraft.icao24,
                    source: "live-tap"
                )
            )
        }
    }

    // MARK: - Photo banner
    //
    // Hero image at the very top of the sheet, sourced from planespotters.
    // Hides itself entirely when no photo is available (lots of GA / cargo
    // / older airframes have no public photo). Most recent photo per
    // airframe is what planespotters serves — which means special
    // liveries surface naturally because photographers chase them first.

    @ViewBuilder
    private var photoBanner: some View {
        if let photo = aircraftPhoto {
            AsyncImage(url: photo.largeURL) { phase in
                switch phase {
                case .success(let img):
                    img.resizable().aspectRatio(contentMode: .fill)
                case .empty, .failure:
                    Rectangle().fill(FlightTheme.cardBackground)
                @unknown default:
                    Rectangle().fill(FlightTheme.cardBackground)
                }
            }
            .frame(maxWidth: .infinity)
            .frame(height: 200)
            .clipped()
        }
    }

    private func photoCredit(name: String, link: URL?) -> some View {
        HStack(spacing: 4) {
            Image(systemName: "camera.fill")
                .font(.caption2)
            Text("Photo by \(name) · planespotters.net")
                .font(.caption2)
        }
        .foregroundStyle(FlightTheme.textTertiary)
        .padding(.top, 4)
        .contentShape(Rectangle())
        .onTapGesture {
            if let link { openURL(link) }
        }
    }

    // MARK: - Header

    private var header: some View {
        VStack(alignment: .leading, spacing: 4) {
            HStack(spacing: 10) {
                if let logoURL = airlineEntry?.logoURL {
                    AsyncImage(url: logoURL) { phase in
                        switch phase {
                        case .success(let img):
                            img.resizable().scaledToFit()
                        default:
                            RoundedRectangle(cornerRadius: 8)
                                .fill(FlightTheme.accent.opacity(0.2))
                        }
                    }
                    .frame(width: 40, height: 40)
                    .clipShape(RoundedRectangle(cornerRadius: 8))
                }
                Text(aircraft.trimmedCallsign ?? aircraft.icao24)
                    .font(.title.weight(.bold).monospaced())
                    .foregroundStyle(FlightTheme.textPrimary)
                Spacer()
                statusBadge
            }
            Text(airlineDisplayName)
                .font(.subheadline)
                .foregroundStyle(FlightTheme.textSecondary)
        }
    }

    private var statusBadge: some View {
        let (text, color): (String, Color) = {
            if aircraft.onGround { return ("On ground", FlightTheme.textSecondary) }
            switch aircraft.verticalState {
            case .climbing:   return ("Climbing",   FlightTheme.onTime)
            case .descending: return ("Descending", FlightTheme.delayed)
            case .level:      return ("Cruising",   FlightTheme.accent)
            }
        }()
        return Text(text)
            .font(.caption.weight(.bold))
            .foregroundStyle(.white)
            .padding(.horizontal, 10)
            .padding(.vertical, 4)
            .background(color, in: Capsule())
    }

    // MARK: - Live state grid

    private var liveStateGrid: some View {
        VStack(spacing: 0) {
            HStack(spacing: 0) {
                statCell(label: "Altitude",
                         value: aircraft.altitudeFeet.map { "\(formatNumber($0)) ft" } ?? "—")
                statCell(label: "Speed",
                         value: aircraft.velocityKnots.map { "\($0) kt" } ?? "—")
            }
            Divider()
            HStack(spacing: 0) {
                statCell(label: "Heading",
                         value: aircraft.heading.map { "\($0)°" } ?? "—")
                statCell(label: "Vertical",
                         value: verticalDisplay)
            }
            Divider()
            HStack(spacing: 0) {
                statCell(label: "Squawk", value: aircraft.squawk ?? "—")
                statCell(label: "Updated", value: shortTime(aircraft.lastContact))
            }
        }
        .flightCard(padding: 0)
    }

    private var verticalDisplay: String {
        if aircraft.onGround { return "—" }
        switch aircraft.verticalState {
        case .climbing:   return "Climb"
        case .descending: return "Descend"
        case .level:      return "Level"
        }
    }

    private func statCell(label: String, value: String) -> some View {
        VStack(alignment: .leading, spacing: 2) {
            Text(label)
                .font(.caption2)
                .foregroundStyle(FlightTheme.textTertiary)
                .tracking(0.5)
            Text(value)
                .font(.subheadline.weight(.semibold).monospaced())
                .foregroundStyle(FlightTheme.textPrimary)
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .padding(16)
    }

    // MARK: - Route
    //
    // OpenSky's /flights/aircraft endpoint only returns *landed* flights, so
    // for a plane currently in flight we usually get nothing relevant — the
    // most recent entry would be its previous leg (often from yesterday).
    //
    // To still show something useful, we display whatever's most recent and
    // label it clearly: "In flight" if the snapshot is fresh, "Last flight"
    // if it's older, "—" only when we genuinely have nothing.

    @ViewBuilder
    private var routeSection: some View {
        if let resolved = resolvedRoute {
            VStack(alignment: .leading, spacing: 6) {
                HStack(spacing: 8) {
                    Text(headerLabel(for: resolved))
                        .font(FlightTheme.label())
                        .foregroundStyle(FlightTheme.textTertiary)
                        .tracking(1)
                    if case .scheduled = resolved {
                        Circle()
                            .fill(FlightTheme.onTime)
                            .frame(width: 6, height: 6)
                    } else if case .fromFR24 = resolved {
                        Circle()
                            .fill(FlightTheme.onTime)
                            .frame(width: 6, height: 6)
                    }
                }
                resolvedRouteCard(resolved)
            }
        } else if isLoadingRoute {
            HStack {
                ProgressView()
                Text("Resolving route…")
                    .font(.caption)
                    .foregroundStyle(FlightTheme.textSecondary)
            }
        } else {
            VStack(alignment: .leading, spacing: 6) {
                Text("ROUTE")
                    .font(FlightTheme.label())
                    .foregroundStyle(FlightTheme.textTertiary)
                    .tracking(1)
                Text("Route unavailable. This aircraft isn't in any schedule source we cover (callsign \(aircraft.trimmedCallsign ?? aircraft.icao24)).")
                    .font(.caption)
                    .foregroundStyle(FlightTheme.textSecondary)
                    .padding(12)
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .background(FlightTheme.cardBackground, in: RoundedRectangle(cornerRadius: 12))
            }
        }
    }

    private func headerLabel(for r: ResolvedRoute) -> String {
        switch r {
        case .fromFR24:
            return aircraft.onGround ? "FLIGHT (ON GROUND)" : "IN FLIGHT"
        case .scheduled:
            return aircraft.onGround ? "FLIGHT (ON GROUND)" : "IN FLIGHT"
        case .fromOpenSky(_, let hoursAgo):
            if hoursAgo < 1 { return "LAST FLIGHT · JUST LANDED" }
            if hoursAgo < 24 { return "LAST FLIGHT · \(hoursAgo)h AGO" }
            return "LAST FLIGHT · \(hoursAgo / 24)d AGO"
        case .inferred:
            return aircraft.onGround ? "ON GROUND" : "IN FLIGHT (INFERRED)"
        }
    }

    @ViewBuilder
    private func resolvedRouteCard(_ r: ResolvedRoute) -> some View {
        switch r {
        case .fromFR24(let dep, let arr, _):
            VStack(alignment: .leading, spacing: 12) {
                HStack(spacing: 16) {
                    fr24Endpoint(
                        iata: dep,
                        label: aircraft.onGround ? "From" : "Departed",
                        emptyText: "Unknown"
                    )
                    Image(systemName: "airplane")
                        .font(.title3)
                        .foregroundStyle(FlightTheme.accent)
                        .rotationEffect(.degrees(-45))
                    fr24Endpoint(
                        iata: arr,
                        label: aircraft.onGround ? "To" : "Heading to",
                        emptyText: "Unknown"
                    )
                }
            }
            .flightCard()

        case .scheduled(let f):
            VStack(alignment: .leading, spacing: 12) {
                HStack(spacing: 16) {
                    routeEndpoint(
                        code: f.departure.airportIata,
                        label: aircraft.onGround ? "From" : "Departed",
                        time: f.departure.dateTime
                    )
                    Image(systemName: "airplane")
                        .font(.title3)
                        .foregroundStyle(FlightTheme.accent)
                        .rotationEffect(.degrees(-45))
                    routeEndpoint(
                        code: f.arrival.airportIata,
                        label: aircraft.onGround ? "To" : "Heading to",
                        time: f.arrival.dateTime
                    )
                }
            }
            .flightCard()

        case .fromOpenSky(let f, _):
            VStack(alignment: .leading, spacing: 12) {
                HStack(spacing: 16) {
                    routeEndpoint(
                        code: f.estDepartureAirport,
                        label: "Departed",
                        time: f.departureDate
                    )
                    Image(systemName: "airplane")
                        .font(.title3)
                        .foregroundStyle(FlightTheme.accent)
                        .rotationEffect(.degrees(-45))
                    routeEndpoint(
                        code: f.estArrivalAirport,
                        label: "Arrived",
                        time: f.arrivalDate
                    )
                }
            }
            .flightCard()

        case .inferred(let depIata, let depName):
            VStack(alignment: .leading, spacing: 12) {
                HStack(spacing: 16) {
                    VStack(alignment: .leading, spacing: 2) {
                        Text("Departed")
                            .font(.caption2)
                            .foregroundStyle(FlightTheme.textTertiary)
                            .tracking(0.5)
                        Text(depIata)
                            .font(FlightTheme.airportCode(28))
                            .foregroundStyle(FlightTheme.textPrimary)
                        if let depName {
                            Text(depName)
                                .font(.caption2)
                                .foregroundStyle(FlightTheme.textSecondary)
                                .lineLimit(1)
                        }
                    }
                    .frame(maxWidth: .infinity, alignment: .leading)
                    Image(systemName: "airplane")
                        .font(.title3)
                        .foregroundStyle(FlightTheme.accent)
                        .rotationEffect(.degrees(-45))
                    VStack(alignment: .leading, spacing: 2) {
                        Text("Heading to")
                            .font(.caption2)
                            .foregroundStyle(FlightTheme.textTertiary)
                            .tracking(0.5)
                        Text("—")
                            .font(FlightTheme.airportCode(28))
                            .foregroundStyle(FlightTheme.textTertiary)
                        Text("Not in schedule data")
                            .font(.caption2)
                            .foregroundStyle(FlightTheme.textSecondary)
                            .lineLimit(1)
                    }
                    .frame(maxWidth: .infinity, alignment: .leading)
                }
            }
            .flightCard()
        }
    }

    /// Endpoint cell for FR24-sourced routes. Different from
    /// `routeEndpoint` because FR24 gives us IATA codes directly (no
    /// ICAO-to-IATA conversion) and no scheduled time.
    private func fr24Endpoint(iata: String?, label: String, emptyText: String) -> some View {
        let code = iata ?? ""
        let cityName: String = {
            guard let iata, let m = database.airport(byIATA: iata) else { return "" }
            return m.name
        }()
        return VStack(alignment: .leading, spacing: 2) {
            Text(label)
                .font(.caption2)
                .foregroundStyle(FlightTheme.textTertiary)
                .tracking(0.5)
            Text(code.isEmpty ? "—" : code)
                .font(FlightTheme.airportCode(28))
                .foregroundStyle(code.isEmpty ? FlightTheme.textTertiary : FlightTheme.textPrimary)
            if !cityName.isEmpty {
                Text(cityName)
                    .font(.caption2)
                    .foregroundStyle(FlightTheme.textSecondary)
                    .lineLimit(1)
            } else if code.isEmpty {
                Text(emptyText)
                    .font(.caption2)
                    .foregroundStyle(FlightTheme.textSecondary)
                    .lineLimit(1)
            }
        }
        .frame(maxWidth: .infinity, alignment: .leading)
    }

    private func routeEndpoint(code: String?, label: String, time: Date) -> some View {
        let iata = code.flatMap(icaoToIATA(_:)) ?? code ?? "—"
        let cityName: String = {
            guard let code, let m = database.airport(byIATA: icaoToIATA(code) ?? code) else { return "" }
            return m.name
        }()

        return VStack(alignment: .leading, spacing: 2) {
            Text(label)
                .font(.caption2)
                .foregroundStyle(FlightTheme.textTertiary)
                .tracking(0.5)
            Text(iata)
                .font(FlightTheme.airportCode(28))
                .foregroundStyle(FlightTheme.textPrimary)
            if !cityName.isEmpty {
                Text(cityName)
                    .font(.caption2)
                    .foregroundStyle(FlightTheme.textSecondary)
                    .lineLimit(1)
            }
            Text(shortDateTime(time))
                .font(.caption2.monospaced())
                .foregroundStyle(FlightTheme.textTertiary)
        }
        .frame(maxWidth: .infinity, alignment: .leading)
    }

    private func recentFlightRow(_ f: OpenSkyFlight) -> some View {
        let dep = f.estDepartureAirport.flatMap(icaoToIATA(_:)) ?? f.estDepartureAirport ?? "—"
        let arr = f.estArrivalAirport.flatMap(icaoToIATA(_:)) ?? f.estArrivalAirport ?? "—"
        return HStack(spacing: 12) {
            Text(dep)
                .font(.subheadline.weight(.semibold).monospaced())
                .foregroundStyle(FlightTheme.textPrimary)
                .frame(width: 56, alignment: .leading)
            Image(systemName: "arrow.right")
                .font(.caption)
                .foregroundStyle(FlightTheme.textTertiary)
            Text(arr)
                .font(.subheadline.weight(.semibold).monospaced())
                .foregroundStyle(FlightTheme.textPrimary)
                .frame(width: 56, alignment: .leading)
            Spacer()
            Text(shortDate(f.departureDate))
                .font(.caption.monospaced())
                .foregroundStyle(FlightTheme.textSecondary)
        }
        .padding(.horizontal, 12)
        .padding(.vertical, 10)
        .background(FlightTheme.cardBackground, in: RoundedRectangle(cornerRadius: 10))
    }

    // MARK: - Aircraft card

    private var aircraftCard: some View {
        VStack(spacing: 0) {
            HStack(spacing: 0) {
                statCell(label: "ICAO24", value: aircraft.icao24.uppercased())
                statCell(label: "Country", value: aircraft.originCountry.isEmpty ? "—" : aircraft.originCountry)
            }
            if let cat = aircraft.category, let name = aircraftCategoryName(cat) {
                Divider()
                HStack(spacing: 0) {
                    statCell(label: "Category", value: name)
                    statCell(label: "Position", value: shortCoord(aircraft.coordinate))
                }
            } else {
                Divider()
                HStack(spacing: 0) {
                    statCell(label: "Position", value: shortCoord(aircraft.coordinate))
                    statCell(label: "", value: "")
                }
            }
        }
        .flightCard(padding: 0)
    }

    // MARK: - Helpers

    private var airlineEntry: AircraftRegistry.Entry? {
        AircraftRegistry.shared.lookup(icao: aircraft.airlineICAO)
    }

    private var airlineDisplayName: String {
        airlineEntry?.name
            ?? aircraft.airlineICAO?.uppercased()
            ?? "Unknown"
    }

    private func formatNumber(_ n: Int) -> String {
        let f = NumberFormatter()
        f.numberStyle = .decimal
        return f.string(from: NSNumber(value: n)) ?? "\(n)"
    }

    private func shortCoord(_ c: CLLocationCoordinate2D) -> String {
        String(format: "%.2f, %.2f", c.latitude, c.longitude)
    }

    private func shortTime(_ d: Date) -> String {
        let f = DateFormatter()
        f.timeStyle = .short
        return f.string(from: d)
    }

    private func shortDate(_ d: Date) -> String {
        let f = DateFormatter()
        f.dateFormat = "MMM d"
        return f.string(from: d)
    }

    private func shortDateTime(_ d: Date) -> String {
        let f = DateFormatter()
        f.dateFormat = "MMM d, HH:mm"
        return f.string(from: d)
    }

    /// OpenSky returns 4-letter ICAO airport codes (e.g. "KDFW"). Strip the
    /// leading region letter for common 3-letter IATA codes in the US/
    /// Canada/etc. Best-effort — falls back to the raw value.
    private func icaoToIATA(_ icao: String?) -> String? {
        guard let icao else { return nil }
        let s = icao.uppercased()
        guard s.count == 4 else { return s }
        // US: KXXX, Canada: CYxx (3 chars after C), Mexico: MMxx (3 chars after M).
        if s.hasPrefix("K") { return String(s.dropFirst()) }
        if s.hasPrefix("CY") { return String(s.dropFirst()) }   // YYZ stays YYZ
        if s.hasPrefix("MM") { return String(s.dropFirst()) }
        return s
    }
}
