import Foundation

/// User-facing sort options for the history list. Flighty's Passport
/// defaults to newest first; we mirror that and offer a few common
/// alternatives.
enum HistorySort: String, CaseIterable, Identifiable {
    case newestFirst    = "Newest first"
    case oldestFirst    = "Oldest first"
    case longestFirst   = "Longest first"
    case shortestFirst  = "Shortest first"
    case airline        = "By airline"
    case flightNumber   = "By flight #"

    var id: String { rawValue }

    var systemImage: String {
        switch self {
        case .newestFirst:   return "arrow.down.circle"
        case .oldestFirst:   return "arrow.up.circle"
        case .longestFirst:  return "arrow.up.right"
        case .shortestFirst: return "arrow.down.right"
        case .airline:       return "building.2"
        case .flightNumber:  return "number"
        }
    }
}

/// Plain-value filter set the history list + map share. Equatable so
/// `.onChange` can drive cached re-derivations cleanly. Empty sets mean
/// "no constraint" — anything passes.
struct HistoryFilters: Equatable {
    var query: String = ""
    var years: Set<Int> = []
    var airlines: Set<String> = []   // ICAO codes ("SWA")
    var airports: Set<String> = []   // IATA codes ("DAL")
    var aircraftTypes: Set<String> = []  // ICAO type ("B738")

    var isEmpty: Bool {
        query.isEmpty && years.isEmpty && airlines.isEmpty && airports.isEmpty && aircraftTypes.isEmpty
    }

    var activeCount: Int {
        var n = 0
        if !query.isEmpty { n += 1 }
        if !years.isEmpty { n += 1 }
        if !airlines.isEmpty { n += 1 }
        if !airports.isEmpty { n += 1 }
        if !aircraftTypes.isEmpty { n += 1 }
        return n
    }

    func matches(_ f: LoggedFlight) -> Bool {
        if !years.isEmpty {
            let y = Calendar.current.component(.year, from: f.flightDate)
            if !years.contains(y) { return false }
        }
        if !airlines.isEmpty {
            let icao = f.carrierICAO ?? f.carrierIATA
            guard let icao, airlines.contains(icao) else { return false }
        }
        if !airports.isEmpty {
            if !airports.contains(f.departureIATA) && !airports.contains(f.arrivalIATA) {
                return false
            }
        }
        if !aircraftTypes.isEmpty {
            guard let t = f.aircraftType, aircraftTypes.contains(t) else { return false }
        }
        if !query.isEmpty {
            let q = query.uppercased()
            let label = f.flightLabel.uppercased()
            let route = "\(f.departureIATA)\(f.arrivalIATA)".uppercased()
            if !label.contains(q) && !route.contains(q) && !f.departureIATA.uppercased().contains(q) && !f.arrivalIATA.uppercased().contains(q) {
                return false
            }
        }
        return true
    }
}

/// Sort comparator built from a HistorySort. Distance comparators take
/// a closure since we need the per-flight distance computed from
/// AirportDatabase rather than stored on the model.
extension HistorySort {
    func comparator(distanceMiles: @escaping (LoggedFlight) -> Int) -> (LoggedFlight, LoggedFlight) -> Bool {
        switch self {
        case .newestFirst:   return { $0.flightDate > $1.flightDate }
        case .oldestFirst:   return { $0.flightDate < $1.flightDate }
        case .longestFirst:  return { distanceMiles($0) > distanceMiles($1) }
        case .shortestFirst:
            return { lhs, rhs in
                let l = distanceMiles(lhs)
                let r = distanceMiles(rhs)
                // Treat 0 as "missing" so 0-mile rows sink to the bottom.
                if l == 0 { return false }
                if r == 0 { return true }
                return l < r
            }
        case .airline:
            return { lhs, rhs in
                let l = lhs.carrierICAO ?? lhs.carrierIATA ?? ""
                let r = rhs.carrierICAO ?? rhs.carrierIATA ?? ""
                if l == r { return lhs.flightDate > rhs.flightDate }
                return l < r
            }
        case .flightNumber:
            return { lhs, rhs in
                let l = Int(lhs.flightNumber ?? "") ?? Int.max
                let r = Int(rhs.flightNumber ?? "") ?? Int.max
                if l == r { return lhs.flightDate > rhs.flightDate }
                return l < r
            }
        }
    }
}
