//
//  ScenarioPlanner.swift
//  SportsTime
//
//  Protocol for scenario-based trip planning.
//

import Foundation

/// Protocol that all scenario planners must implement.
/// Each scenario (A, B, C, D, E) has its own isolated implementation.
///
/// - Invariants:
///   - Always returns either success or explicit failure, never throws
///   - Success contains ranked itinerary options
///   - Failure contains reason and any constraint violations
protocol ScenarioPlanner {

    /// Plan itineraries for this scenario.
    /// - Parameter request: The planning request with all inputs
    /// - Returns: Success with ranked itineraries, or explicit failure
    func plan(request: PlanningRequest) -> ItineraryResult
}

/// Factory for creating the appropriate scenario planner.
///
/// - Expected Behavior:
///   - planningMode == .teamFirst with >= 2 teams → ScenarioEPlanner
///   - followTeamId != nil → ScenarioDPlanner
///   - selectedGames not empty → ScenarioBPlanner
///   - startLocation AND endLocation != nil → ScenarioCPlanner
///   - Otherwise → ScenarioAPlanner (default)
///
/// Priority order: E > D > B > C > A (first matching wins)
enum ScenarioPlannerFactory {

    /// Creates the appropriate planner based on the request inputs.
    ///
    /// - Expected Behavior:
    ///   - planningMode == .teamFirst with >= 2 teams → ScenarioEPlanner
    ///   - followTeamId set → ScenarioDPlanner
    ///   - selectedGames not empty → ScenarioBPlanner
    ///   - Both start and end locations → ScenarioCPlanner
    ///   - Otherwise → ScenarioAPlanner
    static func planner(for request: PlanningRequest) -> ScenarioPlanner {
        print("🔍 ScenarioPlannerFactory: Selecting planner...")
        print("   - planningMode: \(request.preferences.planningMode)")
        print("   - selectedTeamIds.count: \(request.preferences.selectedTeamIds.count)")
        print("   - followTeamId: \(request.preferences.followTeamId ?? "nil")")
        print("   - selectedGames.count: \(request.selectedGames.count)")
        print("   - startLocation: \(request.startLocation?.name ?? "nil")")
        print("   - endLocation: \(request.endLocation?.name ?? "nil")")

        // Scenario E: Team-First mode - user selects teams, finds optimal trip windows
        if request.preferences.planningMode == .teamFirst &&
           request.preferences.selectedTeamIds.count >= 2 {
            print("🔍 ScenarioPlannerFactory: → ScenarioEPlanner (team-first)")
            return ScenarioEPlanner()
        }

        // Scenario D: User wants to follow a specific team
        if request.preferences.followTeamId != nil {
            print("🔍 ScenarioPlannerFactory: → ScenarioDPlanner (follow team)")
            return ScenarioDPlanner()
        }

        // Scenario B: User selected specific games
        if !request.selectedGames.isEmpty {
            print("🔍 ScenarioPlannerFactory: → ScenarioBPlanner (selected games)")
            return ScenarioBPlanner()
        }

        // Scenario C: User specified start and end locations
        if request.startLocation != nil && request.endLocation != nil {
            print("🔍 ScenarioPlannerFactory: → ScenarioCPlanner (start/end locations)")
            return ScenarioCPlanner()
        }

        // Scenario A: Date range only (default)
        print("🔍 ScenarioPlannerFactory: → ScenarioAPlanner (default/date range)")
        return ScenarioAPlanner()
    }

    /// Classifies which scenario applies to this request.
    ///
    /// - Expected Behavior:
    ///   - planningMode == .teamFirst with >= 2 teams → .scenarioE
    ///   - followTeamId set → .scenarioD
    ///   - selectedGames not empty → .scenarioB
    ///   - Both start and end locations → .scenarioC
    ///   - Otherwise → .scenarioA
    static func classify(_ request: PlanningRequest) -> PlanningScenario {
        if request.preferences.planningMode == .teamFirst &&
           request.preferences.selectedTeamIds.count >= 2 {
            return .scenarioE
        }
        if request.preferences.followTeamId != nil {
            return .scenarioD
        }
        if !request.selectedGames.isEmpty {
            return .scenarioB
        }
        if request.startLocation != nil && request.endLocation != nil {
            return .scenarioC
        }
        return .scenarioA
    }
}
