import SwiftUI

/// Walks every LoggedFlight that lacks an aircraftType, looks the
/// scheduled aircraft up via route-explorer, and patches it in. Use
/// after a CSV import that didn't get aircraft data, or any time the
/// Aircraft Stats screen looks empty.
struct EnrichAircraftTypesView: View {
    let store: FlightHistoryStore
    let routeExplorer: RouteExplorerClient

    @Environment(\.dismiss) private var dismiss
    @Environment(\.colorScheme) private var scheme

    @State private var phase: Phase = .ready
    @State private var candidates: [LoggedFlight] = []
    @State private var processedCount = 0
    @State private var enrichedCount = 0
    @State private var skippedDates: [Date] = []
    @State private var task: Task<Void, Never>?

    enum Phase { case ready, scanning, running, cancelled, done }

    var body: some View {
        NavigationStack {
            content
                .navigationTitle("Look up aircraft")
                .navigationBarTitleDisplayMode(.inline)
                .toolbar {
                    ToolbarItem(placement: .cancellationAction) {
                        Button(phase == .running ? "Stop" : "Done") {
                            task?.cancel()
                            dismiss()
                        }
                    }
                }
                .task { await onAppear() }
        }
    }

    @ViewBuilder
    private var content: some View {
        switch phase {
        case .ready:
            ProgressView()
                .frame(maxWidth: .infinity, maxHeight: .infinity)

        case .scanning:
            VStack(spacing: 12) {
                ProgressView()
                Text("Scanning your log…")
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)

        case .running:
            VStack(spacing: 18) {
                Spacer()
                VStack(spacing: 8) {
                    Text("\(processedCount) of \(candidates.count)")
                        .font(.system(size: 44, weight: .heavy).monospacedDigit())
                    Text("Found aircraft for \(enrichedCount)")
                        .font(.subheadline)
                        .foregroundStyle(.secondary)
                }
                ProgressView(value: Double(processedCount), total: Double(max(candidates.count, 1)))
                    .progressViewStyle(.linear)
                    .tint(HistoryStyle.runwayOrange)
                    .padding(.horizontal, 32)
                Spacer()
            }

        case .cancelled:
            ContentUnavailableView(
                "Stopped",
                systemImage: "stop.circle",
                description: Text("Enriched \(enrichedCount) flights before stopping.")
            )

        case .done:
            doneState
        }
    }

    private var doneState: some View {
        VStack(spacing: 14) {
            Spacer()
            Image(systemName: "checkmark.circle.fill")
                .font(.system(size: 56, weight: .heavy))
                .foregroundStyle(HistoryStyle.runwayOrange)
            Text("Found aircraft for \(enrichedCount) of \(candidates.count) flights")
                .font(.system(size: 18, weight: .heavy))
                .multilineTextAlignment(.center)
                .padding(.horizontal, 24)
            if candidates.count - enrichedCount > 0 {
                Text("Others may be too old for route-explorer's schedule data, or the carrier isn't covered. Manual edit still works for those.")
                    .font(.caption)
                    .foregroundStyle(.secondary)
                    .multilineTextAlignment(.center)
                    .padding(.horizontal, 32)
            }
            Spacer()
        }
    }

    private func onAppear() async {
        phase = .scanning
        candidates = store.allFlights().filter { f in
            f.aircraftType == nil
                && f.carrierIATA != nil
                && (f.flightNumber.flatMap(Int.init) != nil)
        }
        if candidates.isEmpty {
            // Nothing to do — everything already has a type.
            phase = .done
            return
        }
        phase = .running
        let t = Task { await runEnrichment() }
        task = t
        await t.value
    }

    private func runEnrichment() async {
        for f in candidates {
            if Task.isCancelled {
                phase = .cancelled
                return
            }
            if let eq = await lookupAircraftType(for: f) {
                f.aircraftType = eq
                enrichedCount += 1
            }
            processedCount += 1
        }
        // Save once at the end — SwiftData batches writes nicely.
        store.persist("enrich aircraft types")
        phase = .done
    }

    /// Two-step lookup:
    ///   1. route-explorer schedule — works for future or near-future
    ///      flights. Returns IATA aircraft codes ("73H").
    ///   2. FlightAware activity-log scrape — works for historical
    ///      flights still on a current flight number. Returns ICAO
    ///      codes ("B738").
    /// Either way we normalize to canonical ICAO via AircraftDatabase
    /// before saving so the rest of the app recognizes the value.
    private func lookupAircraftType(for f: LoggedFlight) async -> String? {
        guard let carrier = f.carrierIATA,
              let numStr = f.flightNumber,
              let num = Int(numStr)
        else { return nil }

        // 1) route-explorer
        let day = Calendar.current.startOfDay(for: f.flightDate)
        let next = Calendar.current.date(byAdding: .day, value: 1, to: day) ?? day
        let results = await routeExplorer.searchSchedule(
            carrierCode: carrier,
            flightNumber: num,
            startDate: day,
            endDate: next
        )
        let exact = results.first {
            $0.departure.airportIata == f.departureIATA
                && $0.arrival.airportIata == f.arrivalIATA
        } ?? results.first
        if let eq = exact?.equipmentIata, !eq.isEmpty {
            return AircraftDatabase.shared.normalizedICAO(forCode: eq)
        }

        // 2) FlightAware fallback
        // Build the ICAO callsign — FA addresses pages by ICAO carrier
        // + flight number. AircraftRegistry already maps IATA→ICAO.
        guard let carrierICAO = f.carrierICAO
            ?? AircraftRegistry.shared.lookup(iata: carrier)?.icao
        else { return nil }
        let callsign = "\(carrierICAO)\(num)"
        if let icaoType = await FlightAwareLookup.shared.lookupType(
            callsign: callsign,
            departureIATA: f.departureIATA,
            arrivalIATA: f.arrivalIATA
        ) {
            return AircraftDatabase.shared.normalizedICAO(forCode: icaoType)
        }
        return nil
    }
}
