//
//  RouteFilters.swift
//  SportsTime
//
//  Filters itinerary results based on user preferences.
//  Applied in TripPlanningEngine AFTER scenario planners return.
//

import Foundation
import CoreLocation

enum RouteFilters {

    // MARK: - Repeat Cities Filter

    /// Filter itinerary options that violate repeat city rules.
    /// When allowRepeatCities=false, each city must be visited on exactly ONE day.
    static func filterRepeatCities(
        _ options: [ItineraryOption],
        allow: Bool
    ) -> [ItineraryOption] {
        guard !allow else { return options }
        return options.filter { !hasRepeatCityViolation($0) }
    }

    /// Check if an itinerary visits any city on multiple days.
    static func hasRepeatCityViolation(_ option: ItineraryOption) -> Bool {
        let calendar = Calendar.current
        var cityDays: [String: Set<Date>] = [:]

        for stop in option.stops {
            let city = stop.city
            let day = calendar.startOfDay(for: stop.arrivalDate)
            cityDays[city, default: []].insert(day)
        }

        // Violation if any city has more than 1 day
        return cityDays.values.contains(where: { $0.count > 1 })
    }

    /// Get cities that are visited on multiple days (for error reporting).
    static func findRepeatCities(in options: [ItineraryOption]) -> [String] {
        var violatingCities = Set<String>()
        let calendar = Calendar.current

        for option in options {
            var cityDays: [String: Set<Date>] = [:]
            for stop in option.stops {
                let day = calendar.startOfDay(for: stop.arrivalDate)
                cityDays[stop.city, default: []].insert(day)
            }
            for (city, days) in cityDays where days.count > 1 {
                violatingCities.insert(city)
            }
        }

        return Array(violatingCities).sorted()
    }

    // MARK: - Trip List Filters

    /// Filter trips by sport. Returns trips containing ANY of the specified sports.
    static func filterBySport(_ trips: [Trip], sports: Set<Sport>) -> [Trip] {
        guard !sports.isEmpty else { return trips }
        return trips.filter { trip in
            !trip.preferences.sports.isDisjoint(with: sports)
        }
    }

    /// Filter trips by date range. Returns trips that overlap with the specified range.
    static func filterByDateRange(_ trips: [Trip], start: Date, end: Date) -> [Trip] {
        let calendar = Calendar.current
        let rangeStart = calendar.startOfDay(for: start)
        let rangeEnd = calendar.startOfDay(for: end)

        return trips.filter { trip in
            let tripStart = calendar.startOfDay(for: trip.startDate)
            let tripEnd = calendar.startOfDay(for: trip.endDate)

            // Trip overlaps if it starts before range ends AND ends after range starts
            return tripStart <= rangeEnd && tripEnd >= rangeStart
        }
    }

    /// Filter trips by status. Returns trips matching the specified status.
    static func filterByStatus(_ trips: [Trip], status: TripStatus) -> [Trip] {
        trips.filter { $0.status == status }
    }

    /// Apply multiple filters. Returns intersection of all filter criteria.
    static func applyFilters(
        _ trips: [Trip],
        sports: Set<Sport>? = nil,
        dateRange: (start: Date, end: Date)? = nil,
        status: TripStatus? = nil
    ) -> [Trip] {
        var result = trips

        if let sports = sports, !sports.isEmpty {
            result = filterBySport(result, sports: sports)
        }

        if let range = dateRange {
            result = filterByDateRange(result, start: range.start, end: range.end)
        }

        if let status = status {
            result = filterByStatus(result, status: status)
        }

        return result
    }

}
