// // ScheduleViewModel.swift // SportsTime // import Foundation import SwiftUI @MainActor @Observable final class ScheduleViewModel { // MARK: - Filter State var selectedSports: Set = Set(Sport.supported) var startDate: Date = Date() var endDate: Date = Calendar.current.date(byAdding: .day, value: 14, to: Date()) ?? Date() var searchText: String = "" // MARK: - Data State private(set) var games: [RichGame] = [] private(set) var isLoading = false private(set) var error: Error? private(set) var errorMessage: String? private let dataProvider = AppDataProvider.shared // MARK: - Computed Properties var filteredGames: [RichGame] { guard !searchText.isEmpty else { return games } let query = searchText.lowercased() return games.filter { game in game.homeTeam.name.lowercased().contains(query) || game.homeTeam.city.lowercased().contains(query) || game.awayTeam.name.lowercased().contains(query) || game.awayTeam.city.lowercased().contains(query) || game.stadium.name.lowercased().contains(query) || game.stadium.city.lowercased().contains(query) } } var gamesByDate: [(date: Date, games: [RichGame])] { let calendar = Calendar.current let grouped = Dictionary(grouping: filteredGames) { game in calendar.startOfDay(for: game.game.dateTime) } return grouped.sorted { $0.key < $1.key }.map { ($0.key, $0.value) } } var gamesBySport: [(sport: Sport, games: [RichGame])] { let grouped = Dictionary(grouping: filteredGames) { game in game.game.sport } // Sort by sport order (use allCases index for consistent ordering) // Within each sport, games are sorted by date return grouped .sorted { lhs, rhs in let lhsIndex = Sport.allCases.firstIndex(of: lhs.key) ?? 0 let rhsIndex = Sport.allCases.firstIndex(of: rhs.key) ?? 0 return lhsIndex < rhsIndex } .map { (sport: $0.key, games: $0.value.sorted { $0.game.dateTime < $1.game.dateTime }) } } var hasFilters: Bool { selectedSports.count < Sport.supported.count || !searchText.isEmpty } // MARK: - Actions func loadGames() async { guard !selectedSports.isEmpty else { games = [] return } isLoading = true error = nil errorMessage = nil do { // Load initial data if needed if dataProvider.teams.isEmpty { await dataProvider.loadInitialData() } // Check if data provider had an error if let providerError = dataProvider.errorMessage { self.errorMessage = providerError self.error = dataProvider.error isLoading = false return } games = try await dataProvider.filterRichGames( sports: selectedSports, startDate: startDate, endDate: endDate ) } catch let cloudKitError as CloudKitError { self.error = cloudKitError self.errorMessage = cloudKitError.errorDescription } catch { self.error = error self.errorMessage = error.localizedDescription } isLoading = false } func clearError() { error = nil errorMessage = nil } func toggleSport(_ sport: Sport) { if selectedSports.contains(sport) { selectedSports.remove(sport) } else { selectedSports.insert(sport) } Task { await loadGames() } } func resetFilters() { selectedSports = Set(Sport.supported) searchText = "" startDate = Date() endDate = Calendar.current.date(byAdding: .day, value: 14, to: Date()) ?? Date() Task { await loadGames() } } func updateDateRange(start: Date, end: Date) { startDate = start endDate = end Task { await loadGames() } } }