//
//  ScheduleViewModel.swift
//  SportsTime
//

import Foundation
import SwiftUI
import os.log

private let logger = Logger(subsystem: "com.88oakapps.SportsTime", category: "ScheduleViewModel")

@MainActor
@Observable
final class ScheduleViewModel {

    // MARK: - Filter State

    var selectedSports: Set<Sport> = Set(Sport.supported)
    var startDate: Date = Calendar.current.startOfDay(for: Date())
    var endDate: Date = Calendar.current.date(byAdding: .day, value: 14, to: Calendar.current.startOfDay(for: 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: - Pre-computed Groupings (avoid computed property overhead)

    /// Games grouped by sport - pre-computed to avoid re-grouping on every render
    private(set) var gamesBySport: [(sport: Sport, games: [RichGame])] = []

    /// All games matching current filters (before any display limiting)
    private var filteredGames: [RichGame] = []

    // MARK: - Diagnostics

    /// Debug info for troubleshooting missing games
    private(set) var diagnostics: ScheduleDiagnostics = ScheduleDiagnostics()

    var hasFilters: Bool {
        selectedSports.count < Sport.supported.count || !searchText.isEmpty
    }

    // MARK: - Actions

    func loadGames() async {
        guard !selectedSports.isEmpty else {
            games = []
            updateFilteredGames()
            return
        }

        isLoading = true
        error = nil
        errorMessage = nil

        // Start diagnostics
        let queryStartDate = startDate
        let queryEndDate = endDate
        let querySports = selectedSports

        logger.info("📅 Loading games: \(querySports.map(\.rawValue).joined(separator: ", "))")
        logger.info("📅 Date range: \(queryStartDate.formatted()) to \(queryEndDate.formatted())")

        do {
            // Load initial data if needed
            if dataProvider.teams.isEmpty {
                logger.info("📅 Teams empty, loading initial data...")
                await dataProvider.loadInitialData()
            }

            // Check if data provider had an error
            if let providerError = dataProvider.errorMessage {
                self.errorMessage = providerError
                self.error = dataProvider.error
                isLoading = false
                updateFilteredGames()
                logger.error("📅 DataProvider error: \(providerError)")
                return
            }

            // Log team/stadium counts for diagnostics
            logger.info("📅 Loaded \(self.dataProvider.teams.count) teams, \(self.dataProvider.stadiums.count) stadiums")

            games = try await dataProvider.filterRichGames(
                sports: selectedSports,
                startDate: startDate,
                endDate: endDate
            )

            // Update diagnostics
            var newDiagnostics = ScheduleDiagnostics()
            newDiagnostics.lastQueryStartDate = queryStartDate
            newDiagnostics.lastQueryEndDate = queryEndDate
            newDiagnostics.lastQuerySports = Array(querySports)
            newDiagnostics.totalGamesReturned = games.count
            newDiagnostics.teamsLoaded = dataProvider.teams.count
            newDiagnostics.stadiumsLoaded = dataProvider.stadiums.count

            // Count games by sport
            var sportCounts: [Sport: Int] = [:]
            for game in games {
                sportCounts[game.game.sport, default: 0] += 1
            }
            newDiagnostics.gamesBySport = sportCounts

            self.diagnostics = newDiagnostics

            AnalyticsManager.shared.track(.scheduleViewed(sports: Array(selectedSports).map(\.rawValue)))
            logger.info("📅 Returned \(self.games.count) games")
            for (sport, count) in sportCounts.sorted(by: { $0.key.rawValue < $1.key.rawValue }) {
                logger.info("📅   \(sport.rawValue): \(count) games")
            }

            // Debug: Print all NBA games
            let nbaGames = games.filter { $0.game.sport == .nba }
            print("🏀 [DEBUG] All NBA games in schedule (\(nbaGames.count) total):")
            for game in nbaGames.sorted(by: { $0.game.dateTime < $1.game.dateTime }) {
                let dateStr = game.game.dateTime.gameDateTimeString(in: game.stadium.timeZone)
                print("🏀   \(dateStr): \(game.awayTeam.name) @ \(game.homeTeam.name) (\(game.game.id))")
            }

        } catch let cloudKitError as CloudKitError {
            self.error = cloudKitError
            self.errorMessage = cloudKitError.errorDescription
            logger.error("📅 CloudKit error: \(cloudKitError.errorDescription ?? "unknown")")
        } catch {
            self.error = error
            self.errorMessage = error.localizedDescription
            logger.error("📅 Error loading games: \(error.localizedDescription)")
        }

        isLoading = false
        updateFilteredGames()
    }

    func clearError() {
        error = nil
        errorMessage = nil
    }

    func toggleSport(_ sport: Sport) {
        if selectedSports.contains(sport) {
            selectedSports.remove(sport)
        } else {
            selectedSports.insert(sport)
        }
        AnalyticsManager.shared.track(.scheduleFiltered(sport: sport.rawValue, dateRange: "\(startDate.formatted(.dateTime.month().day())) - \(endDate.formatted(.dateTime.month().day()))"))
        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()
        }
    }

    // MARK: - Filtering & Grouping (pre-computed, not computed properties)

    /// Recomputes filtered games and groupings based on current search text
    func updateFilteredGames() {
        // Step 1: Filter by search text
        if searchText.isEmpty {
            filteredGames = games
        } else {
            let query = searchText.lowercased()
            filteredGames = 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)
            }
        }

        // Step 2: Pre-compute grouping by sport (done once, not per-render)
        let grouped = Dictionary(grouping: filteredGames) { $0.game.sport }
        gamesBySport = 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 }) }
    }
}

// MARK: - Diagnostics Model

/// Diagnostic information for troubleshooting schedule display issues
struct ScheduleDiagnostics {
    var lastQueryStartDate: Date?
    var lastQueryEndDate: Date?
    var lastQuerySports: [Sport] = []
    var totalGamesReturned: Int = 0
    var teamsLoaded: Int = 0
    var stadiumsLoaded: Int = 0
    var gamesBySport: [Sport: Int] = [:]

    var summary: String {
        guard let start = lastQueryStartDate, let end = lastQueryEndDate else {
            return "No query executed"
        }

        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .short
        dateFormatter.timeStyle = .short

        var lines: [String] = []
        lines.append("Date Range: \(dateFormatter.string(from: start)) - \(dateFormatter.string(from: end))")
        lines.append("Sports: \(lastQuerySports.map(\.rawValue).joined(separator: ", "))")
        lines.append("Teams Loaded: \(teamsLoaded)")
        lines.append("Stadiums Loaded: \(stadiumsLoaded)")
        lines.append("Total Games: \(totalGamesReturned)")

        if !gamesBySport.isEmpty {
            lines.append("By Sport:")
            for (sport, count) in gamesBySport.sorted(by: { $0.key.rawValue < $1.key.rawValue }) {
                lines.append("  \(sport.rawValue): \(count)")
            }
        }

        return lines.joined(separator: "\n")
    }
}
