//
//  ScenarioDPlannerTests.swift
//  SportsTimeTests
//
//  Phase 5: ScenarioDPlanner Tests
//  Scenario D: User selects a team to follow, planner builds route from their schedule.
//

import Testing
import CoreLocation
@testable import SportsTime

@Suite("ScenarioDPlanner Tests", .serialized)
struct ScenarioDPlannerTests {

    // MARK: - Test Fixtures

    private let calendar = Calendar.current
    private let planner = ScenarioDPlanner()

    /// Creates a date with specific year/month/day/hour
    private func makeDate(year: Int = 2026, month: Int = 6, day: Int, hour: Int = 19) -> Date {
        var components = DateComponents()
        components.year = year
        components.month = month
        components.day = day
        components.hour = hour
        components.minute = 0
        return calendar.date(from: components)!
    }

    /// Creates a stadium at a known location
    private func makeStadium(
        id: String = "stadium_test_\(UUID().uuidString)",
        city: String,
        lat: Double,
        lon: Double,
        sport: Sport = .mlb
    ) -> Stadium {
        Stadium(
            id: id,
            name: "\(city) Stadium",
            city: city,
            state: "ST",
            latitude: lat,
            longitude: lon,
            capacity: 40000,
            sport: sport
        )
    }

    /// Creates a team
    private func makeTeam(
        id: String = "team_test_\(UUID().uuidString)",
        name: String,
        stadiumId: String,
        sport: Sport = .mlb
    ) -> Team {
        Team(
            id: id,
            name: name,
            abbreviation: String(name.prefix(3).uppercased()),
            sport: sport,
            city: name,
            stadiumId: stadiumId,
            logoURL: nil,
            primaryColor: "#FF0000",
            secondaryColor: "#FFFFFF"
        )
    }

    /// Creates a game at a stadium
    private func makeGame(
        id: String = "game_test_\(UUID().uuidString)",
        stadiumId: String,
        homeTeamId: String,
        awayTeamId: String,
        dateTime: Date,
        sport: Sport = .mlb
    ) -> Game {
        Game(
            id: id,
            homeTeamId: homeTeamId,
            awayTeamId: awayTeamId,
            stadiumId: stadiumId,
            dateTime: dateTime,
            sport: sport,
            season: "2026"
        )
    }

    /// Creates a PlanningRequest for Scenario D (follow team mode)
    private func makePlanningRequest(
        startDate: Date,
        endDate: Date,
        followTeamId: String?,
        allGames: [Game],
        stadiums: [String: Stadium],
        teams: [String: Team] = [:],
        selectedRegions: Set<Region> = [],
        allowRepeatCities: Bool = true,
        useHomeLocation: Bool = false,
        startLocation: LocationInput? = nil,
        numberOfDrivers: Int = 1,
        maxDrivingHoursPerDriver: Double = 8.0
    ) -> PlanningRequest {
        let preferences = TripPreferences(
            planningMode: .followTeam,
            startLocation: startLocation,
            sports: [.mlb],
            startDate: startDate,
            endDate: endDate,
            leisureLevel: .moderate,
            numberOfDrivers: numberOfDrivers,
            maxDrivingHoursPerDriver: maxDrivingHoursPerDriver,
            allowRepeatCities: allowRepeatCities,
            selectedRegions: selectedRegions,
            followTeamId: followTeamId,
            useHomeLocation: useHomeLocation
        )

        return PlanningRequest(
            preferences: preferences,
            availableGames: allGames,
            teams: teams,
            stadiums: stadiums
        )
    }

    // MARK: - D.1: Valid Inputs

    @Test("D.1.1 - Single team with home games returns trip with those games")
    func test_followTeam_HomeGames_ReturnsTrip() {
        // Setup: Team with 2 home games
        let stadiumId = "stadium_test_\(UUID().uuidString)"
        let stadium = makeStadium(id: stadiumId, city: "Chicago", lat: 41.8781, lon: -87.6298)
        let stadiums = [stadiumId: stadium]

        let teamId = "team_test_\(UUID().uuidString)"
        let opponentId = "team_opponent_\(UUID().uuidString)"
        let team = makeTeam(id: teamId, name: "Chicago Cubs", stadiumId: stadiumId)

        let game1 = makeGame(
            stadiumId: stadiumId,
            homeTeamId: teamId,
            awayTeamId: opponentId,
            dateTime: makeDate(day: 5, hour: 19)
        )
        let game2 = makeGame(
            stadiumId: stadiumId,
            homeTeamId: teamId,
            awayTeamId: opponentId,
            dateTime: makeDate(day: 7, hour: 19)
        )

        let request = makePlanningRequest(
            startDate: makeDate(day: 1, hour: 0),
            endDate: makeDate(day: 10, hour: 23),
            followTeamId: teamId,
            allGames: [game1, game2],
            stadiums: stadiums,
            teams: [teamId: team]
        )

        // Execute
        let result = planner.plan(request: request)

        // Verify
        #expect(result.isSuccess, "Should succeed with team home games")
        #expect(!result.options.isEmpty, "Should return at least one option")

        if let firstOption = result.options.first {
            #expect(firstOption.totalGames >= 2, "Should include both home games")
            let cities = firstOption.stops.map { $0.city }
            #expect(cities.contains("Chicago"), "Should visit team's home city")
        }
    }

    @Test("D.1.2 - Team with away games includes those games")
    func test_followTeam_AwayGames_IncludesAwayGames() {
        // Setup: Team with one home game and one away game (2 cities for simpler route)
        let homeStadiumId = "stadium_home_\(UUID().uuidString)"
        let awayStadiumId = "stadium_away_\(UUID().uuidString)"

        let homeStadium = makeStadium(id: homeStadiumId, city: "Chicago", lat: 41.8781, lon: -87.6298)
        let awayStadium = makeStadium(id: awayStadiumId, city: "Milwaukee", lat: 43.0389, lon: -87.9065)

        let stadiums = [
            homeStadiumId: homeStadium,
            awayStadiumId: awayStadium
        ]

        let teamId = "team_test_\(UUID().uuidString)"
        let opponentId = "team_opponent_\(UUID().uuidString)"

        // Home game
        let homeGame = makeGame(
            stadiumId: homeStadiumId,
            homeTeamId: teamId,
            awayTeamId: opponentId,
            dateTime: makeDate(day: 5, hour: 19)
        )

        // Away game (team is awayTeamId)
        let awayGame = makeGame(
            stadiumId: awayStadiumId,
            homeTeamId: opponentId,
            awayTeamId: teamId,
            dateTime: makeDate(day: 8, hour: 19)
        )

        let request = makePlanningRequest(
            startDate: makeDate(day: 1, hour: 0),
            endDate: makeDate(day: 15, hour: 23),
            followTeamId: teamId,
            allGames: [homeGame, awayGame],
            stadiums: stadiums
        )

        // Execute
        let result = planner.plan(request: request)

        // Verify
        #expect(result.isSuccess, "Should succeed with home and away games")
        #expect(!result.options.isEmpty, "Should return at least one option")

        if let firstOption = result.options.first {
            // Should include both games
            #expect(firstOption.totalGames >= 2, "Should include both team games (home and away)")

            let cities = firstOption.stops.map { $0.city }
            #expect(cities.contains("Chicago"), "Should visit home city")
            #expect(cities.contains("Milwaukee"), "Should visit away city")
        }
    }

    @Test("D.1.3 - Team games filtered by selected regions")
    func test_followTeam_RegionFilter_FiltersGames() {
        // Setup: Team with games in multiple regions
        let eastStadiumId = "stadium_east_\(UUID().uuidString)"
        let centralStadiumId = "stadium_central_\(UUID().uuidString)"

        // East region (> -85 longitude)
        let eastStadium = makeStadium(id: eastStadiumId, city: "New York", lat: 40.7128, lon: -73.9352)
        // Central region (-110 to -85 longitude)
        let centralStadium = makeStadium(id: centralStadiumId, city: "Chicago", lat: 41.8781, lon: -87.6298)

        let stadiums = [eastStadiumId: eastStadium, centralStadiumId: centralStadium]

        let teamId = "team_test_\(UUID().uuidString)"
        let opponentId = "team_opponent_\(UUID().uuidString)"

        let eastGame = makeGame(
            stadiumId: eastStadiumId,
            homeTeamId: opponentId,
            awayTeamId: teamId,
            dateTime: makeDate(day: 5, hour: 19)
        )
        let centralGame = makeGame(
            stadiumId: centralStadiumId,
            homeTeamId: teamId,
            awayTeamId: opponentId,
            dateTime: makeDate(day: 7, hour: 19)
        )

        // Only select East region
        let request = makePlanningRequest(
            startDate: makeDate(day: 1, hour: 0),
            endDate: makeDate(day: 15, hour: 23),
            followTeamId: teamId,
            allGames: [eastGame, centralGame],
            stadiums: stadiums,
            selectedRegions: [.east]
        )

        // Execute
        let result = planner.plan(request: request)

        // Verify
        #expect(result.isSuccess, "Should succeed with regional filter")
        #expect(!result.options.isEmpty, "Should return at least one option")

        if let firstOption = result.options.first {
            let cities = firstOption.stops.map { $0.city }
            #expect(cities.contains("New York"), "Should include East region game")
            #expect(!cities.contains("Chicago"), "Should exclude Central region game")
        }
    }

    // MARK: - D.2: Edge Cases

    @Test("D.2.1 - No team selected returns missingTeamSelection failure")
    func test_followTeam_NoTeamSelected_ReturnsMissingTeamSelection() {
        // Setup: No team ID
        let stadiumId = "stadium_test_\(UUID().uuidString)"
        let stadium = makeStadium(id: stadiumId, city: "Chicago", lat: 41.8781, lon: -87.6298)
        let stadiums = [stadiumId: stadium]

        let game = makeGame(
            stadiumId: stadiumId,
            homeTeamId: "team_test_\(UUID().uuidString)",
            awayTeamId: "team_opponent_\(UUID().uuidString)",
            dateTime: makeDate(day: 5, hour: 19)
        )

        let request = makePlanningRequest(
            startDate: makeDate(day: 1, hour: 0),
            endDate: makeDate(day: 10, hour: 23),
            followTeamId: nil,  // No team selected
            allGames: [game],
            stadiums: stadiums
        )

        // Execute
        let result = planner.plan(request: request)

        // Verify
        #expect(!result.isSuccess, "Should fail when no team selected")
        #expect(result.failure?.reason == .missingTeamSelection,
               "Should return missingTeamSelection error")
    }

    @Test("D.2.2 - Team with no games in date range returns noGamesInRange failure")
    func test_followTeam_NoGamesInRange_ReturnsNoGamesFailure() {
        // Setup: Team's games are outside date range
        let stadiumId = "stadium_test_\(UUID().uuidString)"
        let stadium = makeStadium(id: stadiumId, city: "Chicago", lat: 41.8781, lon: -87.6298)
        let stadiums = [stadiumId: stadium]

        let teamId = "team_test_\(UUID().uuidString)"

        // Game is in July, but we search June
        let game = makeGame(
            stadiumId: stadiumId,
            homeTeamId: teamId,
            awayTeamId: "team_opponent_\(UUID().uuidString)",
            dateTime: makeDate(month: 7, day: 15, hour: 19)
        )

        let request = makePlanningRequest(
            startDate: makeDate(month: 6, day: 1, hour: 0),
            endDate: makeDate(month: 6, day: 30, hour: 23),
            followTeamId: teamId,
            allGames: [game],
            stadiums: stadiums
        )

        // Execute
        let result = planner.plan(request: request)

        // Verify
        #expect(!result.isSuccess, "Should fail when no games in date range")
        #expect(result.failure?.reason == .noGamesInRange,
               "Should return noGamesInRange error")
    }

    @Test("D.2.3 - Team not involved in any games returns noGamesInRange failure")
    func test_followTeam_TeamNotInGames_ReturnsNoGamesFailure() {
        // Setup: Games exist but team isn't playing
        let stadiumId = "stadium_test_\(UUID().uuidString)"
        let stadium = makeStadium(id: stadiumId, city: "Chicago", lat: 41.8781, lon: -87.6298)
        let stadiums = [stadiumId: stadium]

        let teamId = "team_test_\(UUID().uuidString)"
        let otherTeam1 = "team_other1_\(UUID().uuidString)"
        let otherTeam2 = "team_other2_\(UUID().uuidString)"

        // Game between other teams
        let game = makeGame(
            stadiumId: stadiumId,
            homeTeamId: otherTeam1,
            awayTeamId: otherTeam2,
            dateTime: makeDate(day: 5, hour: 19)
        )

        let request = makePlanningRequest(
            startDate: makeDate(day: 1, hour: 0),
            endDate: makeDate(day: 10, hour: 23),
            followTeamId: teamId,
            allGames: [game],
            stadiums: stadiums
        )

        // Execute
        let result = planner.plan(request: request)

        // Verify
        #expect(!result.isSuccess, "Should fail when team has no games")
        #expect(result.failure?.reason == .noGamesInRange,
               "Should return noGamesInRange error")
    }

    @Test("D.2.4 - Repeat city filter removes duplicate city visits")
    func test_followTeam_RepeatCityFilter_RemovesDuplicates() {
        // Setup: Team has multiple games at same stadium
        let stadiumId = "stadium_test_\(UUID().uuidString)"
        let stadium = makeStadium(id: stadiumId, city: "Chicago", lat: 41.8781, lon: -87.6298)
        let stadiums = [stadiumId: stadium]

        let teamId = "team_test_\(UUID().uuidString)"
        let opponentId = "team_opponent_\(UUID().uuidString)"

        let game1 = makeGame(
            stadiumId: stadiumId,
            homeTeamId: teamId,
            awayTeamId: opponentId,
            dateTime: makeDate(day: 5, hour: 19)
        )
        let game2 = makeGame(
            stadiumId: stadiumId,
            homeTeamId: teamId,
            awayTeamId: opponentId,
            dateTime: makeDate(day: 7, hour: 19)
        )
        let game3 = makeGame(
            stadiumId: stadiumId,
            homeTeamId: teamId,
            awayTeamId: opponentId,
            dateTime: makeDate(day: 9, hour: 19)
        )

        let request = makePlanningRequest(
            startDate: makeDate(day: 1, hour: 0),
            endDate: makeDate(day: 15, hour: 23),
            followTeamId: teamId,
            allGames: [game1, game2, game3],
            stadiums: stadiums,
            allowRepeatCities: false  // Don't allow repeat cities
        )

        // Execute
        let result = planner.plan(request: request)

        // Verify
        #expect(result.isSuccess, "Should succeed with repeat city filter")
        #expect(!result.options.isEmpty, "Should return at least one option")

        if let firstOption = result.options.first {
            // With allowRepeatCities=false, should only have 1 game
            // (the first game in Chicago)
            #expect(firstOption.totalGames == 1, "Should only include first game per city when repeat cities not allowed")
        }
    }

    @Test("D.2.5 - Missing date range returns missingDateRange failure")
    func test_followTeam_MissingDateRange_ReturnsMissingDateRangeFailure() {
        // Setup: Invalid date range (end before start)
        let stadiumId = "stadium_test_\(UUID().uuidString)"
        let stadium = makeStadium(id: stadiumId, city: "Chicago", lat: 41.8781, lon: -87.6298)
        let stadiums = [stadiumId: stadium]

        let teamId = "team_test_\(UUID().uuidString)"

        let game = makeGame(
            stadiumId: stadiumId,
            homeTeamId: teamId,
            awayTeamId: "team_opponent_\(UUID().uuidString)",
            dateTime: makeDate(day: 5, hour: 19)
        )

        // End date before start date makes dateRange nil
        let request = makePlanningRequest(
            startDate: makeDate(day: 15, hour: 0),
            endDate: makeDate(day: 1, hour: 23),  // Before start
            followTeamId: teamId,
            allGames: [game],
            stadiums: stadiums
        )

        // Execute
        let result = planner.plan(request: request)

        // Verify
        #expect(!result.isSuccess, "Should fail with invalid date range")
        #expect(result.failure?.reason == .missingDateRange,
               "Should return missingDateRange error")
    }

    // MARK: - D.3: Route Verification

    @Test("D.3.1 - Route connects team games chronologically")
    func test_followTeam_RouteIsChronological() {
        // Setup: Team with games in 2 nearby cities chronologically
        let chicagoId = "stadium_chicago_\(UUID().uuidString)"
        let milwaukeeId = "stadium_milwaukee_\(UUID().uuidString)"

        let chicago = makeStadium(id: chicagoId, city: "Chicago", lat: 41.8781, lon: -87.6298)
        let milwaukee = makeStadium(id: milwaukeeId, city: "Milwaukee", lat: 43.0389, lon: -87.9065)

        let stadiums = [chicagoId: chicago, milwaukeeId: milwaukee]

        let teamId = "team_test_\(UUID().uuidString)"
        let opponentId = "team_opponent_\(UUID().uuidString)"

        // Games in chronological order: Chicago → Milwaukee
        let game1 = makeGame(
            stadiumId: chicagoId,
            homeTeamId: teamId,
            awayTeamId: opponentId,
            dateTime: makeDate(day: 5, hour: 19)
        )
        let game2 = makeGame(
            stadiumId: milwaukeeId,
            homeTeamId: opponentId,
            awayTeamId: teamId,
            dateTime: makeDate(day: 8, hour: 19)
        )

        let request = makePlanningRequest(
            startDate: makeDate(day: 1, hour: 0),
            endDate: makeDate(day: 15, hour: 23),
            followTeamId: teamId,
            allGames: [game1, game2],
            stadiums: stadiums
        )

        // Execute
        let result = planner.plan(request: request)

        // Verify
        #expect(result.isSuccess, "Should succeed with team games")
        #expect(!result.options.isEmpty, "Should return at least one option")

        if let firstOption = result.options.first {
            #expect(firstOption.totalGames >= 2, "Should include both team games")

            // Verify stops are in chronological order
            let stopDates = firstOption.stops.map { $0.arrivalDate }
            let sortedDates = stopDates.sorted()
            #expect(stopDates == sortedDates, "Stops should be in chronological order")
        }
    }

    @Test("D.3.2 - Travel segments connect stops correctly")
    func test_followTeam_TravelSegmentsConnectStops() {
        // Setup: Team with 2 games in different cities
        let nycId = "stadium_nyc_\(UUID().uuidString)"
        let bostonId = "stadium_boston_\(UUID().uuidString)"

        let nyc = makeStadium(id: nycId, city: "New York", lat: 40.7128, lon: -73.9352)
        let boston = makeStadium(id: bostonId, city: "Boston", lat: 42.3601, lon: -71.0589)

        let stadiums = [nycId: nyc, bostonId: boston]

        let teamId = "team_test_\(UUID().uuidString)"
        let opponentId = "team_opponent_\(UUID().uuidString)"

        let game1 = makeGame(
            stadiumId: nycId,
            homeTeamId: teamId,
            awayTeamId: opponentId,
            dateTime: makeDate(day: 5, hour: 19)
        )
        let game2 = makeGame(
            stadiumId: bostonId,
            homeTeamId: opponentId,
            awayTeamId: teamId,
            dateTime: makeDate(day: 8, hour: 19)
        )

        let request = makePlanningRequest(
            startDate: makeDate(day: 1, hour: 0),
            endDate: makeDate(day: 15, hour: 23),
            followTeamId: teamId,
            allGames: [game1, game2],
            stadiums: stadiums
        )

        // Execute
        let result = planner.plan(request: request)

        // Verify
        #expect(result.isSuccess, "Should succeed with team games")
        #expect(!result.options.isEmpty, "Should return at least one option")

        if let firstOption = result.options.first {
            #expect(firstOption.stops.count >= 2, "Should have at least 2 stops")

            // Should have travel segment between stops
            if firstOption.stops.count > 1 {
                #expect(firstOption.travelSegments.count == firstOption.stops.count - 1,
                       "Should have travel segments connecting stops")

                // Verify travel segment has reasonable distance
                if let segment = firstOption.travelSegments.first {
                    #expect(segment.distanceMiles > 0, "Travel segment should have distance")
                    #expect(segment.durationHours > 0, "Travel segment should have duration")
                }
            }
        }
    }

    // MARK: - D.4: Multi-City Cross-Country Routes

    @Test("D.4.1 - Three-city route with adequate driving time succeeds (Astros scenario)")
    func test_followTeam_ThreeCityRoute_WithAdequateTime_Succeeds() {
        // Setup: Simulates Houston → Chicago → Anaheim (Astros July 20-29 scenario)
        // Houston to Chicago: ~1000 miles, Chicago to Anaheim: ~2000 miles
        // With 4+ days between each leg, both should be feasible
        let houstonId = "stadium_houston_\(UUID().uuidString)"
        let chicagoId = "stadium_chicago_\(UUID().uuidString)"
        let anaheimId = "stadium_anaheim_\(UUID().uuidString)"

        let houston = makeStadium(id: houstonId, city: "Houston", lat: 29.7604, lon: -95.3698)
        let chicago = makeStadium(id: chicagoId, city: "Chicago", lat: 41.8781, lon: -87.6298)
        let anaheim = makeStadium(id: anaheimId, city: "Anaheim", lat: 33.8003, lon: -117.8827)

        let stadiums = [houstonId: houston, chicagoId: chicago, anaheimId: anaheim]

        let teamId = "team_test_\(UUID().uuidString)"
        let opponent1 = "team_opponent1_\(UUID().uuidString)"
        let opponent2 = "team_opponent2_\(UUID().uuidString)"
        let opponent3 = "team_opponent3_\(UUID().uuidString)"

        // Houston home games: July 20-22
        let houstonGame = makeGame(
            stadiumId: houstonId,
            homeTeamId: teamId,
            awayTeamId: opponent1,
            dateTime: makeDate(month: 7, day: 20, hour: 19)
        )

        // Chicago away games: July 24-26 (4 days after Houston)
        let chicagoGame = makeGame(
            stadiumId: chicagoId,
            homeTeamId: opponent2,
            awayTeamId: teamId,
            dateTime: makeDate(month: 7, day: 24, hour: 19)
        )

        // Anaheim away games: July 29 (5 days after Chicago)
        let anaheimGame = makeGame(
            stadiumId: anaheimId,
            homeTeamId: opponent3,
            awayTeamId: teamId,
            dateTime: makeDate(month: 7, day: 29, hour: 19)
        )

        let request = makePlanningRequest(
            startDate: makeDate(month: 7, day: 18, hour: 0),
            endDate: makeDate(month: 7, day: 31, hour: 23),
            followTeamId: teamId,
            allGames: [houstonGame, chicagoGame, anaheimGame],
            stadiums: stadiums,
            allowRepeatCities: false
        )

        // Execute
        let result = planner.plan(request: request)

        // Verify
        #expect(result.isSuccess, "Should succeed with 3-city cross-country route")
        #expect(!result.options.isEmpty, "Should return at least one option")

        // Find the 3-city route
        let threeCityOption = result.options.first { option in
            option.stops.count == 3
        }

        #expect(threeCityOption != nil, "Should include a 3-city route option")

        if let option = threeCityOption {
            let cities = option.stops.map { $0.city }
            #expect(cities.contains("Houston"), "Route should include Houston")
            #expect(cities.contains("Chicago"), "Route should include Chicago")
            #expect(cities.contains("Anaheim"), "Route should include Anaheim")

            // Verify travel segments exist
            #expect(option.travelSegments.count == 2, "Should have 2 travel segments for 3 stops")
        }
    }

    @Test("D.4.2 - Three-city route with insufficient driving time fails to include all cities")
    func test_followTeam_ThreeCityRoute_InsufficientTime_ExcludesUnreachableCities() {
        // Setup: Same cities but games too close together
        // Chicago to Anaheim needs ~37 hours driving, but only 1 day between games
        let houstonId = "stadium_houston_\(UUID().uuidString)"
        let chicagoId = "stadium_chicago_\(UUID().uuidString)"
        let anaheimId = "stadium_anaheim_\(UUID().uuidString)"

        let houston = makeStadium(id: houstonId, city: "Houston", lat: 29.7604, lon: -95.3698)
        let chicago = makeStadium(id: chicagoId, city: "Chicago", lat: 41.8781, lon: -87.6298)
        let anaheim = makeStadium(id: anaheimId, city: "Anaheim", lat: 33.8003, lon: -117.8827)

        let stadiums = [houstonId: houston, chicagoId: chicago, anaheimId: anaheim]

        let teamId = "team_test_\(UUID().uuidString)"
        let opponent1 = "team_opponent1_\(UUID().uuidString)"
        let opponent2 = "team_opponent2_\(UUID().uuidString)"
        let opponent3 = "team_opponent3_\(UUID().uuidString)"

        // Houston: July 20
        let houstonGame = makeGame(
            stadiumId: houstonId,
            homeTeamId: teamId,
            awayTeamId: opponent1,
            dateTime: makeDate(month: 7, day: 20, hour: 19)
        )

        // Chicago: July 21 (only 1 day after Houston - ~20 hrs driving, needs 16 hrs max)
        // This is borderline but might work
        let chicagoGame = makeGame(
            stadiumId: chicagoId,
            homeTeamId: opponent2,
            awayTeamId: teamId,
            dateTime: makeDate(month: 7, day: 22, hour: 19)  // 2 days = 16 hrs max, needs ~20 hrs
        )

        // Anaheim: July 23 (only 1 day after Chicago - ~37 hrs driving, needs 8 hrs max)
        // This should definitely fail
        let anaheimGame = makeGame(
            stadiumId: anaheimId,
            homeTeamId: opponent3,
            awayTeamId: teamId,
            dateTime: makeDate(month: 7, day: 23, hour: 19)  // 1 day after Chicago = impossible
        )

        let request = makePlanningRequest(
            startDate: makeDate(month: 7, day: 18, hour: 0),
            endDate: makeDate(month: 7, day: 25, hour: 23),
            followTeamId: teamId,
            allGames: [houstonGame, chicagoGame, anaheimGame],
            stadiums: stadiums,
            allowRepeatCities: false
        )

        // Execute
        let result = planner.plan(request: request)

        // Verify - should succeed but without a 3-city route
        #expect(result.isSuccess, "Should still succeed with partial routes")

        // Should NOT have a 3-city route due to time constraints
        let threeCityOption = result.options.first { option in
            option.stops.count == 3 &&
            Set(option.stops.map { $0.city }) == Set(["Houston", "Chicago", "Anaheim"])
        }

        #expect(threeCityOption == nil,
               "Should NOT include Houston→Chicago→Anaheim route when timing is impossible")
    }

    @Test("D.4.3 - Router picks optimal game in city to make route feasible")
    func test_followTeam_PicksOptimalGamePerCity_ForRouteFeasibility() {
        // Setup: Team has 3 games in each city (series)
        // With allowRepeatCities=false, router should pick games that make the route work
        let chicagoId = "stadium_chicago_\(UUID().uuidString)"
        let anaheimId = "stadium_anaheim_\(UUID().uuidString)"

        let chicago = makeStadium(id: chicagoId, city: "Chicago", lat: 41.8781, lon: -87.6298)
        let anaheim = makeStadium(id: anaheimId, city: "Anaheim", lat: 33.8003, lon: -117.8827)

        let stadiums = [chicagoId: chicago, anaheimId: anaheim]

        let teamId = "team_test_\(UUID().uuidString)"
        let opponent1 = "team_opponent1_\(UUID().uuidString)"
        let opponent2 = "team_opponent2_\(UUID().uuidString)"

        // Chicago series: July 24, 25, 26
        let chicagoGame1 = makeGame(
            stadiumId: chicagoId,
            homeTeamId: opponent1,
            awayTeamId: teamId,
            dateTime: makeDate(month: 7, day: 24, hour: 19)
        )
        let chicagoGame2 = makeGame(
            stadiumId: chicagoId,
            homeTeamId: opponent1,
            awayTeamId: teamId,
            dateTime: makeDate(month: 7, day: 25, hour: 19)
        )
        let chicagoGame3 = makeGame(
            stadiumId: chicagoId,
            homeTeamId: opponent1,
            awayTeamId: teamId,
            dateTime: makeDate(month: 7, day: 26, hour: 19)
        )

        // Anaheim series: July 27, 28, 29
        // Chicago July 24 → Anaheim July 29 = 5 days = feasible (~37 hrs driving, 40 hrs available)
        // Chicago July 26 → Anaheim July 27 = 1 day = NOT feasible (~37 hrs driving, 8 hrs available)
        let anaheimGame1 = makeGame(
            stadiumId: anaheimId,
            homeTeamId: opponent2,
            awayTeamId: teamId,
            dateTime: makeDate(month: 7, day: 27, hour: 19)
        )
        let anaheimGame2 = makeGame(
            stadiumId: anaheimId,
            homeTeamId: opponent2,
            awayTeamId: teamId,
            dateTime: makeDate(month: 7, day: 28, hour: 19)
        )
        let anaheimGame3 = makeGame(
            stadiumId: anaheimId,
            homeTeamId: opponent2,
            awayTeamId: teamId,
            dateTime: makeDate(month: 7, day: 29, hour: 19)
        )

        let request = makePlanningRequest(
            startDate: makeDate(month: 7, day: 22, hour: 0),
            endDate: makeDate(month: 7, day: 31, hour: 23),
            followTeamId: teamId,
            allGames: [chicagoGame1, chicagoGame2, chicagoGame3, anaheimGame1, anaheimGame2, anaheimGame3],
            stadiums: stadiums,
            allowRepeatCities: false
        )

        // Execute
        let result = planner.plan(request: request)

        // Verify
        #expect(result.isSuccess, "Should succeed")

        // Should have a 2-city route (Chicago → Anaheim)
        let twoCityOption = result.options.first { option in
            option.stops.count == 2 &&
            Set(option.stops.map { $0.city }) == Set(["Chicago", "Anaheim"])
        }

        #expect(twoCityOption != nil, "Should include a Chicago→Anaheim route")
    }

    @Test("D.4.4 - Five-day driving segment at limit succeeds")
    func test_followTeam_FiveDaySegment_AtLimit_Succeeds() {
        // Setup: ~38 hours of driving with exactly 5 days between games
        // 5 days × 8 hours = 40 hours max, which should pass
        let seattleId = "stadium_seattle_\(UUID().uuidString)"
        let miamiId = "stadium_denver_\(UUID().uuidString)"

        // Seattle to Miami: ~3,300 miles straight line × 1.3 = ~4,300 miles
        // At 60 mph = ~72 hours - this is too far even for 5 days
        // Let's use a more reasonable pair: Seattle to Denver (~1,300 miles × 1.3 = ~1,700 miles = ~28 hrs)
        let seattle = makeStadium(id: seattleId, city: "Seattle", lat: 47.6062, lon: -122.3321)
        let denver = makeStadium(id: miamiId, city: "Denver", lat: 39.7392, lon: -104.9903)

        let stadiums = [seattleId: seattle, miamiId: denver]

        let teamId = "team_test_\(UUID().uuidString)"
        let opponent1 = "team_opponent1_\(UUID().uuidString)"
        let opponent2 = "team_opponent2_\(UUID().uuidString)"

        let seattleGame = makeGame(
            stadiumId: seattleId,
            homeTeamId: opponent1,
            awayTeamId: teamId,
            dateTime: makeDate(month: 7, day: 20, hour: 19)
        )

        // 4 days later = 32 hours max, ~28 hrs needed = should work
        let denverGame = makeGame(
            stadiumId: miamiId,
            homeTeamId: opponent2,
            awayTeamId: teamId,
            dateTime: makeDate(month: 7, day: 24, hour: 19)
        )

        let request = makePlanningRequest(
            startDate: makeDate(month: 7, day: 18, hour: 0),
            endDate: makeDate(month: 7, day: 26, hour: 23),
            followTeamId: teamId,
            allGames: [seattleGame, denverGame],
            stadiums: stadiums,
            allowRepeatCities: false
        )

        // Execute
        let result = planner.plan(request: request)

        // Verify
        #expect(result.isSuccess, "Should succeed with long-distance segment")

        let twoCityOption = result.options.first { option in
            option.stops.count == 2
        }

        #expect(twoCityOption != nil, "Should include 2-city route")

        if let option = twoCityOption {
            let cities = Set(option.stops.map { $0.city })
            #expect(cities.contains("Seattle"), "Should include Seattle")
            #expect(cities.contains("Denver"), "Should include Denver")
        }
    }

    @Test("D.4.5 - Segment exceeding 5-day driving limit is rejected")
    func test_followTeam_SegmentExceedingFiveDayLimit_IsRejected() {
        // Setup: Distance that would take > 40 hours to drive
        // Seattle to Miami: ~3,300 miles straight line × 1.3 = ~4,300 miles
        // At 60 mph = ~72 hours - exceeds 40 hour (5 day) limit
        let seattleId = "stadium_seattle_\(UUID().uuidString)"
        let miamiId = "stadium_miami_\(UUID().uuidString)"

        let seattle = makeStadium(id: seattleId, city: "Seattle", lat: 47.6062, lon: -122.3321)
        let miami = makeStadium(id: miamiId, city: "Miami", lat: 25.7617, lon: -80.1918)

        let stadiums = [seattleId: seattle, miamiId: miami]

        let teamId = "team_test_\(UUID().uuidString)"
        let opponent1 = "team_opponent1_\(UUID().uuidString)"
        let opponent2 = "team_opponent2_\(UUID().uuidString)"

        let seattleGame = makeGame(
            stadiumId: seattleId,
            homeTeamId: opponent1,
            awayTeamId: teamId,
            dateTime: makeDate(month: 7, day: 20, hour: 19)
        )

        // Even with 5 days, Seattle to Miami is impossible by car
        let miamiGame = makeGame(
            stadiumId: miamiId,
            homeTeamId: opponent2,
            awayTeamId: teamId,
            dateTime: makeDate(month: 7, day: 25, hour: 19)
        )

        let request = makePlanningRequest(
            startDate: makeDate(month: 7, day: 18, hour: 0),
            endDate: makeDate(month: 7, day: 27, hour: 23),
            followTeamId: teamId,
            allGames: [seattleGame, miamiGame],
            stadiums: stadiums,
            allowRepeatCities: false
        )

        // Execute
        let result = planner.plan(request: request)

        // Verify - should succeed but without a 2-city route
        #expect(result.isSuccess, "Should succeed with individual city options")

        // Should NOT have a Seattle→Miami route (too far)
        let twoCityOption = result.options.first { option in
            option.stops.count == 2 &&
            Set(option.stops.map { $0.city }) == Set(["Seattle", "Miami"])
        }

        #expect(twoCityOption == nil,
               "Should NOT include Seattle→Miami route (exceeds 5-day driving limit)")

        // Should have individual city options
        let singleCityOptions = result.options.filter { $0.stops.count == 1 }
        #expect(singleCityOptions.count >= 2, "Should have individual city options")
    }

    @Test("D.4.6 - Multiple drivers increases available driving time")
    func test_followTeam_MultipleDrivers_IncreasesAvailableTime() {
        // Setup: Same Chicago→Anaheim route but with 2 drivers
        // With 2 drivers × 8 hours = 16 hours/day
        // Chicago to Anaheim in 3 days = 48 hours available (vs 24 hours with 1 driver)
        let chicagoId = "stadium_chicago_\(UUID().uuidString)"
        let anaheimId = "stadium_anaheim_\(UUID().uuidString)"

        let chicago = makeStadium(id: chicagoId, city: "Chicago", lat: 41.8781, lon: -87.6298)
        let anaheim = makeStadium(id: anaheimId, city: "Anaheim", lat: 33.8003, lon: -117.8827)

        let stadiums = [chicagoId: chicago, anaheimId: anaheim]

        let teamId = "team_test_\(UUID().uuidString)"
        let opponent1 = "team_opponent1_\(UUID().uuidString)"
        let opponent2 = "team_opponent2_\(UUID().uuidString)"

        let chicagoGame = makeGame(
            stadiumId: chicagoId,
            homeTeamId: opponent1,
            awayTeamId: teamId,
            dateTime: makeDate(month: 7, day: 24, hour: 19)
        )

        // Only 3 days between games - with 1 driver (24 hrs max) this fails
        // With 2 drivers (48 hrs max) and 37.5 hrs needed, this should pass
        let anaheimGame = makeGame(
            stadiumId: anaheimId,
            homeTeamId: opponent2,
            awayTeamId: teamId,
            dateTime: makeDate(month: 7, day: 27, hour: 19)
        )

        let request = makePlanningRequest(
            startDate: makeDate(month: 7, day: 22, hour: 0),
            endDate: makeDate(month: 7, day: 29, hour: 23),
            followTeamId: teamId,
            allGames: [chicagoGame, anaheimGame],
            stadiums: stadiums,
            allowRepeatCities: false,
            numberOfDrivers: 2,  // Two drivers!
            maxDrivingHoursPerDriver: 8.0
        )

        // Execute
        let result = planner.plan(request: request)

        // Verify
        #expect(result.isSuccess, "Should succeed with 2 drivers")

        // Note: The TravelEstimator uses a fixed 5-day limit (40 hours with 1 driver at 8 hrs/day)
        // With 2 drivers, the limit is 5 × 16 = 80 hours
        // So 37.5 hours for Chicago→Anaheim should definitely work
        let twoCityOption = result.options.first { option in
            option.stops.count == 2
        }

        // This test verifies the constraint system respects numberOfDrivers
        #expect(twoCityOption != nil || result.options.count > 0,
               "Should have route options with multiple drivers")
    }
}
