//
//  NBAStatsProvider.swift
//  SportsTime
//
//  NBA Stats API provider - unofficial but functional.
//  API: https://stats.nba.com
//  Note: Requires specific headers, may break without notice.
//

import Foundation

// MARK: - NBA Stats Provider

struct NBAStatsProvider: ScoreAPIProvider {

    // MARK: - Protocol Requirements

    let name = "NBA Stats API"
    let supportedSports: Set<Sport> = [.nba]
    let reliability: ProviderReliability = .unofficial
    let rateLimitKey = "nba_stats"

    // MARK: - API Configuration

    private let baseURL = "https://stats.nba.com/stats"

    // Required headers to avoid 403 errors
    private let requiredHeaders: [String: String] = [
        "Host": "stats.nba.com",
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
        "Accept": "application/json, text/plain, */*",
        "Accept-Language": "en-US,en;q=0.5",
        "Referer": "https://www.nba.com/",
        "x-nba-stats-origin": "stats",
        "x-nba-stats-token": "true",
        "Connection": "keep-alive"
    ]

    // MARK: - Team ID Mapping

    /// Maps team abbreviations to NBA Stats API team IDs
    private static let teamIdMapping: [String: Int] = [
        "ATL": 1610612737, "BOS": 1610612738, "BKN": 1610612751, "CHA": 1610612766,
        "CHI": 1610612741, "CLE": 1610612739, "DAL": 1610612742, "DEN": 1610612743,
        "DET": 1610612765, "GSW": 1610612744, "HOU": 1610612745, "IND": 1610612754,
        "LAC": 1610612746, "LAL": 1610612747, "MEM": 1610612763, "MIA": 1610612748,
        "MIL": 1610612749, "MIN": 1610612750, "NOP": 1610612740, "NYK": 1610612752,
        "OKC": 1610612760, "ORL": 1610612753, "PHI": 1610612755, "PHX": 1610612756,
        "POR": 1610612757, "SAC": 1610612758, "SAS": 1610612759, "TOR": 1610612761,
        "UTA": 1610612762, "WAS": 1610612764
    ]

    // Reverse mapping
    private static let idToAbbrevMapping: [Int: String] = {
        Dictionary(uniqueKeysWithValues: teamIdMapping.map { ($1, $0) })
    }()

    // Team names
    private static let teamNames: [String: String] = [
        "ATL": "Atlanta Hawks", "BOS": "Boston Celtics", "BKN": "Brooklyn Nets",
        "CHA": "Charlotte Hornets", "CHI": "Chicago Bulls", "CLE": "Cleveland Cavaliers",
        "DAL": "Dallas Mavericks", "DEN": "Denver Nuggets", "DET": "Detroit Pistons",
        "GSW": "Golden State Warriors", "HOU": "Houston Rockets", "IND": "Indiana Pacers",
        "LAC": "Los Angeles Clippers", "LAL": "Los Angeles Lakers", "MEM": "Memphis Grizzlies",
        "MIA": "Miami Heat", "MIL": "Milwaukee Bucks", "MIN": "Minnesota Timberwolves",
        "NOP": "New Orleans Pelicans", "NYK": "New York Knicks", "OKC": "Oklahoma City Thunder",
        "ORL": "Orlando Magic", "PHI": "Philadelphia 76ers", "PHX": "Phoenix Suns",
        "POR": "Portland Trail Blazers", "SAC": "Sacramento Kings", "SAS": "San Antonio Spurs",
        "TOR": "Toronto Raptors", "UTA": "Utah Jazz", "WAS": "Washington Wizards"
    ]

    // MARK: - Fetch Game

    func fetchGame(query: HistoricalGameQuery) async throws -> HistoricalGameResult? {
        guard query.sport == .nba else {
            throw ScoreProviderError.unsupportedSport(query.sport)
        }

        // Build scoreboard URL for the date
        let dateString = query.normalizedDateString.replacingOccurrences(of: "-", with: "")
        let urlString = "\(baseURL)/scoreboardv2?GameDate=\(dateString)&LeagueID=00&DayOffset=0"

        guard let url = URL(string: urlString) else {
            throw ScoreProviderError.networkError(underlying: "Invalid URL")
        }

        // Create request with required headers
        var request = URLRequest(url: url)
        request.httpMethod = "GET"
        for (key, value) in requiredHeaders {
            request.setValue(value, forHTTPHeaderField: key)
        }

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

        // Check HTTP response
        guard let httpResponse = response as? HTTPURLResponse else {
            throw ScoreProviderError.networkError(underlying: "Invalid response type")
        }

        guard httpResponse.statusCode == 200 else {
            if httpResponse.statusCode == 429 {
                throw ScoreProviderError.rateLimited
            }
            if httpResponse.statusCode == 403 {
                throw ScoreProviderError.providerUnavailable(reason: "Access denied - headers may need update")
            }
            throw ScoreProviderError.networkError(underlying: "HTTP \(httpResponse.statusCode)")
        }

        // Parse response
        return try parseScoreboardResponse(data: data, query: query)
    }

    // MARK: - Response Parsing

    private func parseScoreboardResponse(data: Data, query: HistoricalGameQuery) throws -> HistoricalGameResult? {
        guard let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
              let resultSets = json["resultSets"] as? [[String: Any]] else {
            throw ScoreProviderError.parseError(message: "Invalid JSON structure")
        }

        // Find the GameHeader result set
        guard let gameHeaderSet = resultSets.first(where: { ($0["name"] as? String) == "GameHeader" }),
              let headers = gameHeaderSet["headers"] as? [String],
              let rowSet = gameHeaderSet["rowSet"] as? [[Any]] else {
            return nil
        }

        // Get column indices
        let homeTeamIdIdx = headers.firstIndex(of: "HOME_TEAM_ID")
        let visitorTeamIdIdx = headers.firstIndex(of: "VISITOR_TEAM_ID")
        let gameStatusIdx = headers.firstIndex(of: "GAME_STATUS_TEXT")

        // Find the LineScore result set for scores
        let lineScoreSet = resultSets.first(where: { ($0["name"] as? String) == "LineScore" })
        let lineScoreHeaders = lineScoreSet?["headers"] as? [String]
        let lineScoreRows = lineScoreSet?["rowSet"] as? [[Any]]
        let teamIdScoreIdx = lineScoreHeaders?.firstIndex(of: "TEAM_ID")
        let ptsIdx = lineScoreHeaders?.firstIndex(of: "PTS")

        // Process each game
        for row in rowSet {
            guard let homeTeamIdIdx = homeTeamIdIdx,
                  let visitorTeamIdIdx = visitorTeamIdIdx,
                  homeTeamIdIdx < row.count,
                  visitorTeamIdIdx < row.count,
                  let homeTeamId = row[homeTeamIdIdx] as? Int,
                  let awayTeamId = row[visitorTeamIdIdx] as? Int else {
                continue
            }

            // Get team abbreviations
            guard let homeAbbrev = Self.idToAbbrevMapping[homeTeamId],
                  let awayAbbrev = Self.idToAbbrevMapping[awayTeamId] else {
                continue
            }

            // Check if this matches the query
            if let queryHome = query.homeTeamAbbrev, queryHome.uppercased() != homeAbbrev {
                continue
            }
            if let queryAway = query.awayTeamAbbrev, queryAway.uppercased() != awayAbbrev {
                continue
            }

            // Get team names
            let homeTeamName = Self.teamNames[homeAbbrev] ?? homeAbbrev
            let awayTeamName = Self.teamNames[awayAbbrev] ?? awayAbbrev

            // Get scores from LineScore
            var homeScore: Int?
            var awayScore: Int?

            if let lineScoreRows = lineScoreRows,
               let teamIdScoreIdx = teamIdScoreIdx,
               let ptsIdx = ptsIdx {

                for scoreRow in lineScoreRows {
                    guard teamIdScoreIdx < scoreRow.count,
                          ptsIdx < scoreRow.count,
                          let teamId = scoreRow[teamIdScoreIdx] as? Int else {
                        continue
                    }

                    if teamId == homeTeamId {
                        homeScore = scoreRow[ptsIdx] as? Int
                    } else if teamId == awayTeamId {
                        awayScore = scoreRow[ptsIdx] as? Int
                    }
                }
            }

            return HistoricalGameResult(
                sport: .nba,
                gameDate: query.date,
                homeTeamAbbrev: homeAbbrev,
                awayTeamAbbrev: awayAbbrev,
                homeTeamName: homeTeamName,
                awayTeamName: awayTeamName,
                homeScore: homeScore,
                awayScore: awayScore,
                source: .api,
                providerName: name
            )
        }

        return nil
    }
}

// MARK: - Sendable Conformance

extension NBAStatsProvider: Sendable {}
