//
//  NHLStatsProvider.swift
//  SportsTime
//
//  NHL Stats API provider - official, documented, stable.
//  API: https://api-web.nhle.com
//

import Foundation

// MARK: - NHL Stats Provider

struct NHLStatsProvider: ScoreAPIProvider {

    // MARK: - Protocol Requirements

    let name = "NHL Stats API"
    let supportedSports: Set<Sport> = [.nhl]
    let reliability: ProviderReliability = .official
    let rateLimitKey = "nhl_stats"

    // MARK: - API Configuration

    private let baseURL = "https://api-web.nhle.com/v1"

    // MARK: - Team Abbreviation Mapping

    /// Maps common team abbreviations to NHL API team codes
    private static let teamAbbrevMapping: [String: String] = [
        "ANA": "ANA", "ARI": "ARI", "BOS": "BOS", "BUF": "BUF",
        "CGY": "CGY", "CAR": "CAR", "CHI": "CHI", "COL": "COL",
        "CBJ": "CBJ", "DAL": "DAL", "DET": "DET", "EDM": "EDM",
        "FLA": "FLA", "LA": "LAK", "LAK": "LAK", "MIN": "MIN",
        "MTL": "MTL", "NSH": "NSH", "NJ": "NJD", "NJD": "NJD",
        "NYI": "NYI", "NYR": "NYR", "OTT": "OTT", "PHI": "PHI",
        "PIT": "PIT", "SJ": "SJS", "SJS": "SJS", "SEA": "SEA",
        "STL": "STL", "TB": "TBL", "TBL": "TBL", "TOR": "TOR",
        "UTA": "UTA", "VAN": "VAN", "VGK": "VGK", "WSH": "WSH",
        "WPG": "WPG"
    ]

    // Team names for display
    private static let teamNames: [String: String] = [
        "ANA": "Anaheim Ducks", "ARI": "Arizona Coyotes", "BOS": "Boston Bruins",
        "BUF": "Buffalo Sabres", "CGY": "Calgary Flames", "CAR": "Carolina Hurricanes",
        "CHI": "Chicago Blackhawks", "COL": "Colorado Avalanche",
        "CBJ": "Columbus Blue Jackets", "DAL": "Dallas Stars", "DET": "Detroit Red Wings",
        "EDM": "Edmonton Oilers", "FLA": "Florida Panthers", "LAK": "Los Angeles Kings",
        "MIN": "Minnesota Wild", "MTL": "Montreal Canadiens", "NSH": "Nashville Predators",
        "NJD": "New Jersey Devils", "NYI": "New York Islanders", "NYR": "New York Rangers",
        "OTT": "Ottawa Senators", "PHI": "Philadelphia Flyers", "PIT": "Pittsburgh Penguins",
        "SJS": "San Jose Sharks", "SEA": "Seattle Kraken", "STL": "St. Louis Blues",
        "TBL": "Tampa Bay Lightning", "TOR": "Toronto Maple Leafs", "UTA": "Utah Hockey Club",
        "VAN": "Vancouver Canucks", "VGK": "Vegas Golden Knights",
        "WSH": "Washington Capitals", "WPG": "Winnipeg Jets"
    ]

    // MARK: - Fetch Game

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

        // Build schedule URL for the date
        let dateString = query.normalizedDateString
        let urlString = "\(baseURL)/schedule/\(dateString)"

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

        // Fetch data
        let (data, response) = try await URLSession.shared.data(from: url)

        // 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
            }
            throw ScoreProviderError.networkError(underlying: "HTTP \(httpResponse.statusCode)")
        }

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

    // MARK: - Response Parsing

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

        // Find games on the requested date
        for dayEntry in gameWeek {
            guard let games = dayEntry["games"] as? [[String: Any]] else { continue }

            for game in games {
                // Extract team info
                guard let homeTeam = game["homeTeam"] as? [String: Any],
                      let awayTeam = game["awayTeam"] as? [String: Any],
                      let homeAbbrevRaw = homeTeam["abbrev"] as? String,
                      let awayAbbrevRaw = awayTeam["abbrev"] as? String else {
                    continue
                }

                // Normalize abbreviations
                let homeAbbrev = Self.teamAbbrevMapping[homeAbbrevRaw.uppercased()] ?? homeAbbrevRaw.uppercased()
                let awayAbbrev = Self.teamAbbrevMapping[awayAbbrevRaw.uppercased()] ?? awayAbbrevRaw.uppercased()

                // Check if this matches the query
                if let queryHome = query.homeTeamAbbrev {
                    let normalizedQueryHome = Self.teamAbbrevMapping[queryHome.uppercased()] ?? queryHome.uppercased()
                    if normalizedQueryHome != homeAbbrev {
                        continue
                    }
                }
                if let queryAway = query.awayTeamAbbrev {
                    let normalizedQueryAway = Self.teamAbbrevMapping[queryAway.uppercased()] ?? queryAway.uppercased()
                    if normalizedQueryAway != awayAbbrev {
                        continue
                    }
                }

                // Extract team names
                let homeTeamName = homeTeam["placeName"] as? [String: Any]
                let homeTeamNameDefault = (homeTeamName?["default"] as? String) ?? Self.teamNames[homeAbbrev] ?? homeAbbrev

                let awayTeamName = awayTeam["placeName"] as? [String: Any]
                let awayTeamNameDefault = (awayTeamName?["default"] as? String) ?? Self.teamNames[awayAbbrev] ?? awayAbbrev

                // Extract scores
                let homeScore = homeTeam["score"] as? Int
                let awayScore = awayTeam["score"] as? Int

                // Extract game date
                let gameDate: Date
                if let startTime = game["startTimeUTC"] as? String {
                    let formatter = ISO8601DateFormatter()
                    gameDate = formatter.date(from: startTime) ?? query.date
                } else {
                    gameDate = query.date
                }

                return HistoricalGameResult(
                    sport: .nhl,
                    gameDate: gameDate,
                    homeTeamAbbrev: homeAbbrev,
                    awayTeamAbbrev: awayAbbrev,
                    homeTeamName: homeTeamNameDefault,
                    awayTeamName: awayTeamNameDefault,
                    homeScore: homeScore,
                    awayScore: awayScore,
                    source: .api,
                    providerName: name
                )
            }
        }

        return nil
    }
}

// MARK: - Sendable Conformance

extension NHLStatsProvider: Sendable {}
