// // TripWizardViewModel.swift // SportsTime // // ViewModel for trip wizard. // import Foundation import SwiftUI @Observable final class TripWizardViewModel { // MARK: - Planning Mode var planningMode: PlanningMode? = nil { didSet { if oldValue != nil && oldValue != planningMode { resetAllSelections() } } } // MARK: - Sports Selection var selectedSports: Set = [] // MARK: - Dates var startDate: Date = Date() var endDate: Date = Date().addingTimeInterval(86400 * 7) var hasSetDates: Bool = false // MARK: - Regions var selectedRegions: Set = [] // MARK: - Route Preferences var routePreference: RoutePreference = .balanced var hasSetRoutePreference: Bool = false // MARK: - Repeat Cities var allowRepeatCities: Bool = false var hasSetRepeatCities: Bool = false // MARK: - Must Stops var mustStopLocations: [LocationInput] = [] // MARK: - Planning State var isPlanning: Bool = false // MARK: - Sport Availability var sportAvailability: [Sport: Bool] = [:] var isLoadingSportAvailability: Bool = false // MARK: - Visibility /// All steps visible once planning mode is selected var areStepsVisible: Bool { planningMode != nil } // MARK: - Validation /// All required fields must be set before planning var canPlanTrip: Bool { planningMode != nil && hasSetDates && !selectedSports.isEmpty && !selectedRegions.isEmpty && hasSetRoutePreference && hasSetRepeatCities } /// Field validation for the review step - shows which fields are missing var fieldValidation: FieldValidation { FieldValidation( sports: selectedSports.isEmpty ? .missing : .valid, dates: hasSetDates ? .valid : .missing, regions: selectedRegions.isEmpty ? .missing : .valid, routePreference: hasSetRoutePreference ? .valid : .missing, repeatCities: hasSetRepeatCities ? .valid : .missing ) } // MARK: - Sport Availability func canSelectSport(_ sport: Sport) -> Bool { sportAvailability[sport] ?? true // Default to available if not checked } func fetchSportAvailability() async { guard hasSetDates else { return } isLoadingSportAvailability = true defer { isLoadingSportAvailability = false } var availability: [Sport: Bool] = [:] for sport in Sport.supported { do { let games = try await AppDataProvider.shared.filterGames( sports: [sport], startDate: startDate, endDate: endDate ) availability[sport] = !games.isEmpty } catch { availability[sport] = true // Default to available on error } } await MainActor.run { self.sportAvailability = availability } } // MARK: - Reset Logic private func resetAllSelections() { selectedSports = [] hasSetDates = false selectedRegions = [] hasSetRoutePreference = false hasSetRepeatCities = false mustStopLocations = [] } } // MARK: - Field Validation struct FieldValidation { enum Status { case valid case missing } let sports: Status let dates: Status let regions: Status let routePreference: Status let repeatCities: Status }