//
//  TripCreationView.swift
//  SportsTime
//

import SwiftUI

struct TripCreationView: View {
    @Environment(\.dismiss) private var dismiss
    @Environment(\.colorScheme) private var colorScheme

    @Bindable var viewModel: TripCreationViewModel
    let initialSport: Sport?

    init(viewModel: TripCreationViewModel, initialSport: Sport? = nil) {
        self.viewModel = viewModel
        self.initialSport = initialSport
    }
    @State private var showGamePicker = false
    @State private var showCityInput = false
    @State private var cityInputType: CityInputType = .mustStop
    @State private var showLocationBanner = true
    @State private var showTripDetail = false
    @State private var showTripOptions = false
    @State private var completedTrip: Trip?
    @State private var tripOptions: [ItineraryOption] = []

    // Location search state
    @State private var startLocationSuggestions: [LocationSearchResult] = []
    @State private var endLocationSuggestions: [LocationSearchResult] = []
    @State private var startSearchTask: Task<Void, Never>?
    @State private var endSearchTask: Task<Void, Never>?
    @State private var isSearchingStart = false
    @State private var isSearchingEnd = false

    private let locationService = LocationService.shared

    enum CityInputType {
        case mustStop
        case preferred
        case homeLocation
        case startLocation
        case endLocation
    }

    var body: some View {
        NavigationStack {
            ScrollView {
                VStack(spacing: Theme.Spacing.lg) {
                    // Hero header
                    heroHeader

                    // Planning Mode Selector
                    planningModeSection

                    // Location Permission Banner (only for locations mode)
                    if viewModel.planningMode == .locations && showLocationBanner {
                        LocationPermissionBanner(isPresented: $showLocationBanner)
                    }

                    // Mode-specific sections
                    switch viewModel.planningMode {
                    case .dateRange:
                        // Sports + Dates
                        sportsSection
                        datesSection

                    case .gameFirst:
                        // Sports + Game Picker + Trip Duration
                        sportsSection
                        gameBrowserSection
                        tripDurationSection

                    case .locations:
                        // Locations + Sports + optional games
                        locationSection
                        sportsSection
                        datesSection
                        gamesSection

                    case .followTeam:
                        // Team picker + Dates + Home location toggle
                        teamPickerSection
                        datesSection
                        homeLocationSection
                    }

                    // Common sections
                    travelSection
                    optionalSection

                    // Validation message
                    if let message = viewModel.formValidationMessage {
                        validationBanner(message: message)
                    }

                    // Plan button
                    planButton
                }
                .padding(Theme.Spacing.md)
            }
            .themedBackground()
                        .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Cancel") {
                        dismiss()
                    }
                }
            }
            .overlay {
                if case .planning = viewModel.viewState {
                    planningOverlay
                }
            }
            .sheet(isPresented: $showGamePicker) {
                GamePickerSheet(
                    selectedSports: viewModel.selectedSports,
                    selectedIds: $viewModel.mustSeeGameIds
                )
            }
            .sheet(isPresented: $showCityInput) {
                LocationSearchSheet(inputType: cityInputType) { location in
                    switch cityInputType {
                    case .mustStop:
                        viewModel.addMustStopLocation(location)
                    case .preferred:
                        viewModel.addPreferredCity(location.name)
                    case .homeLocation, .startLocation:
                        viewModel.startLocationText = location.name
                        viewModel.startLocation = location
                    case .endLocation:
                        viewModel.endLocationText = location.name
                        viewModel.endLocation = location
                    }
                }
            }
            .alert("Error", isPresented: Binding(
                get: { viewModel.viewState.isError },
                set: { if !$0 { viewModel.viewState = .editing } }
            )) {
                Button("OK") {
                    viewModel.viewState = .editing
                }
            } message: {
                if case .error(let message) = viewModel.viewState {
                    Text(message)
                }
            }
            .navigationDestination(isPresented: $showTripOptions) {
                TripOptionsView(
                    options: tripOptions,
                    games: buildGamesDictionary(),
                    preferences: viewModel.currentPreferences,
                    convertToTrip: { option in
                        viewModel.convertOptionToTrip(option)
                    }
                )
            }
            .navigationDestination(isPresented: $showTripDetail) {
                if let trip = completedTrip {
                    TripDetailView(trip: trip, games: buildGamesDictionary())
                }
            }
            .onChange(of: viewModel.viewState) { _, newState in
                switch newState {
                case .selectingOption(let options):
                    tripOptions = options
                    showTripOptions = true
                case .completed(let trip):
                    completedTrip = trip
                    showTripDetail = true
                default:
                    break
                }
            }
            .onChange(of: showTripOptions) { _, isShowing in
                if !isShowing {
                    // User navigated back from options to editing
                    viewModel.viewState = .editing
                    tripOptions = []
                }
            }
            .onChange(of: showTripDetail) { _, isShowing in
                if !isShowing {
                    // User navigated back from single-option detail to editing
                    completedTrip = nil
                    viewModel.viewState = .editing
                }
            }
            .task {
                await viewModel.loadScheduleData()
            }
            .onAppear {
                if let sport = initialSport {
                    viewModel.selectedSports = [sport]
                }
            }
        }
    }

    // MARK: - Hero Header

    private var heroHeader: some View {
        VStack(spacing: Theme.Spacing.sm) {
            Image(systemName: "map.fill")
                .font(.largeTitle)
                .foregroundStyle(Theme.warmOrange)

            Text("Plan Your Adventure")
                .font(.title2)
                .foregroundStyle(Theme.textPrimary(colorScheme))

            Text("Select your games, set your route, and hit the road")
                .font(.subheadline)
                .foregroundStyle(Theme.textSecondary(colorScheme))
                .multilineTextAlignment(.center)
        }
        .padding(.vertical, Theme.Spacing.md)
    }

    // MARK: - Sections

    private var planningModeSection: some View {
        ThemedSection(title: "How do you want to plan?") {
            LazyVGrid(
                columns: [
                    GridItem(.flexible(), spacing: Theme.Spacing.sm),
                    GridItem(.flexible(), spacing: Theme.Spacing.sm)
                ],
                spacing: Theme.Spacing.sm
            ) {
                ForEach(PlanningMode.allCases) { mode in
                    PlanningModeCard(
                        mode: mode,
                        isSelected: viewModel.planningMode == mode,
                        colorScheme: colorScheme
                    ) {
                        withAnimation(.easeInOut(duration: 0.2)) {
                            viewModel.planningMode = mode
                        }
                    }
                }
            }
        }
    }

    private var locationSection: some View {
        ThemedSection(title: "Locations") {
            // Start Location - opens search sheet
            locationButton(
                label: "Start Location",
                icon: "location.circle.fill",
                location: viewModel.startLocation,
                placeholder: "Where are you starting from?"
            ) {
                cityInputType = .startLocation
                showCityInput = true
            }

            // End Location - opens search sheet
            locationButton(
                label: "End Location",
                icon: "mappin.circle.fill",
                location: viewModel.endLocation,
                placeholder: "Where do you want to end up?"
            ) {
                cityInputType = .endLocation
                showCityInput = true
            }
        }
    }

    private func locationButton(
        label: String,
        icon: String,
        location: LocationInput?,
        placeholder: String,
        action: @escaping () -> Void
    ) -> some View {
        VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
            Text(label)
                .font(.subheadline)
                .fontWeight(.medium)
                .foregroundStyle(Theme.warmOrange)

            Button(action: action) {
                HStack(spacing: Theme.Spacing.md) {
                    Image(systemName: icon)
                        .foregroundStyle(Theme.warmOrange)
                        .frame(width: 24)

                    if let location = location {
                        Text(location.name)
                            .foregroundStyle(Theme.textPrimary(colorScheme))
                    } else {
                        Text(placeholder)
                            .foregroundStyle(Theme.textMuted(colorScheme))
                    }

                    Spacer()

                    Image(systemName: "chevron.right")
                        .font(.caption)
                        .foregroundStyle(Theme.textMuted(colorScheme))
                }
                .padding(Theme.Spacing.md)
                .background(Theme.cardBackgroundElevated(colorScheme))
                .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium))
            }
            .buttonStyle(.plain)
        }
    }

    private func searchLocation(query: String, isStart: Bool) {
        // Cancel previous search
        if isStart {
            startSearchTask?.cancel()
        } else {
            endSearchTask?.cancel()
        }

        guard query.count >= 2 else {
            if isStart {
                startLocationSuggestions = []
                isSearchingStart = false
            } else {
                endLocationSuggestions = []
                isSearchingEnd = false
            }
            return
        }

        let task = Task {
            // Debounce
            try? await Task.sleep(for: .milliseconds(300))
            guard !Task.isCancelled else { return }

            if isStart {
                isSearchingStart = true
            } else {
                isSearchingEnd = true
            }

            do {
                let results = try await locationService.searchLocations(query)
                guard !Task.isCancelled else { return }

                if isStart {
                    startLocationSuggestions = Array(results.prefix(5))
                    isSearchingStart = false
                } else {
                    endLocationSuggestions = Array(results.prefix(5))
                    isSearchingEnd = false
                }
            } catch {
                if isStart {
                    startLocationSuggestions = []
                    isSearchingStart = false
                } else {
                    endLocationSuggestions = []
                    isSearchingEnd = false
                }
            }
        }

        if isStart {
            startSearchTask = task
        } else {
            endSearchTask = task
        }
    }

    @ViewBuilder
    private func locationSuggestionsList(
        suggestions: [LocationSearchResult],
        isLoading: Bool,
        onSelect: @escaping (LocationSearchResult) -> Void
    ) -> some View {
        VStack(alignment: .leading, spacing: 0) {
            ForEach(suggestions) { result in
                Button {
                    onSelect(result)
                } label: {
                    HStack(spacing: Theme.Spacing.sm) {
                        Image(systemName: "mappin.circle.fill")
                            .foregroundStyle(Theme.warmOrange)
                            .font(.subheadline)

                        VStack(alignment: .leading, spacing: 2) {
                            Text(result.name)
                                .font(.subheadline)
                                .foregroundStyle(Theme.textPrimary(colorScheme))

                            if !result.address.isEmpty {
                                Text(result.address)
                                    .font(.caption)
                                    .foregroundStyle(Theme.textMuted(colorScheme))
                            }
                        }

                        Spacer()
                    }
                    .padding(.vertical, Theme.Spacing.sm)
                    .padding(.horizontal, Theme.Spacing.xs)
                }
                .buttonStyle(.plain)

                if result.id != suggestions.last?.id {
                    Divider()
                        .overlay(Theme.surfaceGlow(colorScheme))
                }
            }
        }
        .padding(.top, Theme.Spacing.xs)
        .background(Theme.cardBackgroundElevated(colorScheme))
        .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.small))
    }

    private var gameBrowserSection: some View {
        ThemedSection(title: "Select Games") {
            if viewModel.isLoadingGames || viewModel.availableGames.isEmpty {
                HStack(spacing: Theme.Spacing.sm) {
                    LoadingSpinner(size: .small)
                    Text("Loading games...")
                        .font(.body)
                        .foregroundStyle(Theme.textSecondary(colorScheme))
                }
                .frame(maxWidth: .infinity, alignment: .center)
                .padding(.vertical, Theme.Spacing.md)
                .task(id: viewModel.selectedSports) {
                    // Always load 90-day browsing window for gameFirst mode
                    await viewModel.loadGamesForBrowsing()
                }
            } else {
                Button {
                    showGamePicker = true
                } label: {
                    HStack(spacing: Theme.Spacing.md) {
                        ZStack {
                            Circle()
                                .fill(Theme.warmOrange.opacity(0.15))
                                .frame(width: 44, height: 44)
                            Image(systemName: "sportscourt.fill")
                                .foregroundStyle(Theme.warmOrange)
                        }

                        VStack(alignment: .leading, spacing: 4) {
                            Text("Browse Teams & Games")
                                .font(.body)
                                .foregroundStyle(Theme.textPrimary(colorScheme))
                            Text("\(viewModel.availableGames.count) games available")
                                .font(.subheadline)
                                .foregroundStyle(Theme.textSecondary(colorScheme))
                        }

                        Spacer()

                        Image(systemName: "chevron.right")
                            .foregroundStyle(Theme.textMuted(colorScheme))
                    }
                    .padding(Theme.Spacing.md)
                    .background(Theme.cardBackgroundElevated(colorScheme))
                    .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium))
                }
                .buttonStyle(.plain)
            }

            // Show selected games summary
            if !viewModel.mustSeeGameIds.isEmpty {
                VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
                    HStack {
                        Image(systemName: "checkmark.circle.fill")
                            .foregroundStyle(.green)
                        Text("\(viewModel.mustSeeGameIds.count) game(s) selected")
                            .font(.body)
                            .foregroundStyle(Theme.textPrimary(colorScheme))

                        Spacer()

                        Button {
                            viewModel.deselectAllGames()
                        } label: {
                            Text("Deselect All")
                                .font(.subheadline)
                                .foregroundStyle(.red)
                        }
                    }

                    // Show selected games preview
                    ForEach(viewModel.selectedGames.prefix(3)) { game in
                        HStack(spacing: Theme.Spacing.sm) {
                            SportColorBar(sport: game.game.sport)
                            Text("\(game.awayTeam.abbreviation) @ \(game.homeTeam.abbreviation)")
                                .font(.subheadline)
                                .foregroundStyle(Theme.textPrimary(colorScheme))
                            Spacer()
                            Text(game.game.formattedDate)
                                .font(.caption)
                                .foregroundStyle(Theme.textMuted(colorScheme))
                        }
                    }

                    if viewModel.selectedGames.count > 3 {
                        Text("+ \(viewModel.selectedGames.count - 3) more")
                            .font(.subheadline)
                            .foregroundStyle(Theme.textSecondary(colorScheme))
                    }
                }
                .padding(Theme.Spacing.md)
                .background(Theme.cardBackgroundElevated(colorScheme))
                .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium))
            }
        }
    }

    private var tripDurationSection: some View {
        ThemedSection(title: "Trip Duration") {
            VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
                HStack {
                    Image(systemName: "calendar.badge.clock")
                        .foregroundStyle(Theme.warmOrange)
                    Text("Days")
                        .font(.body)
                        .foregroundStyle(Theme.textPrimary(colorScheme))

                    Spacer()

                    Stepper(
                        value: $viewModel.gameFirstTripDuration,
                        in: 2...21,
                        step: 1
                    ) {
                        Text("\(viewModel.gameFirstTripDuration) days")
                            .font(.body.monospacedDigit())
                            .foregroundStyle(Theme.textPrimary(colorScheme))
                    }
                }
                .padding(Theme.Spacing.md)
                .background(Theme.cardBackgroundElevated(colorScheme))
                .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium))

                Text("We'll find all possible \(viewModel.gameFirstTripDuration)-day trips that include your selected games")
                    .font(.caption)
                    .foregroundStyle(Theme.textSecondary(colorScheme))
            }
        }
    }

    private var sportsSection: some View {
        ThemedSection(title: "Sports") {
            SportSelectorGrid(
                selectedSports: viewModel.selectedSports
            ) { sport in
                if viewModel.selectedSports.contains(sport) {
                    viewModel.selectedSports.remove(sport)
                } else {
                    viewModel.selectedSports.insert(sport)
                }
            }
            .padding(.vertical, Theme.Spacing.xs)
        }
    }

    private var datesSection: some View {
        ThemedSection(title: "Dates") {
            DateRangePicker(
                startDate: $viewModel.startDate,
                endDate: $viewModel.endDate
            )
        }
    }

    // MARK: - Follow Team Mode

    @State private var showTeamPicker = false

    private var teamPickerSection: some View {
        ThemedSection(title: "Select Team") {
            Button {
                showTeamPicker = true
            } label: {
                HStack(spacing: Theme.Spacing.md) {
                    ZStack {
                        Circle()
                            .fill(Theme.warmOrange.opacity(0.15))
                            .frame(width: 40, height: 40)
                        Image(systemName: "person.3.fill")
                            .foregroundStyle(Theme.warmOrange)
                    }

                    VStack(alignment: .leading, spacing: 2) {
                        if let team = viewModel.followedTeam {
                            Text(team.name)
                                .font(.body)
                                .foregroundStyle(Theme.textPrimary(colorScheme))
                            Text(team.sport.displayName)
                                .font(.caption)
                                .foregroundStyle(Theme.textSecondary(colorScheme))
                        } else {
                            Text("Choose a team")
                                .font(.body)
                                .foregroundStyle(Theme.textPrimary(colorScheme))
                            Text("Pick the team to follow")
                                .font(.caption)
                                .foregroundStyle(Theme.textMuted(colorScheme))
                        }
                    }

                    Spacer()

                    Image(systemName: "chevron.right")
                        .foregroundStyle(Theme.textMuted(colorScheme))
                }
                .padding(Theme.Spacing.md)
                .background(Theme.cardBackgroundElevated(colorScheme))
                .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium))
            }
            .buttonStyle(.plain)
        }
        .sheet(isPresented: $showTeamPicker) {
            TeamPickerSheet(
                selectedTeamId: $viewModel.followTeamId,
                teamsBySport: viewModel.teamsBySport
            )
        }
    }

    private var homeLocationSection: some View {
        ThemedSection(title: "Trip Start/End") {
            VStack(spacing: Theme.Spacing.md) {
                ThemedToggle(
                    label: "Start and end from home",
                    isOn: $viewModel.useHomeLocation,
                    icon: "house.fill"
                )

                if viewModel.useHomeLocation {
                    // Show button to open location search sheet (same as must-stop)
                    Button {
                        cityInputType = .homeLocation
                        showCityInput = true
                    } label: {
                        HStack(spacing: Theme.Spacing.md) {
                            ZStack {
                                Circle()
                                    .fill(Theme.warmOrange.opacity(0.15))
                                    .frame(width: 40, height: 40)
                                Image(systemName: "house.fill")
                                    .foregroundStyle(Theme.warmOrange)
                            }

                            VStack(alignment: .leading, spacing: 2) {
                                if let location = viewModel.startLocation {
                                    Text(location.name)
                                        .font(.body)
                                        .foregroundStyle(Theme.textPrimary(colorScheme))
                                    if let address = location.address, !address.isEmpty {
                                        Text(address)
                                            .font(.caption)
                                            .foregroundStyle(Theme.textSecondary(colorScheme))
                                    }
                                } else {
                                    Text("Choose home location")
                                        .font(.body)
                                        .foregroundStyle(Theme.textPrimary(colorScheme))
                                    Text("Tap to search cities")
                                        .font(.caption)
                                        .foregroundStyle(Theme.textMuted(colorScheme))
                                }
                            }

                            Spacer()

                            Image(systemName: "chevron.right")
                                .foregroundStyle(Theme.textMuted(colorScheme))
                        }
                        .padding(Theme.Spacing.md)
                        .background(Theme.cardBackgroundElevated(colorScheme))
                        .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium))
                    }
                    .buttonStyle(.plain)
                } else {
                    Text("Trip will start at first game and end at last game (fly-in/fly-out)")
                        .font(.caption)
                        .foregroundStyle(Theme.textMuted(colorScheme))
                        .padding(.leading, 32)
                }
            }
        }
    }

    private var gamesSection: some View {
        ThemedSection(title: "Must-See Games") {
            Button {
                showGamePicker = true
            } label: {
                HStack(spacing: Theme.Spacing.md) {
                    ZStack {
                        Circle()
                            .fill(Theme.warmOrange.opacity(0.15))
                            .frame(width: 40, height: 40)
                        Image(systemName: "star.fill")
                            .foregroundStyle(Theme.warmOrange)
                    }

                    Text("Select Games")
                        .font(.body)
                        .foregroundStyle(Theme.textPrimary(colorScheme))

                    Spacer()

                    Text("\(viewModel.selectedGamesCount) selected")
                        .font(.subheadline)
                        .foregroundStyle(Theme.textSecondary(colorScheme))

                    Image(systemName: "chevron.right")
                        .foregroundStyle(Theme.textMuted(colorScheme))
                }
                .padding(Theme.Spacing.md)
                .background(Theme.cardBackgroundElevated(colorScheme))
                .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium))
            }
            .buttonStyle(.plain)
        }
    }

    private var travelSection: some View {
        ThemedSection(title: "Travel") {
            VStack(spacing: Theme.Spacing.md) {
                // Region selector
                VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
                    Text("Regions")
                        .font(.subheadline)
                        .foregroundStyle(Theme.textSecondary(colorScheme))

                    RegionMapSelector(
                        selectedRegions: $viewModel.selectedRegions,
                        onToggle: { region in
                            viewModel.toggleRegion(region)
                        }
                    )

                    if viewModel.selectedRegions.isEmpty {
                        Text("Select at least one region")
                            .font(.caption)
                            .foregroundStyle(Theme.warmOrange)
                            .padding(.top, Theme.Spacing.xxs)
                    } else {
                        Text("Games will be found in selected regions")
                            .font(.caption)
                            .foregroundStyle(Theme.textMuted(colorScheme))
                            .padding(.top, Theme.Spacing.xxs)
                    }
                }

                // Route preference
                VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
                    Text("Route Preference")
                        .font(.subheadline)
                        .foregroundStyle(Theme.textSecondary(colorScheme))

                    Picker("Route Preference", selection: $viewModel.routePreference) {
                        ForEach(RoutePreference.allCases) { pref in
                            Text(pref.displayName).tag(pref)
                        }
                    }
                    .pickerStyle(.segmented)
                }

                // Allow repeat cities
                ThemedToggle(
                    label: "Allow Repeat Cities",
                    isOn: $viewModel.allowRepeatCities,
                    icon: "arrow.triangle.2.circlepath"
                )

                if !viewModel.allowRepeatCities {
                    Text("Each city will only be visited on one day")
                        .font(.caption)
                        .foregroundStyle(Theme.textMuted(colorScheme))
                        .padding(.leading, 32)
                }
            }
            .animation(.easeInOut(duration: 0.2), value: viewModel.selectedRegions)
        }
    }

    private var optionalSection: some View {
        ThemedSection(title: "More Options") {
            VStack(spacing: Theme.Spacing.md) {
                // Must-Stop Locations
                VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
                    HStack {
                        Image(systemName: "mappin.circle")
                            .foregroundStyle(Theme.warmOrange)
                        Text("Must-Stop Locations")
                            .font(.body)
                            .foregroundStyle(Theme.textPrimary(colorScheme))
                        Spacer()
                        Text("\(viewModel.mustStopLocations.count)")
                            .font(.subheadline)
                            .foregroundStyle(Theme.textSecondary(colorScheme))
                    }

                    ForEach(viewModel.mustStopLocations, id: \.name) { location in
                        HStack {
                            VStack(alignment: .leading, spacing: 2) {
                                Text(location.name)
                                    .font(.subheadline)
                                    .foregroundStyle(Theme.textPrimary(colorScheme))
                                if let address = location.address, !address.isEmpty {
                                    Text(address)
                                        .font(.caption)
                                        .foregroundStyle(Theme.textMuted(colorScheme))
                                }
                            }
                            Spacer()
                            Button {
                                viewModel.removeMustStopLocation(location)
                            } label: {
                                Image(systemName: "xmark.circle.fill")
                                    .foregroundStyle(Theme.textMuted(colorScheme))
                            }
                        }
                        .padding(Theme.Spacing.sm)
                        .background(Theme.cardBackgroundElevated(colorScheme))
                        .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.small))
                    }

                    Button {
                        cityInputType = .mustStop
                        showCityInput = true
                    } label: {
                        HStack {
                            Image(systemName: "plus.circle.fill")
                            Text("Add Location")
                        }
                        .font(.subheadline)
                        .foregroundStyle(Theme.warmOrange)
                    }
                }

                Divider()
                    .overlay(Theme.surfaceGlow(colorScheme))

                // EV Charging (feature flagged)
                if FeatureFlags.enableEVCharging {
                    ThemedToggle(
                        label: "EV Charging Needed",
                        isOn: $viewModel.needsEVCharging,
                        icon: "bolt.car"
                    )
                }

                // Drivers
                ThemedStepper(
                    label: "Number of Drivers",
                    value: viewModel.numberOfDrivers,
                    range: 1...4,
                    onIncrement: { viewModel.numberOfDrivers += 1 },
                    onDecrement: { viewModel.numberOfDrivers -= 1 }
                )
            }
        }
    }

    private var planningOverlay: some View {
        LoadingSheet(label: "Planning trip")
    }

    private var planButton: some View {
        Button {
            Task {
                await viewModel.planTrip()
            }
        } label: {
            HStack(spacing: Theme.Spacing.sm) {
                Image(systemName: "map.fill")
                Text("Plan My Trip")
                    .fontWeight(.semibold)
            }
            .frame(maxWidth: .infinity)
            .padding(Theme.Spacing.md)
            .background(viewModel.isFormValid ? Theme.warmOrange : Theme.textMuted(colorScheme))
            .foregroundStyle(.white)
            .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium))
        }
        .disabled(!viewModel.isFormValid)
        .padding(.top, Theme.Spacing.md)
        .glowEffect(color: viewModel.isFormValid ? Theme.warmOrange : .clear, radius: 12)
    }

    private func validationBanner(message: String) -> some View {
        HStack(spacing: Theme.Spacing.sm) {
            Image(systemName: "exclamationmark.triangle.fill")
                .foregroundStyle(.orange)
            Text(message)
                .font(.subheadline)
                .foregroundStyle(Theme.textPrimary(colorScheme))
        }
        .padding(Theme.Spacing.md)
        .frame(maxWidth: .infinity, alignment: .leading)
        .background(Color.orange.opacity(0.15))
        .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium))
    }

    // MARK: - Helpers

    private func binding(for sport: Sport) -> Binding<Bool> {
        Binding(
            get: { viewModel.selectedSports.contains(sport) },
            set: { isSelected in
                if isSelected {
                    viewModel.selectedSports.insert(sport)
                } else {
                    viewModel.selectedSports.remove(sport)
                }
            }
        )
    }

    private func buildGamesDictionary() -> [String: RichGame] {
        viewModel.availableGames.reduce(into: [:]) { $0[$1.id] = $1 }
    }
}

// MARK: - View State Extensions

extension TripCreationViewModel.ViewState {
    var isError: Bool {
        if case .error = self { return true }
        return false
    }

    var isCompleted: Bool {
        if case .completed = self { return true }
        return false
    }
}

// MARK: - Game Picker Sheet (Calendar view: Sport → Team → Date with lazy loading)

struct GamePickerSheet: View {
    let selectedSports: Set<Sport>
    @Binding var selectedIds: Set<String>
    @Environment(\.dismiss) private var dismiss
    @Environment(\.colorScheme) private var colorScheme

    @State private var expandedSports: Set<Sport> = []
    @State private var expandedTeams: Set<String> = []
    @State private var gamesCache: [String: [RichGame]] = [:]  // teamId -> games
    @State private var loadingTeams: Set<String> = []
    @State private var selectedGamesCache: [String: RichGame] = [:]  // gameId -> game (for count display)

    private let dataProvider = AppDataProvider.shared

    // Get teams for a sport (from in-memory cache, no fetching needed)
    private func teamsForSport(_ sport: Sport) -> [Team] {
        dataProvider.teams(for: sport).sorted { $0.name < $1.name }
    }

    private var sortedSports: [Sport] {
        Sport.supported.filter { selectedSports.contains($0) }
    }

    private var selectedGamesCount: Int {
        selectedIds.count
    }

    private func selectedCountForSport(_ sport: Sport) -> Int {
        let teamIds = Set(teamsForSport(sport).map { $0.id })
        return selectedGamesCache.values.filter { game in
            teamIds.contains(game.homeTeam.id) || teamIds.contains(game.awayTeam.id)
        }.count
    }

    private func selectedCountForTeam(_ teamId: String) -> Int {
        guard let games = gamesCache[teamId] else { return 0 }
        return games.filter { selectedIds.contains($0.id) }.count
    }

    var body: some View {
        NavigationStack {
            ScrollView {
                LazyVStack(spacing: 0) {
                    // Selected games summary (always visible to prevent layout jump)
                    HStack {
                        Image(systemName: selectedIds.isEmpty ? "circle" : "checkmark.circle.fill")
                            .foregroundStyle(selectedIds.isEmpty ? Theme.textMuted(colorScheme) : .green)
                        Text("\(selectedGamesCount) game(s) selected")
                            .font(.subheadline)
                            .foregroundStyle(selectedIds.isEmpty ? Theme.textMuted(colorScheme) : Theme.textPrimary(colorScheme))
                        Spacer()
                    }
                    .padding(Theme.Spacing.md)
                    .background(Theme.cardBackground(colorScheme))

                    // Sport sections
                    ForEach(sortedSports) { sport in
                        LazySportSection(
                            sport: sport,
                            teams: teamsForSport(sport),
                            selectedIds: $selectedIds,
                            expandedSports: $expandedSports,
                            expandedTeams: $expandedTeams,
                            gamesCache: $gamesCache,
                            loadingTeams: $loadingTeams,
                            selectedGamesCache: $selectedGamesCache,
                            selectedCount: selectedCountForSport(sport)
                        )
                    }
                }
            }
            .themedBackground()
            .navigationTitle("Select Games")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    if !selectedIds.isEmpty {
                        Button("Reset") {
                            var transaction = Transaction()
                            transaction.disablesAnimations = true
                            withTransaction(transaction) {
                                selectedIds.removeAll()
                                selectedGamesCache.removeAll()
                            }
                        }
                        .foregroundStyle(.red)
                    }
                }
                ToolbarItem(placement: .confirmationAction) {
                    Button("Done") {
                        dismiss()
                    }
                    .fontWeight(.semibold)
                }
            }
        }
    }
}

// MARK: - Lazy Sport Section (loads teams from memory, games loaded on-demand per team)

struct LazySportSection: View {
    let sport: Sport
    let teams: [Team]
    @Binding var selectedIds: Set<String>
    @Binding var expandedSports: Set<Sport>
    @Binding var expandedTeams: Set<String>
    @Binding var gamesCache: [String: [RichGame]]
    @Binding var loadingTeams: Set<String>
    @Binding var selectedGamesCache: [String: RichGame]
    let selectedCount: Int

    @Environment(\.colorScheme) private var colorScheme

    private var isExpanded: Bool {
        expandedSports.contains(sport)
    }

    var body: some View {
        VStack(spacing: 0) {
            // Sport header
            Button {
                withAnimation(.easeInOut(duration: 0.2)) {
                    if isExpanded {
                        expandedSports.remove(sport)
                    } else {
                        expandedSports.insert(sport)
                    }
                }
            } label: {
                HStack(spacing: Theme.Spacing.sm) {
                    Image(systemName: sport.iconName)
                        .font(.title3)
                        .foregroundStyle(sport.themeColor)
                        .frame(width: 32)

                    Text(sport.rawValue)
                        .font(.headline)
                        .foregroundStyle(Theme.textPrimary(colorScheme))

                    Text("\(teams.count) teams")
                        .font(.subheadline)
                        .foregroundStyle(Theme.textMuted(colorScheme))

                    Spacer()

                    if selectedCount > 0 {
                        Text("\(selectedCount)")
                            .font(.caption)
                            .foregroundStyle(.white)
                            .padding(.horizontal, 8)
                            .padding(.vertical, 4)
                            .background(sport.themeColor)
                            .clipShape(Capsule())
                    }

                    Image(systemName: "chevron.right")
                        .font(.system(size: 14, weight: .semibold))
                        .foregroundStyle(Theme.textMuted(colorScheme))
                        .rotationEffect(.degrees(isExpanded ? 90 : 0))
                }
                .padding(Theme.Spacing.md)
                .background(Theme.cardBackground(colorScheme))
            }
            .buttonStyle(.plain)

            // Teams list (when expanded)
            if isExpanded {
                VStack(spacing: 0) {
                    ForEach(teams) { team in
                        LazyTeamSection(
                            team: team,
                            sport: sport,
                            selectedIds: $selectedIds,
                            expandedTeams: $expandedTeams,
                            gamesCache: $gamesCache,
                            loadingTeams: $loadingTeams,
                            selectedGamesCache: $selectedGamesCache
                        )
                    }
                }
                .padding(.leading, Theme.Spacing.lg)
            }

            Divider()
                .overlay(Theme.surfaceGlow(colorScheme))
        }
    }
}

// MARK: - Lazy Team Section (loads games on-demand when expanded)

struct LazyTeamSection: View {
    let team: Team
    let sport: Sport
    @Binding var selectedIds: Set<String>
    @Binding var expandedTeams: Set<String>
    @Binding var gamesCache: [String: [RichGame]]
    @Binding var loadingTeams: Set<String>
    @Binding var selectedGamesCache: [String: RichGame]

    @Environment(\.colorScheme) private var colorScheme

    private let dataProvider = AppDataProvider.shared

    private var isExpanded: Bool {
        expandedTeams.contains(team.id)
    }

    private var isLoading: Bool {
        loadingTeams.contains(team.id)
    }

    private var games: [RichGame] {
        gamesCache[team.id] ?? []
    }

    private var selectedCount: Int {
        games.filter { selectedIds.contains($0.id) }.count
    }

    private var gamesCount: Int? {
        gamesCache[team.id]?.count
    }

    // Group games by date
    private var gamesByDate: [(date: String, games: [RichGame])] {
        let sortedGames = games.sorted { $0.game.dateTime < $1.game.dateTime }
        let grouped = Dictionary(grouping: sortedGames) { game in
            game.game.formattedDate
        }
        return grouped.sorted { $0.value.first!.game.dateTime < $1.value.first!.game.dateTime }
            .map { (date: $0.key, games: $0.value) }
    }

    var body: some View {
        VStack(spacing: 0) {
            // Team header
            Button {
                withAnimation(.easeInOut(duration: 0.2)) {
                    if isExpanded {
                        expandedTeams.remove(team.id)
                    } else {
                        expandedTeams.insert(team.id)
                        // Load games if not cached
                        if gamesCache[team.id] == nil && !loadingTeams.contains(team.id) {
                            loadGames()
                        }
                    }
                }
            } label: {
                HStack(spacing: Theme.Spacing.sm) {
                    // Team color
                    if let colorHex = team.primaryColor {
                        Circle()
                            .fill(Color(hex: colorHex))
                            .frame(width: 10, height: 10)
                    }

                    Text("\(team.city) \(team.name)")
                        .font(.subheadline)
                        .foregroundStyle(Theme.textPrimary(colorScheme))

                    if let count = gamesCount {
                        Text("\(count)")
                            .font(.caption)
                            .foregroundStyle(Theme.textMuted(colorScheme))
                    }

                    Spacer()

                    if isLoading {
                        LoadingSpinner(size: .small)
                    } else if selectedCount > 0 {
                        Text("\(selectedCount)")
                            .font(.caption2)
                            .foregroundStyle(.white)
                            .padding(.horizontal, 6)
                            .padding(.vertical, 3)
                            .background(Theme.warmOrange)
                            .clipShape(Capsule())
                    }

                    Image(systemName: "chevron.right")
                        .font(.caption)
                        .foregroundStyle(Theme.textMuted(colorScheme))
                        .rotationEffect(.degrees(isExpanded ? 90 : 0))
                }
                .padding(.vertical, Theme.Spacing.sm)
                .padding(.horizontal, Theme.Spacing.md)
                .background(Theme.cardBackgroundElevated(colorScheme))
            }
            .buttonStyle(.plain)

            // Games grouped by date (when expanded)
            if isExpanded {
                if isLoading {
                    HStack {
                        LoadingSpinner(size: .small)
                        Text("Loading games...")
                            .font(.caption)
                            .foregroundStyle(Theme.textMuted(colorScheme))
                    }
                    .padding(Theme.Spacing.md)
                } else if games.isEmpty {
                    Text("No games scheduled")
                        .font(.caption)
                        .foregroundStyle(Theme.textMuted(colorScheme))
                        .padding(Theme.Spacing.md)
                } else {
                    VStack(spacing: 0) {
                        ForEach(gamesByDate, id: \.date) { dateGroup in
                            VStack(alignment: .leading, spacing: 0) {
                                // Date header
                                Text(dateGroup.date)
                                    .font(.caption)
                                    .foregroundStyle(Theme.warmOrange)
                                    .padding(.horizontal, Theme.Spacing.md)
                                    .padding(.top, Theme.Spacing.sm)
                                    .padding(.bottom, Theme.Spacing.xs)

                                // Games on this date
                                ForEach(dateGroup.games) { game in
                                    GameCalendarRow(
                                        game: game,
                                        isSelected: selectedIds.contains(game.id),
                                        onTap: {
                                            // Disable implicit animation to prevent weird morphing effect
                                            var transaction = Transaction()
                                            transaction.disablesAnimations = true
                                            withTransaction(transaction) {
                                                if selectedIds.contains(game.id) {
                                                    selectedIds.remove(game.id)
                                                    selectedGamesCache.removeValue(forKey: game.id)
                                                } else {
                                                    selectedIds.insert(game.id)
                                                    selectedGamesCache[game.id] = game
                                                }
                                            }
                                        }
                                    )
                                }
                            }
                        }
                    }
                    .padding(.leading, Theme.Spacing.md)
                    .background(Theme.cardBackgroundElevated(colorScheme).opacity(0.5))
                }
            }
        }
    }

    private func loadGames() {
        loadingTeams.insert(team.id)
        Task {
            do {
                let loadedGames = try await dataProvider.gamesForTeam(teamId: team.id)
                await MainActor.run {
                    gamesCache[team.id] = loadedGames
                    loadingTeams.remove(team.id)
                }
            } catch {
                await MainActor.run {
                    gamesCache[team.id] = []
                    loadingTeams.remove(team.id)
                }
            }
        }
    }
}

// MARK: - Game Calendar Row

struct GameCalendarRow: View {
    let game: RichGame
    let isSelected: Bool
    let onTap: () -> Void

    @Environment(\.colorScheme) private var colorScheme

    var body: some View {
        Button(action: onTap) {
            HStack(spacing: Theme.Spacing.sm) {
                // Selection indicator
                Image(systemName: isSelected ? "checkmark.circle.fill" : "circle")
                    .font(.title3)
                    .foregroundStyle(isSelected ? Theme.warmOrange : Theme.textMuted(colorScheme))
                    .animation(nil, value: isSelected)

                VStack(alignment: .leading, spacing: 2) {
                    Text("vs \(game.awayTeam.name)")
                        .font(.subheadline)
                        .foregroundStyle(Theme.textPrimary(colorScheme))

                    HStack(spacing: Theme.Spacing.xs) {
                        Label(game.game.gameTime, systemImage: "clock")
                            .font(.caption)
                            .foregroundStyle(Theme.textSecondary(colorScheme))

                        Text("•")
                            .foregroundStyle(Theme.textMuted(colorScheme))

                        Label(game.stadium.name, systemImage: "building.2")
                            .font(.caption)
                            .foregroundStyle(Theme.textMuted(colorScheme))
                            .lineLimit(1)
                    }

                    HStack(spacing: Theme.Spacing.xs) {
                        Label(game.stadium.fullAddress, systemImage: "mappin.circle.fill")
                            .font(.caption)
                            .foregroundStyle(Theme.textMuted(colorScheme))

                        if let broadcast = game.game.broadcastInfo, !broadcast.isEmpty {
                            Text("•")
                                .foregroundStyle(Theme.textMuted(colorScheme))

                            Label(broadcast, systemImage: "tv")
                                .font(.caption)
                                .foregroundStyle(Theme.textMuted(colorScheme))
                        }
                    }
                }

                Spacer()
            }
            .padding(.vertical, Theme.Spacing.sm)
            .padding(.horizontal, Theme.Spacing.md)
            .background(isSelected ? Theme.warmOrange.opacity(0.1) : Color.clear)
            .animation(nil, value: isSelected)
        }
        .buttonStyle(.plain)
    }
}

// MARK: - Location Search Sheet

struct LocationSearchSheet: View {
    let inputType: TripCreationView.CityInputType
    let onAdd: (LocationInput) -> Void

    @Environment(\.dismiss) private var dismiss
    @State private var searchText = ""
    @State private var searchResults: [LocationSearchResult] = []
    @State private var isSearching = false
    @State private var searchTask: Task<Void, Never>?

    private let locationService = LocationService.shared

    var body: some View {
        NavigationStack {
            VStack(spacing: 0) {
                // Search field
                HStack {
                    Image(systemName: "magnifyingglass")
                        .foregroundStyle(.secondary)
                    TextField("Search cities, addresses, places...", text: $searchText)
                        .textFieldStyle(.plain)
                        .autocorrectionDisabled()
                    if isSearching {
                        LoadingSpinner(size: .small)
                    } else if !searchText.isEmpty {
                        Button {
                            searchText = ""
                            searchResults = []
                        } label: {
                            Image(systemName: "xmark.circle.fill")
                                .foregroundStyle(.secondary)
                        }
                    }
                }
                .padding()
                .background(Color(.secondarySystemBackground))
                .clipShape(RoundedRectangle(cornerRadius: 10))
                .padding()

                // Results list
                if searchResults.isEmpty && !searchText.isEmpty && !isSearching {
                    ContentUnavailableView(
                        "No Results",
                        systemImage: "mappin.slash",
                        description: Text("Try a different search term")
                    )
                } else {
                    List(searchResults) { result in
                        Button {
                            onAdd(result.toLocationInput())
                            dismiss()
                        } label: {
                            HStack {
                                Image(systemName: "mappin.circle.fill")
                                    .foregroundStyle(.red)
                                    .font(.title2)
                                VStack(alignment: .leading) {
                                    Text(result.name)
                                        .foregroundStyle(.primary)
                                    if !result.address.isEmpty {
                                        Text(result.address)
                                            .font(.caption)
                                            .foregroundStyle(.secondary)
                                    }
                                }
                                Spacer()
                                Image(systemName: "plus.circle")
                                    .foregroundStyle(.blue)
                            }
                        }
                        .buttonStyle(.plain)
                    }
                    .listStyle(.plain)
                }

                Spacer()
            }
            .navigationTitle(inputType == .mustStop ? "Add Must-Stop" : "Add Location")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Cancel") {
                        dismiss()
                    }
                }
            }
        }
        .presentationDetents([.large])
        .onChange(of: searchText) { _, newValue in
            // Debounce search
            searchTask?.cancel()
            searchTask = Task {
                try? await Task.sleep(for: .milliseconds(300))
                guard !Task.isCancelled else { return }
                await performSearch(query: newValue)
            }
        }
    }

    private func performSearch(query: String) async {
        guard !query.isEmpty else {
            searchResults = []
            return
        }

        isSearching = true
        do {
            searchResults = try await locationService.searchLocations(query)
        } catch {
            searchResults = []
        }
        isSearching = false
    }
}

// MARK: - Trip Options View

// MARK: - Sort Options

enum TripSortOption: String, CaseIterable, Identifiable {
    case recommended = "Recommended"
    case mostCities = "Most Cities"
    case mostGames = "Most Games"
    case leastGames = "Least Games"
    case mostMiles = "Most Miles"
    case leastMiles = "Least Miles"
    case bestEfficiency = "Best Efficiency"

    var id: String { rawValue }

    var icon: String {
        switch self {
        case .recommended: return "star.fill"
        case .mostCities: return "mappin.and.ellipse"
        case .mostGames, .leastGames: return "sportscourt"
        case .mostMiles, .leastMiles: return "road.lanes"
        case .bestEfficiency: return "gauge.with.dots.needle.33percent"
        }
    }
}

enum TripPaceFilter: String, CaseIterable, Identifiable {
    case all = "All"
    case packed = "Packed"
    case moderate = "Moderate"
    case relaxed = "Relaxed"

    var id: String { rawValue }

    var icon: String {
        switch self {
        case .all: return "rectangle.stack"
        case .packed: return "flame"
        case .moderate: return "equal.circle"
        case .relaxed: return "leaf"
        }
    }
}

enum CitiesFilter: Int, CaseIterable, Identifiable {
    case noLimit = 100
    case fifteen = 15
    case ten = 10
    case five = 5
    case four = 4
    case three = 3
    case two = 2

    var id: Int { rawValue }

    var displayName: String {
        switch self {
        case .noLimit: return "No Limit"
        case .fifteen: return "15"
        case .ten: return "10"
        case .five: return "5"
        case .four: return "4"
        case .three: return "3"
        case .two: return "2"
        }
    }
}

// MARK: - Trip Options Grouper

enum TripOptionsGrouper {
    typealias GroupedOptions = (header: String, options: [ItineraryOption])

    static func groupByCityCount(_ options: [ItineraryOption], ascending: Bool) -> [GroupedOptions] {
        let grouped = Dictionary(grouping: options) { option in
            Set(option.stops.map { $0.city }).count
        }
        let sorted = ascending ? grouped.sorted { $0.key < $1.key } : grouped.sorted { $0.key > $1.key }
        return sorted.map { count, opts in
            ("\(count) \(count == 1 ? "city" : "cities")", opts)
        }
    }

    static func groupByGameCount(_ options: [ItineraryOption], ascending: Bool) -> [GroupedOptions] {
        let grouped = Dictionary(grouping: options) { $0.totalGames }
        let sorted = ascending ? grouped.sorted { $0.key < $1.key } : grouped.sorted { $0.key > $1.key }
        return sorted.map { count, opts in
            ("\(count) \(count == 1 ? "game" : "games")", opts)
        }
    }

    static func groupByMileageRange(_ options: [ItineraryOption], ascending: Bool) -> [GroupedOptions] {
        let ranges: [(min: Int, max: Int, label: String)] = [
            (0, 500, "0-500 mi"),
            (500, 1000, "500-1000 mi"),
            (1000, 1500, "1000-1500 mi"),
            (1500, 2000, "1500-2000 mi"),
            (2000, Int.max, "2000+ mi")
        ]

        var groupedDict: [String: [ItineraryOption]] = [:]
        for option in options {
            let miles = Int(option.totalDistanceMiles)
            for range in ranges {
                if miles >= range.min && miles < range.max {
                    groupedDict[range.label, default: []].append(option)
                    break
                }
            }
        }

        // Sort by range order
        let rangeOrder = ascending ? ranges : ranges.reversed()
        return rangeOrder.compactMap { range in
            guard let opts = groupedDict[range.label], !opts.isEmpty else { return nil }
            return (range.label, opts)
        }
    }
}

struct TripOptionsView: View {
    let options: [ItineraryOption]
    let games: [String: RichGame]
    let preferences: TripPreferences?
    let convertToTrip: (ItineraryOption) -> Trip

    @State private var selectedTrip: Trip?
    @State private var showTripDetail = false
    @State private var sortOption: TripSortOption = .recommended
    @State private var citiesFilter: CitiesFilter = .noLimit
    @State private var paceFilter: TripPaceFilter = .all
    @Environment(\.colorScheme) private var colorScheme

    // MARK: - Computed Properties

    private func uniqueCityCount(for option: ItineraryOption) -> Int {
        Set(option.stops.map { $0.city }).count
    }

    private var filteredAndSortedOptions: [ItineraryOption] {
        // Apply filters first
        let filtered = options.filter { option in
            let cityCount = uniqueCityCount(for: option)

            // City filter
            guard cityCount <= citiesFilter.rawValue else { return false }

            // Pace filter based on games per day ratio
            switch paceFilter {
            case .all:
                return true
            case .packed:
                // High game density: > 0.8 games per day
                return gamesPerDay(for: option) >= 0.8
            case .moderate:
                // Medium density: 0.4-0.8 games per day
                let gpd = gamesPerDay(for: option)
                return gpd >= 0.4 && gpd < 0.8
            case .relaxed:
                // Low density: < 0.4 games per day
                return gamesPerDay(for: option) < 0.4
            }
        }

        // Then apply sorting
        switch sortOption {
        case .recommended:
            return filtered
        case .mostCities:
            return filtered.sorted { $0.stops.count > $1.stops.count }
        case .mostGames:
            return filtered.sorted { $0.totalGames > $1.totalGames }
        case .leastGames:
            return filtered.sorted { $0.totalGames < $1.totalGames }
        case .mostMiles:
            return filtered.sorted { $0.totalDistanceMiles > $1.totalDistanceMiles }
        case .leastMiles:
            return filtered.sorted { $0.totalDistanceMiles < $1.totalDistanceMiles }
        case .bestEfficiency:
            return filtered.sorted {
                let effA = $0.totalDrivingHours > 0 ? Double($0.totalGames) / $0.totalDrivingHours : 0
                let effB = $1.totalDrivingHours > 0 ? Double($1.totalGames) / $1.totalDrivingHours : 0
                return effA > effB
            }
        }
    }

    private func gamesPerDay(for option: ItineraryOption) -> Double {
        guard let first = option.stops.first,
              let last = option.stops.last else { return 0 }
        let days = max(1, Calendar.current.dateComponents([.day], from: first.arrivalDate, to: last.departureDate).day ?? 1)
        return Double(option.totalGames) / Double(days)
    }

    private var groupedOptions: [TripOptionsGrouper.GroupedOptions] {
        switch sortOption {
        case .recommended, .bestEfficiency:
            // Flat list, no grouping
            return [("", filteredAndSortedOptions)]

        case .mostCities:
            return TripOptionsGrouper.groupByCityCount(filteredAndSortedOptions, ascending: false)

        case .mostGames:
            return TripOptionsGrouper.groupByGameCount(filteredAndSortedOptions, ascending: false)

        case .leastGames:
            return TripOptionsGrouper.groupByGameCount(filteredAndSortedOptions, ascending: true)

        case .mostMiles:
            return TripOptionsGrouper.groupByMileageRange(filteredAndSortedOptions, ascending: false)

        case .leastMiles:
            return TripOptionsGrouper.groupByMileageRange(filteredAndSortedOptions, ascending: true)
        }
    }

    var body: some View {
        ScrollView {
            LazyVStack(spacing: 16) {
                // Hero header
                VStack(spacing: 8) {
                    Image(systemName: "point.topright.arrow.triangle.backward.to.point.bottomleft.scurvepath.fill")
                        .font(.largeTitle)
                        .foregroundStyle(Theme.warmOrange)

                    Text("\(filteredAndSortedOptions.count) of \(options.count) Routes")
                        .font(.title2)
                        .foregroundStyle(Theme.textPrimary(colorScheme))
                }
                .padding(.top, Theme.Spacing.lg)

                // Filters section
                filtersSection
                    .padding(.horizontal, Theme.Spacing.md)

                // Options list (grouped when applicable)
                if filteredAndSortedOptions.isEmpty {
                    emptyFilterState
                        .padding(.top, Theme.Spacing.xl)
                } else {
                    ForEach(Array(groupedOptions.enumerated()), id: \.offset) { _, group in
                        VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
                            // Section header (only if non-empty)
                            if !group.header.isEmpty {
                                HStack {
                                    Text(group.header)
                                        .font(.headline)
                                        .foregroundStyle(Theme.textPrimary(colorScheme))

                                    Spacer()

                                    Text("\(group.options.count)")
                                        .font(.subheadline)
                                        .foregroundStyle(Theme.textMuted(colorScheme))
                                }
                                .padding(.horizontal, Theme.Spacing.md)
                                .padding(.top, Theme.Spacing.md)
                            }

                            // Options in this group
                            ForEach(group.options) { option in
                                TripOptionCard(
                                    option: option,
                                    games: games,
                                    onSelect: {
                                        selectedTrip = convertToTrip(option)
                                        showTripDetail = true
                                    }
                                )
                                .padding(.horizontal, Theme.Spacing.md)
                            }
                        }
                    }
                }
            }
            .padding(.bottom, Theme.Spacing.xxl)
        }
        .themedBackground()
        .navigationDestination(isPresented: $showTripDetail) {
            if let trip = selectedTrip {
                TripDetailView(trip: trip, games: games)
            }
        }
        .onChange(of: showTripDetail) { _, isShowing in
            if !isShowing {
                selectedTrip = nil
            }
        }
    }

    private var sortPicker: some View {
        Menu {
            ForEach(TripSortOption.allCases) { option in
                Button {
                    withAnimation(.easeInOut(duration: 0.2)) {
                        sortOption = option
                    }
                } label: {
                    Label(option.rawValue, systemImage: option.icon)
                }
            }
        } label: {
            HStack(spacing: 8) {
                Image(systemName: sortOption.icon)
                    .font(.subheadline)
                Text(sortOption.rawValue)
                    .font(.subheadline)
                Image(systemName: "chevron.down")
                    .font(.caption)
            }
            .foregroundStyle(Theme.textPrimary(colorScheme))
            .padding(.horizontal, 16)
            .padding(.vertical, 10)
            .background(Theme.cardBackground(colorScheme))
            .clipShape(Capsule())
            .overlay(
                Capsule()
                    .strokeBorder(Theme.textMuted(colorScheme).opacity(0.2), lineWidth: 1)
            )
        }
    }

    // MARK: - Filters Section

    private var filtersSection: some View {
        VStack(spacing: Theme.Spacing.md) {
            // Sort and Pace row
            HStack(spacing: Theme.Spacing.sm) {
                sortPicker
                Spacer()
                pacePicker
            }

            // Cities picker
            citiesPicker
        }
        .padding(Theme.Spacing.md)
        .background(Theme.cardBackground(colorScheme))
        .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium))
    }

    private var pacePicker: some View {
        Menu {
            ForEach(TripPaceFilter.allCases) { pace in
                Button {
                    withAnimation(.easeInOut(duration: 0.2)) {
                        paceFilter = pace
                    }
                } label: {
                    Label(pace.rawValue, systemImage: pace.icon)
                }
            }
        } label: {
            HStack(spacing: 6) {
                Image(systemName: paceFilter.icon)
                    .font(.caption)
                    .contentTransition(.identity)
                Text(paceFilter.rawValue)
                    .font(.subheadline)
                    .contentTransition(.identity)
                Image(systemName: "chevron.down")
                    .font(.caption2)
            }
            .foregroundStyle(paceFilter == .all ? Theme.textPrimary(colorScheme) : Theme.warmOrange)
            .padding(.horizontal, 12)
            .padding(.vertical, 8)
            .background(paceFilter == .all ? Theme.cardBackground(colorScheme) : Theme.warmOrange.opacity(0.15))
            .clipShape(Capsule())
            .overlay(
                Capsule()
                    .strokeBorder(paceFilter == .all ? Theme.textMuted(colorScheme).opacity(0.2) : Theme.warmOrange.opacity(0.3), lineWidth: 1)
            )
            .animation(nil, value: paceFilter)
        }
    }

    private var citiesPicker: some View {
        VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
            Label("Max Cities", systemImage: "mappin.circle")
                .font(.subheadline)
                .foregroundStyle(Theme.textSecondary(colorScheme))

            ScrollView(.horizontal, showsIndicators: false) {
                HStack(spacing: 8) {
                    ForEach(CitiesFilter.allCases) { filter in
                        Button {
                            withAnimation(.easeInOut(duration: 0.2)) {
                                citiesFilter = filter
                            }
                        } label: {
                            Text(filter.displayName)
                                .font(.system(size: 13, weight: citiesFilter == filter ? .semibold : .medium))
                                .foregroundStyle(citiesFilter == filter ? .white : Theme.textPrimary(colorScheme))
                                .padding(.horizontal, 12)
                                .padding(.vertical, 6)
                                .background(citiesFilter == filter ? Theme.warmOrange : Theme.cardBackground(colorScheme))
                                .clipShape(Capsule())
                                .overlay(
                                    Capsule()
                                        .strokeBorder(citiesFilter == filter ? Color.clear : Theme.textMuted(colorScheme).opacity(0.2), lineWidth: 1)
                                )
                        }
                        .buttonStyle(.plain)
                    }
                }
            }
        }
    }

    private var emptyFilterState: some View {
        VStack(spacing: Theme.Spacing.md) {
            Image(systemName: "line.3.horizontal.decrease.circle")
                .font(.system(size: 48))
                .foregroundStyle(Theme.textMuted(colorScheme))

            Text("No routes match your filters")
                .font(.body)
                .foregroundStyle(Theme.textSecondary(colorScheme))

            Button {
                withAnimation {
                    citiesFilter = .noLimit
                    paceFilter = .all
                }
            } label: {
                Text("Reset Filters")
                    .font(.subheadline)
                    .foregroundStyle(Theme.warmOrange)
            }
        }
        .frame(maxWidth: .infinity)
        .padding(.vertical, Theme.Spacing.xxl)
    }
}

// MARK: - Trip Option Card

struct TripOptionCard: View {
    let option: ItineraryOption
    let games: [String: RichGame]
    let onSelect: () -> Void
    @Environment(\.colorScheme) private var colorScheme

    @State private var aiDescription: String?
    @State private var isLoadingDescription = false

    private var uniqueCities: [String] {
        option.stops.map { $0.city }.removingDuplicates()
    }

    private var totalGames: Int {
        option.stops.flatMap { $0.games }.count
    }

    private var uniqueSports: [Sport] {
        let gameIds = option.stops.flatMap { $0.games }
        let sports = gameIds.compactMap { games[$0]?.game.sport }
        return Array(Set(sports)).sorted { $0.rawValue < $1.rawValue }
    }

    private var gamesPerSport: [(sport: Sport, count: Int)] {
        let gameIds = option.stops.flatMap { $0.games }
        var countsBySport: [Sport: Int] = [:]
        for gameId in gameIds {
            if let sport = games[gameId]?.game.sport {
                countsBySport[sport, default: 0] += 1
            }
        }
        return countsBySport.sorted { $0.key.rawValue < $1.key.rawValue }
            .map { (sport: $0.key, count: $0.value) }
    }

    var body: some View {
        Button(action: onSelect) {
            HStack(spacing: Theme.Spacing.md) {
                // Route info
                VStack(alignment: .leading, spacing: 6) {
                    // Vertical route display
                    VStack(alignment: .leading, spacing: 0) {
                        Text(uniqueCities.first ?? "")
                            .font(.subheadline)
                            .foregroundStyle(Theme.textPrimary(colorScheme))

                        VStack(spacing: 0) {
                            Text("|")
                                .font(.caption2)
                            Image(systemName: "chevron.down")
                                .font(.caption2)
                        }
                        .foregroundStyle(Theme.warmOrange)

                        Text(uniqueCities.last ?? "")
                            .font(.subheadline)
                            .foregroundStyle(Theme.textPrimary(colorScheme))
                    }

                    // Top stats row: cities and miles
                    HStack(spacing: 12) {
                        Label("\(uniqueCities.count) cities", systemImage: "mappin")
                        if option.totalDistanceMiles > 0 {
                            Label("\(Int(option.totalDistanceMiles)) mi", systemImage: "car")
                        }
                    }
                    .font(.caption)
                    .foregroundStyle(Theme.textSecondary(colorScheme))

                    // Bottom row: sports with game counts
                    HStack(spacing: 6) {
                        ForEach(gamesPerSport, id: \.sport) { item in
                            HStack(spacing: 3) {
                                Image(systemName: item.sport.iconName)
                                    .font(.caption2)
                                Text("\(item.sport.rawValue.uppercased()) \(item.count)")
                                    .font(.caption2)
                            }
                            .padding(.horizontal, 6)
                            .padding(.vertical, 3)
                            .background(item.sport.themeColor.opacity(0.15))
                            .foregroundStyle(item.sport.themeColor)
                            .clipShape(Capsule())
                        }
                    }

                    // AI-generated description (after stats)
                    if let description = aiDescription {
                        Text(description)
                            .font(.system(size: 13, weight: .regular))
                            .foregroundStyle(Theme.textMuted(colorScheme))
                            .fixedSize(horizontal: false, vertical: true)
                            .transition(.opacity)
                    } else if isLoadingDescription {
                        HStack(spacing: 4) {
                            LoadingSpinner(size: .small)
                            Text("Generating...")
                                .font(.caption2)
                                .foregroundStyle(Theme.textMuted(colorScheme))
                        }
                    }
                }

                Spacer()

                // Right: Chevron
                Image(systemName: "chevron.right")
                    .font(.system(size: 14, weight: .semibold))
                    .foregroundStyle(Theme.textMuted(colorScheme))
            }
            .padding(Theme.Spacing.md)
            .background(Theme.cardBackground(colorScheme))
            .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium))
            .overlay {
                RoundedRectangle(cornerRadius: Theme.CornerRadius.medium)
                    .stroke(Theme.surfaceGlow(colorScheme), lineWidth: 1)
            }
        }
        .buttonStyle(.plain)
        .task(id: option.id) {
            // Reset state when option changes
            aiDescription = nil
            isLoadingDescription = false
            await generateDescription()
        }
    }

    private func generateDescription() async {
        guard RouteDescriptionGenerator.shared.isAvailable else { return }

        isLoadingDescription = true

        // Build input from THIS specific option
        let input = RouteDescriptionInput(from: option, games: games)

        if let description = await RouteDescriptionGenerator.shared.generateDescription(for: input) {
            withAnimation(.easeInOut(duration: 0.3)) {
                aiDescription = description
            }
        }
        isLoadingDescription = false
    }
}

// MARK: - Array Extension for Removing Duplicates

extension Array where Element: Hashable {
    func removingDuplicates() -> [Element] {
        var seen = Set<Element>()
        return filter { seen.insert($0).inserted }
    }
}

// MARK: - Themed Form Components

struct ThemedSection<Content: View>: View {
    let title: String
    @ViewBuilder let content: () -> Content
    @Environment(\.colorScheme) private var colorScheme

    var body: some View {
        VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
            Text(title)
                .font(.title2)
                .foregroundStyle(Theme.textPrimary(colorScheme))

            VStack(alignment: .leading, spacing: Theme.Spacing.md) {
                content()
            }
            .padding(Theme.Spacing.lg)
            .background(Theme.cardBackground(colorScheme))
            .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.large))
            .overlay {
                RoundedRectangle(cornerRadius: Theme.CornerRadius.large)
                    .stroke(Theme.surfaceGlow(colorScheme), lineWidth: 1)
            }
        }
    }
}

struct ThemedTextField: View {
    let label: String
    let placeholder: String
    @Binding var text: String
    var icon: String = "mappin"
    @Environment(\.colorScheme) private var colorScheme

    var body: some View {
        VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
            Text(label)
                .font(.subheadline)
                .foregroundStyle(Theme.textSecondary(colorScheme))

            HStack(spacing: Theme.Spacing.sm) {
                Image(systemName: icon)
                    .foregroundStyle(Theme.warmOrange)
                    .frame(width: 24)

                TextField(placeholder, text: $text)
                    .font(.body)
                    .foregroundStyle(Theme.textPrimary(colorScheme))
            }
            .padding(Theme.Spacing.md)
            .background(Theme.cardBackgroundElevated(colorScheme))
            .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium))
        }
    }
}

struct ThemedToggle: View {
    let label: String
    @Binding var isOn: Bool
    var icon: String = "checkmark.circle"
    @Environment(\.colorScheme) private var colorScheme

    var body: some View {
        HStack(spacing: Theme.Spacing.sm) {
            Image(systemName: icon)
                .foregroundStyle(isOn ? Theme.warmOrange : Theme.textMuted(colorScheme))
                .frame(width: 24)

            Text(label)
                .font(.body)
                .foregroundStyle(Theme.textPrimary(colorScheme))

            Spacer()

            Toggle("", isOn: $isOn)
                .labelsHidden()
                .tint(Theme.warmOrange)
        }
    }
}

struct ThemedStepper: View {
    let label: String
    let value: Int
    let range: ClosedRange<Int>
    let onIncrement: () -> Void
    let onDecrement: () -> Void
    @Environment(\.colorScheme) private var colorScheme

    var body: some View {
        HStack {
            Text(label)
                .font(.body)
                .foregroundStyle(Theme.textPrimary(colorScheme))

            Spacer()

            HStack(spacing: Theme.Spacing.sm) {
                Button {
                    if value > range.lowerBound {
                        onDecrement()
                    }
                } label: {
                    Image(systemName: "minus.circle.fill")
                        .font(.title2)
                        .foregroundStyle(value > range.lowerBound ? Theme.warmOrange : Theme.textMuted(colorScheme))
                }
                .disabled(value <= range.lowerBound)

                Text("\(value)")
                    .font(.body)
                    .foregroundStyle(Theme.textPrimary(colorScheme))
                    .frame(minWidth: 30)

                Button {
                    if value < range.upperBound {
                        onIncrement()
                    }
                } label: {
                    Image(systemName: "plus.circle.fill")
                        .font(.title2)
                        .foregroundStyle(value < range.upperBound ? Theme.warmOrange : Theme.textMuted(colorScheme))
                }
                .disabled(value >= range.upperBound)
            }
        }
    }
}

struct ThemedDatePicker: View {
    let label: String
    @Binding var selection: Date
    @Environment(\.colorScheme) private var colorScheme

    var body: some View {
        HStack {
            HStack(spacing: Theme.Spacing.sm) {
                Image(systemName: "calendar")
                    .foregroundStyle(Theme.warmOrange)
                Text(label)
                    .font(.body)
                    .foregroundStyle(Theme.textPrimary(colorScheme))
            }

            Spacer()

            DatePicker("", selection: $selection, displayedComponents: .date)
                .labelsHidden()
                .tint(Theme.warmOrange)
        }
    }
}

// MARK: - Date Range Picker

struct DateRangePicker: View {
    @Binding var startDate: Date
    @Binding var endDate: Date
    @Environment(\.colorScheme) private var colorScheme

    @State private var displayedMonth: Date = Date()
    @State private var selectionState: SelectionState = .none

    enum SelectionState {
        case none
        case startSelected
        case complete
    }

    private let calendar = Calendar.current
    private let daysOfWeek = ["S", "M", "T", "W", "T", "F", "S"]

    private var monthYearString: String {
        let formatter = DateFormatter()
        formatter.dateFormat = "MMMM yyyy"
        return formatter.string(from: displayedMonth)
    }

    private var daysInMonth: [Date?] {
        guard let monthInterval = calendar.dateInterval(of: .month, for: displayedMonth),
              let monthFirstWeek = calendar.dateInterval(of: .weekOfMonth, for: monthInterval.start) else {
            return []
        }

        var days: [Date?] = []
        let startOfMonth = monthInterval.start
        let endOfMonth = calendar.date(byAdding: .day, value: -1, to: monthInterval.end)!

        // Get the first day of the week containing the first day of the month
        var currentDate = monthFirstWeek.start

        // Add days until we've covered the month
        while currentDate <= endOfMonth || days.count % 7 != 0 {
            if currentDate >= startOfMonth && currentDate <= endOfMonth {
                days.append(currentDate)
            } else if currentDate < startOfMonth {
                days.append(nil) // Placeholder for days before month starts
            } else if days.count % 7 != 0 {
                days.append(nil) // Placeholder to complete the last week
            } else {
                break
            }
            currentDate = calendar.date(byAdding: .day, value: 1, to: currentDate)!
        }

        return days
    }

    private var tripDuration: Int {
        let components = calendar.dateComponents([.day], from: startDate, to: endDate)
        return (components.day ?? 0) + 1
    }

    var body: some View {
        VStack(spacing: Theme.Spacing.md) {
            // Selected range summary
            selectedRangeSummary

            // Month navigation
            monthNavigation

            // Days of week header
            daysOfWeekHeader

            // Calendar grid
            calendarGrid

            // Trip duration
            tripDurationBadge
        }
        .onAppear {
            // Initialize displayed month to show the start date's month
            displayedMonth = calendar.startOfDay(for: startDate)
            // If dates are already selected (endDate > startDate), show complete state
            if endDate > startDate {
                selectionState = .complete
            }
        }
    }

    private var selectedRangeSummary: some View {
        HStack(spacing: Theme.Spacing.md) {
            // Start date
            VStack(alignment: .leading, spacing: 4) {
                Text("START")
                    .font(.caption2)
                    .foregroundStyle(Theme.textMuted(colorScheme))
                Text(startDate.formatted(.dateTime.month(.abbreviated).day().year()))
                    .font(.body)
                    .foregroundStyle(Theme.warmOrange)
            }
            .frame(maxWidth: .infinity, alignment: .leading)

            // Arrow
            Image(systemName: "arrow.right")
                .font(.subheadline)
                .foregroundStyle(Theme.textMuted(colorScheme))

            // End date
            VStack(alignment: .trailing, spacing: 4) {
                Text("END")
                    .font(.caption2)
                    .foregroundStyle(Theme.textMuted(colorScheme))
                Text(endDate.formatted(.dateTime.month(.abbreviated).day().year()))
                    .font(.body)
                    .foregroundStyle(Theme.warmOrange)
            }
            .frame(maxWidth: .infinity, alignment: .trailing)
        }
        .padding(Theme.Spacing.md)
        .background(Theme.cardBackgroundElevated(colorScheme))
        .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium))
    }

    private var monthNavigation: some View {
        HStack {
            Button {
                withAnimation(.easeInOut(duration: 0.2)) {
                    displayedMonth = calendar.date(byAdding: .month, value: -1, to: displayedMonth) ?? displayedMonth
                }
            } label: {
                Image(systemName: "chevron.left")
                    .font(.body)
                    .foregroundStyle(Theme.warmOrange)
                    .frame(width: 36, height: 36)
                    .background(Theme.warmOrange.opacity(0.15))
                    .clipShape(Circle())
            }

            Spacer()

            Text(monthYearString)
                .font(.headline)
                .foregroundStyle(Theme.textPrimary(colorScheme))

            Spacer()

            Button {
                withAnimation(.easeInOut(duration: 0.2)) {
                    displayedMonth = calendar.date(byAdding: .month, value: 1, to: displayedMonth) ?? displayedMonth
                }
            } label: {
                Image(systemName: "chevron.right")
                    .font(.body)
                    .foregroundStyle(Theme.warmOrange)
                    .frame(width: 36, height: 36)
                    .background(Theme.warmOrange.opacity(0.15))
                    .clipShape(Circle())
            }
        }
    }

    private var daysOfWeekHeader: some View {
        HStack(spacing: 0) {
            ForEach(Array(daysOfWeek.enumerated()), id: \.offset) { _, day in
                Text(day)
                    .font(.caption)
                    .foregroundStyle(Theme.textMuted(colorScheme))
                    .frame(maxWidth: .infinity)
            }
        }
    }

    private var calendarGrid: some View {
        let columns = Array(repeating: GridItem(.flexible(), spacing: 4), count: 7)

        return LazyVGrid(columns: columns, spacing: 4) {
            ForEach(Array(daysInMonth.enumerated()), id: \.offset) { _, date in
                if let date = date {
                    DayCell(
                        date: date,
                        isStart: calendar.isDate(date, inSameDayAs: startDate),
                        isEnd: calendar.isDate(date, inSameDayAs: endDate),
                        isInRange: isDateInRange(date),
                        isToday: calendar.isDateInToday(date),
                        onTap: { handleDateTap(date) }
                    )
                } else {
                    Color.clear
                        .frame(height: 40)
                }
            }
        }
    }

    private var tripDurationBadge: some View {
        HStack(spacing: Theme.Spacing.xs) {
            Image(systemName: "calendar.badge.clock")
                .foregroundStyle(Theme.warmOrange)
            Text("\(tripDuration) day\(tripDuration == 1 ? "" : "s")")
                .font(.subheadline)
                .foregroundStyle(Theme.textSecondary(colorScheme))
        }
        .frame(maxWidth: .infinity, alignment: .center)
        .padding(.top, Theme.Spacing.xs)
    }

    private func isDateInRange(_ date: Date) -> Bool {
        let start = calendar.startOfDay(for: startDate)
        let end = calendar.startOfDay(for: endDate)
        let current = calendar.startOfDay(for: date)
        return current > start && current < end
    }

    private func handleDateTap(_ date: Date) {
        let today = calendar.startOfDay(for: Date())
        let tappedDate = calendar.startOfDay(for: date)

        // Don't allow selecting dates in the past
        if tappedDate < today {
            return
        }

        switch selectionState {
        case .none, .complete:
            // First tap: set start date, reset end to same day
            startDate = date
            endDate = date
            selectionState = .startSelected

        case .startSelected:
            // Second tap: set end date (if after start)
            if date >= startDate {
                endDate = date
            } else {
                // If tapped date is before start, make it the new start
                endDate = startDate
                startDate = date
            }
            selectionState = .complete
        }
    }
}

// MARK: - Day Cell

struct DayCell: View {
    let date: Date
    let isStart: Bool
    let isEnd: Bool
    let isInRange: Bool
    let isToday: Bool
    let onTap: () -> Void

    @Environment(\.colorScheme) private var colorScheme

    private let calendar = Calendar.current

    private var dayNumber: String {
        "\(calendar.component(.day, from: date))"
    }

    private var isPast: Bool {
        calendar.startOfDay(for: date) < calendar.startOfDay(for: Date())
    }

    var body: some View {
        Button(action: onTap) {
            ZStack {
                // Range highlight background (stretches edge to edge)
                if isInRange || isStart || isEnd {
                    HStack(spacing: 0) {
                        Rectangle()
                            .fill(Theme.warmOrange.opacity(0.15))
                            .frame(maxWidth: .infinity)
                            .opacity(isStart && !isEnd ? 0 : 1)
                            .offset(x: isStart ? 20 : 0)

                        Rectangle()
                            .fill(Theme.warmOrange.opacity(0.15))
                            .frame(maxWidth: .infinity)
                            .opacity(isEnd && !isStart ? 0 : 1)
                            .offset(x: isEnd ? -20 : 0)
                    }
                    .opacity(isStart && isEnd ? 0 : 1) // Hide when start == end
                }

                // Day circle
                ZStack {
                    if isStart || isEnd {
                        Circle()
                            .fill(Theme.warmOrange)
                    } else if isToday {
                        Circle()
                            .stroke(Theme.warmOrange, lineWidth: 2)
                    }

                    Text(dayNumber)
                        .font(.system(size: 14, weight: (isStart || isEnd) ? .bold : .medium))
                        .foregroundStyle(
                            isPast ? Theme.textMuted(colorScheme).opacity(0.5) :
                            (isStart || isEnd) ? .white :
                            isToday ? Theme.warmOrange :
                            Theme.textPrimary(colorScheme)
                        )
                }
                .frame(width: 36, height: 36)
            }
        }
        .buttonStyle(.plain)
        .disabled(isPast)
        .frame(height: 40)
    }
}

// MARK: - Team Picker Sheet

struct TeamPickerSheet: View {
    @Binding var selectedTeamId: String?
    let teamsBySport: [Sport: [Team]]

    @Environment(\.dismiss) private var dismiss
    @Environment(\.colorScheme) private var colorScheme

    @State private var searchText = ""

    private var sortedSports: [Sport] {
        Sport.allCases.filter { teamsBySport[$0] != nil && !teamsBySport[$0]!.isEmpty }
    }

    private var filteredTeamsBySport: [Sport: [Team]] {
        guard !searchText.isEmpty else { return teamsBySport }

        var filtered: [Sport: [Team]] = [:]
        for (sport, teams) in teamsBySport {
            let matchingTeams = teams.filter {
                $0.name.localizedCaseInsensitiveContains(searchText) ||
                $0.city.localizedCaseInsensitiveContains(searchText) ||
                $0.abbreviation.localizedCaseInsensitiveContains(searchText)
            }
            if !matchingTeams.isEmpty {
                filtered[sport] = matchingTeams
            }
        }
        return filtered
    }

    var body: some View {
        NavigationStack {
            List {
                ForEach(sortedSports, id: \.self) { sport in
                    if let teams = filteredTeamsBySport[sport], !teams.isEmpty {
                        Section(sport.displayName) {
                            ForEach(teams) { team in
                                TeamRow(
                                    team: team,
                                    isSelected: selectedTeamId == team.id,
                                    colorScheme: colorScheme
                                ) {
                                    selectedTeamId = team.id
                                    dismiss()
                                }
                            }
                        }
                    }
                }
            }
            .searchable(text: $searchText, prompt: "Search teams")
            .navigationTitle("Select Team")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Cancel") {
                        dismiss()
                    }
                }
            }
        }
    }
}

// MARK: - Planning Mode Card

struct PlanningModeCard: View {
    let mode: PlanningMode
    let isSelected: Bool
    let colorScheme: ColorScheme
    let onTap: () -> Void

    var body: some View {
        Button(action: onTap) {
            VStack(spacing: Theme.Spacing.sm) {
                // Icon
                ZStack {
                    Circle()
                        .fill(isSelected ? Theme.warmOrange : Theme.warmOrange.opacity(0.15))
                        .frame(width: 44, height: 44)

                    Image(systemName: mode.iconName)
                        .font(.system(size: 20, weight: .semibold))
                        .foregroundStyle(isSelected ? .white : Theme.warmOrange)
                }

                // Title
                Text(mode.displayName)
                    .font(.subheadline.weight(.medium))
                    .foregroundStyle(Theme.textPrimary(colorScheme))
                    .lineLimit(1)
            }
            .frame(maxWidth: .infinity)
            .padding(.vertical, Theme.Spacing.md)
            .padding(.horizontal, Theme.Spacing.sm)
            .background(
                RoundedRectangle(cornerRadius: Theme.CornerRadius.medium)
                    .fill(Theme.cardBackgroundElevated(colorScheme))
            )
            .overlay(
                RoundedRectangle(cornerRadius: Theme.CornerRadius.medium)
                    .strokeBorder(
                        isSelected ? Theme.warmOrange : Color.clear,
                        lineWidth: 2
                    )
            )
        }
        .buttonStyle(.plain)
        .accessibilityLabel("\(mode.displayName): \(mode.description)")
        .accessibilityAddTraits(isSelected ? .isSelected : [])
    }
}

struct TeamRow: View {
    let team: Team
    let isSelected: Bool
    let colorScheme: ColorScheme
    let onTap: () -> Void

    var body: some View {
        Button(action: onTap) {
            HStack(spacing: Theme.Spacing.md) {
                // Team color indicator
                if let colorHex = team.primaryColor {
                    Circle()
                        .fill(Color(hex: colorHex))
                        .frame(width: 12, height: 12)
                } else {
                    Circle()
                        .fill(Theme.warmOrange)
                        .frame(width: 12, height: 12)
                }

                VStack(alignment: .leading, spacing: 2) {
                    Text(team.name)
                        .font(.body)
                        .foregroundStyle(Theme.textPrimary(colorScheme))
                    Text(team.city)
                        .font(.caption)
                        .foregroundStyle(Theme.textSecondary(colorScheme))
                }

                Spacer()

                if isSelected {
                    Image(systemName: "checkmark.circle.fill")
                        .foregroundStyle(Theme.warmOrange)
                }
            }
            .contentShape(Rectangle())
        }
        .buttonStyle(.plain)
    }
}

#Preview {
    TripCreationView(viewModel: TripCreationViewModel())
}
