import SwiftUI

private enum BrowseMode: String, CaseIterable {
    case list = "List"
    case map = "Map"
}

struct AirportBrowserSheet: View {
    let service: FlightService
    let database: AirportDatabase
    let onSelect: (Airport) -> Void

    @Environment(\.dismiss) private var dismiss
    @State private var browseMode: BrowseMode = .list
    @State private var countries: [Country] = []
    @State private var isLoadingCountries = true
    @State private var countrySearch = ""
    @State private var error: String?

    var filteredCountries: [Country] {
        guard !countrySearch.isEmpty else { return countries }
        return countries.filter {
            $0.name.localizedCaseInsensitiveContains(countrySearch) ||
            $0.id.localizedCaseInsensitiveContains(countrySearch)
        }
    }

    var body: some View {
        NavigationStack {
            VStack(spacing: 0) {
                Picker("Browse Mode", selection: $browseMode) {
                    ForEach(BrowseMode.allCases, id: \.self) { mode in
                        Text(mode.rawValue)
                    }
                }
                .pickerStyle(.segmented)
                .padding()

                switch browseMode {
                case .list:
                    listContent
                case .map:
                    AirportMapView(
                        database: database,
                        service: service,
                        onSelect: { airport in
                            onSelect(airport)
                            dismiss()
                        }
                    )
                }
            }
            .navigationTitle("Browse Airports")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Cancel") { dismiss() }
                }
            }
            .task {
                await loadCountries()
            }
            .navigationDestination(for: Country.self) { country in
                CountryAirportsView(
                    country: country,
                    service: service,
                    onSelect: { airport in
                        onSelect(airport)
                        dismiss()
                    }
                )
            }
        }
    }

    @ViewBuilder
    private var listContent: some View {
        if isLoadingCountries {
            Spacer()
            ProgressView("Loading countries...")
            Spacer()
        } else if let error {
            ContentUnavailableView {
                Label("Error", systemImage: "exclamationmark.triangle")
            } description: {
                Text(error)
            }
        } else {
            List(filteredCountries) { country in
                NavigationLink(value: country) {
                    Text(country.name)
                }
            }
            .searchable(text: $countrySearch, prompt: "Search countries")
        }
    }
}

// MARK: - Lifecycle

extension AirportBrowserSheet {
    func loadCountries() async {
        do {
            countries = try await service.fetchCountries()
        } catch {
            self.error = error.localizedDescription
        }
        isLoadingCountries = false
    }
}

private struct CountryAirportsView: View {
    let country: Country
    let service: FlightService
    let onSelect: (Airport) -> Void

    @State private var airports: [BrowseAirport] = []
    @State private var isLoading = true
    @State private var error: String?
    @State private var airportSearch = ""
    @State private var selectingIATA: String?

    var filteredAirports: [BrowseAirport] {
        guard !airportSearch.isEmpty else { return airports }
        return airports.filter {
            $0.city.localizedCaseInsensitiveContains(airportSearch) ||
            $0.iata.localizedCaseInsensitiveContains(airportSearch)
        }
    }

    var body: some View {
        Group {
            if isLoading {
                ProgressView("Loading airports...")
            } else if let error {
                ContentUnavailableView {
                    Label("Error", systemImage: "exclamationmark.triangle")
                } description: {
                    Text(error)
                }
            } else if airports.isEmpty {
                ContentUnavailableView(
                    "No Airports",
                    systemImage: "airplane.slash",
                    description: Text("No airports found in \(country.name).")
                )
            } else {
                List(filteredAirports) { airport in
                    Button {
                        selectAirport(airport)
                    } label: {
                        HStack {
                            VStack(alignment: .leading, spacing: 2) {
                                Text(airport.city)
                                    .font(.headline)
                                    .foregroundStyle(.primary)
                                Text(airport.iata)
                                    .font(.caption)
                                    .foregroundStyle(.secondary)
                            }
                            Spacer()
                            if selectingIATA == airport.iata {
                                ProgressView()
                                    .controlSize(.small)
                            }
                        }
                    }
                    .disabled(selectingIATA != nil)
                }
                .searchable(text: $airportSearch, prompt: "Search airports")
            }
        }
        .navigationTitle(country.name)
        .task {
            do {
                airports = try await service.fetchAirports(country: country)
            } catch {
                self.error = error.localizedDescription
            }
            isLoading = false
        }
    }

    private func selectAirport(_ browseAirport: BrowseAirport) {
        selectingIATA = browseAirport.iata
        Task {
            do {
                let results = try await service.searchAirports(term: browseAirport.iata)
                if let match = results.first(where: { $0.iata == browseAirport.iata }) {
                    onSelect(match)
                } else {
                    onSelect(Airport(
                        id: "",
                        iata: browseAirport.iata,
                        name: browseAirport.city
                    ))
                }
            } catch {
                selectingIATA = nil
            }
        }
    }
}
