import Foundation
import CoreLocation

/// Computes totals + narrative stats over the user's flight history.
/// Pure derivation — no side effects, no I/O. Built once per view body
/// pass over a flights snapshot.
@MainActor
struct StatsEngine {
    let flights: [LoggedFlight]
    let store: FlightHistoryStore
    let database: AirportDatabase

    init(store: FlightHistoryStore, database: AirportDatabase, flights: [LoggedFlight]) {
        self.store = store
        self.database = database
        self.flights = flights
    }

    // MARK: - Totals

    var totalFlights: Int { flights.count }

    var totalMiles: Int {
        flights.reduce(0) { acc, f in acc + (store.distanceMiles(for: f) ?? 0) }
    }

    var totalMinutes: Int {
        flights.reduce(0) { acc, f in
            // Prefer logged duration; fall back to estimated 7 min per 100 mi.
            if let d = store.durationMinutes(for: f) { return acc + d }
            if let mi = store.distanceMiles(for: f) { return acc + Int(Double(mi) / 100.0 * 7.0) }
            return acc
        }
    }

    var totalHours: Int { totalMinutes / 60 }

    var uniqueAirports: Int {
        Set(flights.flatMap { [$0.departureIATA, $0.arrivalIATA] }
            .filter { !$0.isEmpty }).count
    }

    var uniqueAirlines: Int {
        Set(flights.compactMap { $0.carrierICAO ?? $0.carrierIATA }).count
    }

    var uniqueAircraftTypes: Int {
        Set(flights.compactMap { $0.aircraftType }).count
    }

    var uniqueCountries: Int {
        Set(flights.flatMap { [$0.departureIATA, $0.arrivalIATA] }
            .compactMap { database.airport(byIATA: $0)?.country }).count
    }

    // MARK: - Compact display

    var shortDistance: String {
        let n = totalMiles
        if n >= 1_000_000 { return String(format: "%.1fM", Double(n) / 1_000_000) }
        if n >= 10_000   { return String(format: "%.0fk", Double(n) / 1_000) }
        return numberString(n)
    }

    var shortDuration: String {
        if totalHours >= 1000 { return String(format: "%.0fk", Double(totalHours) / 1_000) }
        return "\(totalHours)"
    }

    // MARK: - Narrative

    /// Most-flown carrier ICAO.
    var topAirline: (icao: String, count: Int)? {
        let counts = Dictionary(grouping: flights.compactMap { $0.carrierICAO ?? $0.carrierIATA }) { $0 }
            .mapValues(\.count)
        return counts.max(by: { $0.value < $1.value }).map { ($0.key, $0.value) }
    }

    /// Most-flown route (dep + arr, ignoring direction).
    var topRoute: (label: String, count: Int)? {
        let pairs = flights.map { f in [f.departureIATA, f.arrivalIATA].sorted().joined(separator: "↔") }
        let counts = Dictionary(grouping: pairs) { $0 }.mapValues(\.count)
        return counts.max(by: { $0.value < $1.value }).map { ($0.key, $0.value) }
    }

    /// Most-visited airport (counts each endpoint independently).
    var topAirport: (iata: String, count: Int)? {
        let codes = flights.flatMap { [$0.departureIATA, $0.arrivalIATA] }.filter { !$0.isEmpty }
        let counts = Dictionary(grouping: codes) { $0 }.mapValues(\.count)
        return counts.max(by: { $0.value < $1.value }).map { ($0.key, $0.value) }
    }

    /// Tail numbers we've flown more than once.
    var repeatedTails: [(reg: String, count: Int)] {
        let regs = flights.compactMap { $0.registration }
        let counts = Dictionary(grouping: regs) { $0 }.mapValues(\.count)
        return counts.filter { $0.value > 1 }
            .map { ($0.key, $0.value) }
            .sorted { $0.count > $1.count }
    }

    /// Longest single flight by distance.
    var longestFlight: LoggedFlight? {
        flights.max { (store.distanceMiles(for: $0) ?? 0) < (store.distanceMiles(for: $1) ?? 0) }
    }

    /// Shortest single flight by distance.
    var shortestFlight: LoggedFlight? {
        flights
            .filter { (store.distanceMiles(for: $0) ?? 0) > 0 }
            .min { (store.distanceMiles(for: $0) ?? 0) < (store.distanceMiles(for: $1) ?? 0) }
    }

    /// Flights bucketed by year, most recent first.
    var byYear: [(year: Int, flights: [LoggedFlight])] {
        let cal = Calendar.current
        let grouped = Dictionary(grouping: flights) { cal.component(.year, from: $0.flightDate) }
        return grouped
            .map { (year: $0.key, flights: $0.value) }
            .sorted { $0.year > $1.year }
    }

    /// Flights for one calendar year.
    func flights(for year: Int) -> [LoggedFlight] {
        let cal = Calendar.current
        return flights.filter { cal.component(.year, from: $0.flightDate) == year }
    }

    // MARK: - Helpers

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