//
//  HistoricalGameScraper.swift
//  SportsTime
//
//  Scrapes historical game data from sports reference sites when local database has no match.
//  Runs on-device so scales to unlimited users with no server costs.
//

import Foundation
import SwiftSoup

// MARK: - Scraped Game Result

struct ScrapedGame: Sendable {
    let date: Date
    let homeTeam: String
    let awayTeam: String
    let homeScore: Int?
    let awayScore: Int?
    let stadiumName: String
    let sport: Sport

    var formattedScore: String? {
        guard let home = homeScore, let away = awayScore else { return nil }
        return "\(awayTeam) \(away) - \(homeTeam) \(home)"
    }
}

// MARK: - Historical Game Scraper

actor HistoricalGameScraper {
    static let shared = HistoricalGameScraper()

    // In-memory cache to avoid redundant network requests during a session
    private var cache: [String: ScrapedGame?] = [:]

    private init() {}

    // MARK: - Public API

    /// Scrape historical game data for a stadium on a specific date
    func scrapeGame(stadium: Stadium, date: Date) async -> ScrapedGame? {
        let cacheKey = "\(stadium.id)-\(dateKey(date))"

        // Check cache first
        if let cached = cache[cacheKey] {
            print("🌐 [Scraper] Cache hit for \(stadium.name) on \(dateKey(date))")
            return cached
        }

        print("🌐 [Scraper] ════════════════════════════════════════")
        print("🌐 [Scraper] Scraping game for \(stadium.name) on \(dateKey(date))")
        print("🌐 [Scraper] Sport: \(stadium.sport.rawValue)")

        let result: ScrapedGame?
        switch stadium.sport {
        case .mlb:
            result = await scrapeBaseballReference(stadium: stadium, date: date)
        case .nba:
            result = await scrapeBasketballReference(stadium: stadium, date: date)
        case .nhl:
            result = await scrapeHockeyReference(stadium: stadium, date: date)
        case .nfl:
            result = await scrapeFootballReference(stadium: stadium, date: date)
        case .mls, .wnba, .nwsl:
            print("🌐 [Scraper] ⚠️ \(stadium.sport.rawValue) scraping not yet implemented")
            result = nil
        }

        cache[cacheKey] = result

        if let game = result {
            print("🌐 [Scraper] ✅ Found: \(game.awayTeam) @ \(game.homeTeam)")
            if let score = game.formattedScore {
                print("🌐 [Scraper] Score: \(score)")
            }
        } else {
            print("🌐 [Scraper] ❌ No game found")
        }
        print("🌐 [Scraper] ════════════════════════════════════════")

        return result
    }

    // MARK: - Sport-Specific Scrapers

    private func scrapeBaseballReference(stadium: Stadium, date: Date) async -> ScrapedGame? {
        let (month, day, year) = dateComponents(date)
        let urlString = "https://www.baseball-reference.com/boxes/?month=\(month)&day=\(day)&year=\(year)"
        return await scrapeReferencesSite(urlString: urlString, stadium: stadium, date: date, sport: .mlb)
    }

    private func scrapeBasketballReference(stadium: Stadium, date: Date) async -> ScrapedGame? {
        let (month, day, year) = dateComponents(date)
        let urlString = "https://www.basketball-reference.com/boxscores/?month=\(month)&day=\(day)&year=\(year)"
        return await scrapeReferencesSite(urlString: urlString, stadium: stadium, date: date, sport: .nba)
    }

    private func scrapeHockeyReference(stadium: Stadium, date: Date) async -> ScrapedGame? {
        let (month, day, year) = dateComponents(date)
        let urlString = "https://www.hockey-reference.com/boxscores/?month=\(month)&day=\(day)&year=\(year)"
        return await scrapeReferencesSite(urlString: urlString, stadium: stadium, date: date, sport: .nhl)
    }

    private func scrapeFootballReference(stadium: Stadium, date: Date) async -> ScrapedGame? {
        print("🌐 [Scraper] ⚠️ NFL scraping not yet implemented")
        return nil
    }

    // MARK: - Generic Scraper (SwiftSoup)

    private func scrapeReferencesSite(
        urlString: String,
        stadium: Stadium,
        date: Date,
        sport: Sport
    ) async -> ScrapedGame? {
        print("🌐 [Scraper] Fetching: \(urlString)")

        guard let url = URL(string: urlString) else { return nil }

        do {
            var request = URLRequest(url: url)
            request.setValue("Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)", forHTTPHeaderField: "User-Agent")

            let (data, response) = try await URLSession.shared.data(for: request)

            guard let httpResponse = response as? HTTPURLResponse,
                  httpResponse.statusCode == 200,
                  let html = String(data: data, encoding: .utf8) else {
                print("🌐 [Scraper] ❌ Failed to fetch page")
                return nil
            }

            print("🌐 [Scraper] Parsing HTML (\(data.count) bytes)")

            let targetTeams = await findTeamNamesForStadium(stadium)
            guard !targetTeams.isEmpty else {
                print("🌐 [Scraper] ❌ No team mapping for stadium: \(stadium.name)")
                return nil
            }
            print("🌐 [Scraper] Looking for home team: \(targetTeams.first ?? "unknown")")

            // Parse with SwiftSoup
            let doc = try SwiftSoup.parse(html)
            let gameSummaries = try doc.select("div.game_summary")
            print("🌐 [Scraper] Found \(gameSummaries.count) games on this date")

            for game in gameSummaries {
                let rows = try game.select("table.teams tbody tr")

                if rows.count >= 2 {
                    let awayRow = rows[0]
                    let homeRow = rows[1]

                    let awayTeam = try awayRow.select("td a").first()?.text() ?? ""
                    let homeTeam = try homeRow.select("td a").first()?.text() ?? ""

                    let awayScoreText = try awayRow.select("td.right").first()?.text() ?? ""
                    let homeScoreText = try homeRow.select("td.right").first()?.text() ?? ""

                    print("🌐 [Scraper] Game: \(awayTeam) @ \(homeTeam)")

                    // Check if any of our target team names match the home team
                    let isMatch = targetTeams.contains { targetName in
                        homeTeam.lowercased().contains(targetName.lowercased()) ||
                        targetName.lowercased().contains(homeTeam.lowercased())
                    }

                    if isMatch {
                        return ScrapedGame(
                            date: date,
                            homeTeam: homeTeam,
                            awayTeam: awayTeam,
                            homeScore: Int(homeScoreText),
                            awayScore: Int(awayScoreText),
                            stadiumName: stadium.name,
                            sport: sport
                        )
                    }
                }
            }

            print("🌐 [Scraper] ⚠️ No game found for team: \(targetTeams.first ?? "unknown")")

        } catch {
            print("🌐 [Scraper] ❌ Error: \(error.localizedDescription)")
        }

        return nil
    }

    // MARK: - Helpers

    private func dateComponents(_ date: Date) -> (Int, Int, Int) {
        let calendar = Calendar.current
        return (
            calendar.component(.month, from: date),
            calendar.component(.day, from: date),
            calendar.component(.year, from: date)
        )
    }

    private func dateKey(_ date: Date) -> String {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        return formatter.string(from: date)
    }

    /// Returns an array of possible names for the home team (team name + city variations)
    /// Uses AppDataProvider to dynamically look up teams by stadium ID, so new stadiums
    /// and renames are automatically supported via CloudKit sync.
    private func findTeamNamesForStadium(_ stadium: Stadium) async -> [String] {
        // Access MainActor-isolated AppDataProvider
        let teams = await MainActor.run { AppDataProvider.shared.teams }

        // Find the team that plays at this stadium using canonical ID
        guard let team = teams.first(where: { $0.stadiumId == stadium.id }) else {
            print("🌐 [Scraper] No team found for stadium ID: \(stadium.id)")
            return []
        }

        // Return variations that Sports-Reference sites might use
        // (team name, city, abbreviation)
        return [team.name, team.city, team.abbreviation]
    }

    func clearCache() {
        cache.removeAll()
    }
}
