import SwiftUI

/// Browses aggregated load-factor "tightness" per major US hub, computed
/// from the bundled BTS Reporting Carrier dataset. Surfaces the
/// ``HubLoadHeatmapService`` (which would otherwise be dead code).
///
/// Each row shows the hub's IATA, the aggregated average load factor,
/// the BTS sample size powering the number, and a colour-coded band
/// (`open` / `moderate` / `tight` / `full`). Sort defaults to tightest
/// first since that's the nonrev-relevant ordering.
struct HubLoadsView: View {
    /// Curated list of US hubs surfaced in the view. Mirrors the airports
    /// the bundled BTS data covers — pulling the full ~4k airport list
    /// would mostly be misses since the bundle is filtered to ~8k records
    /// across the major carriers.
    private static let hubIATAs: [String] = [
        "ATL", "DFW", "DEN", "ORD", "LAX", "JFK", "LGA", "EWR",
        "CLT", "MCO", "MIA", "SEA", "PHX", "SFO", "IAH", "BOS",
        "MSP", "DTW", "PHL", "FLL", "BWI", "SLC", "DCA", "IAD",
        "LAS", "MDW", "MEM", "MSY", "PDX", "SAN", "STL", "TPA",
        "AUS", "BNA", "DAL", "HOU", "OAK", "RDU", "RSW", "SJC",
        "JAX", "ABQ", "ANC", "BHM", "BUR", "CLE", "CMH", "CVG",
        "ELP", "HNL", "ICT", "IND", "MCI", "OKC", "OMA", "ONT",
        "PIT", "PVD", "SAT", "SDF", "SMF", "SNA", "TUL", "TUS"
    ]

    @State private var rows: [HubRow] = []
    @State private var isLoading = true
    @State private var sourcePeriod: String?

    var body: some View {
        ZStack {
            FlightTheme.background.ignoresSafeArea()

            if isLoading {
                ProgressView()
                    .tint(FlightTheme.accent)
            } else if rows.isEmpty {
                emptyState
            } else {
                List {
                    Section {
                        ForEach(rows) { row in
                            HubLoadRow(row: row)
                        }
                    } header: {
                        Text("Tightest hubs first")
                    } footer: {
                        if let sourcePeriod {
                            Text("Based on DOT BTS data — \(sourcePeriod). Higher percentages = fuller flights = tougher nonrev / standby odds.")
                        }
                    }
                }
                .listStyle(.insetGrouped)
                .scrollContentBackground(.hidden)
            }
        }
        .navigationTitle("Hub loads")
        .navigationBarTitleDisplayMode(.inline)
        .task {
            await load()
        }
    }

    private var emptyState: some View {
        VStack(spacing: 12) {
            Image(systemName: "chart.bar.xaxis")
                .font(.system(size: 36))
                .foregroundStyle(FlightTheme.textTertiary)
            Text("No load data available")
                .font(.subheadline.weight(.semibold))
                .foregroundStyle(FlightTheme.textSecondary)
            Text("The bundled BTS data has no records for these hubs.")
                .font(.caption)
                .foregroundStyle(FlightTheme.textTertiary)
                .multilineTextAlignment(.center)
                .padding(.horizontal, 32)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }

    // MARK: - Load

    private func load() async {
        let service = HubLoadHeatmapService()
        let now = Date()
        var results: [HubRow] = []
        for iata in Self.hubIATAs {
            if let index = await service.loadIndex(forAirport: iata, on: now) {
                results.append(HubRow(
                    id: iata,
                    iata: iata,
                    avgLoadPct: index.avgLoadPct,
                    sampleSize: index.sampleSize,
                    band: index.band
                ))
            }
        }
        // Tightest first — most relevant ordering for nonrev planning.
        results.sort {
            if $0.avgLoadPct != $1.avgLoadPct {
                return $0.avgLoadPct > $1.avgLoadPct
            }
            return $0.iata < $1.iata
        }

        let meta = await BTSDataStore.shared.metadata()

        await MainActor.run {
            self.rows = results
            self.sourcePeriod = meta.map { "DOT BTS \($0.sourcePeriod) (\($0.recordCount) records)" }
            self.isLoading = false
        }
    }

    // MARK: - Row type

    struct HubRow: Identifiable {
        let id: String
        let iata: String
        let avgLoadPct: Double
        let sampleSize: Int
        let band: HubLoadHeatmapService.LoadBand
    }
}

// MARK: - Row

private struct HubLoadRow: View {
    let row: HubLoadsView.HubRow

    var body: some View {
        HStack(spacing: 14) {
            iataBadge
            VStack(alignment: .leading, spacing: 2) {
                Text(bandLabel)
                    .font(.caption.weight(.heavy))
                    .tracking(0.6)
                    .foregroundStyle(bandColor)
                Text("\(row.sampleSize) routes sampled")
                    .font(.caption2)
                    .foregroundStyle(FlightTheme.textSecondary)
            }
            Spacer()
            Text("\(Int(round(row.avgLoadPct * 100)))%")
                .font(.title3.weight(.bold).monospacedDigit())
                .foregroundStyle(bandColor)
        }
        .padding(.vertical, 4)
    }

    private var iataBadge: some View {
        Text(row.iata)
            .font(FlightTheme.flightNumber(13))
            .foregroundStyle(.white)
            .frame(width: 46, height: 30)
            .background(bandColor)
            .clipShape(RoundedRectangle(cornerRadius: 7))
    }

    private var bandLabel: String {
        switch row.band {
        case .open:     return "OPEN — nonrev-friendly"
        case .moderate: return "MODERATE"
        case .tight:    return "TIGHT — list early"
        case .full:     return "FULL — backup itinerary recommended"
        }
    }

    private var bandColor: Color {
        switch row.band {
        case .open:     return FlightTheme.onTime
        case .moderate: return FlightTheme.accent
        case .tight:    return FlightTheme.delayed
        case .full:     return FlightTheme.cancelled
        }
    }
}

#Preview {
    HubLoadsView()
}
