//
//  MLBStatsProvider.swift
//  SportsTime
//
//  MLB Stats API provider - official, documented, stable.
//  API: https://statsapi.mlb.com
//

import Foundation

// MARK: - MLB Stats Provider

struct MLBStatsProvider: ScoreAPIProvider {

    // MARK: - Protocol Requirements

    let name = "MLB Stats API"
    let supportedSports: Set<Sport> = [.mlb]
    let reliability: ProviderReliability = .official
    let rateLimitKey = "mlb_stats"

    // MARK: - API Configuration

    private let baseURL = "https://statsapi.mlb.com/api/v1"

    // MARK: - Team ID Mapping

    /// Maps team abbreviations to MLB Stats API team IDs
    private static let teamIdMapping: [String: Int] = [
        "ARI": 109, "ATL": 144, "BAL": 110, "BOS": 111,
        "CHC": 112, "CWS": 145, "CIN": 113, "CLE": 114,
        "COL": 115, "DET": 116, "HOU": 117, "KC": 118,
        "LAA": 108, "LAD": 119, "MIA": 146, "MIL": 158,
        "MIN": 142, "NYM": 121, "NYY": 147, "OAK": 133,
        "PHI": 143, "PIT": 134, "SD": 135, "SF": 137,
        "SEA": 136, "STL": 138, "TB": 139, "TEX": 140,
        "TOR": 141, "WSH": 120
    ]

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

    // MARK: - Fetch Game

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

        // Build schedule URL for the date
        let dateString = query.normalizedDateString
        let urlString = "\(baseURL)/schedule?sportId=1&date=\(dateString)&hydrate=team,linescore"

        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 dates = json["dates"] as? [[String: Any]] else {
            throw ScoreProviderError.parseError(message: "Invalid JSON structure")
        }

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

            for game in games {
                // Extract team info
                guard let teams = game["teams"] as? [String: Any],
                      let homeTeamData = teams["home"] as? [String: Any],
                      let awayTeamData = teams["away"] as? [String: Any],
                      let homeTeam = homeTeamData["team"] as? [String: Any],
                      let awayTeam = awayTeamData["team"] as? [String: Any],
                      let homeTeamId = homeTeam["id"] as? Int,
                      let awayTeamId = awayTeam["id"] 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
                }

                // Extract team names
                let homeTeamName = homeTeam["name"] as? String ?? homeAbbrev
                let awayTeamName = awayTeam["name"] as? String ?? awayAbbrev

                // Extract scores from linescore if available
                var homeScore: Int?
                var awayScore: Int?

                if let linescore = game["linescore"] as? [String: Any],
                   let lineTeams = linescore["teams"] as? [String: Any] {
                    if let homeLineData = lineTeams["home"] as? [String: Any] {
                        homeScore = homeLineData["runs"] as? Int
                    }
                    if let awayLineData = lineTeams["away"] as? [String: Any] {
                        awayScore = awayLineData["runs"] as? Int
                    }
                }

                // Alternative: get scores from team data
                if homeScore == nil, let score = homeTeamData["score"] as? Int {
                    homeScore = score
                }
                if awayScore == nil, let score = awayTeamData["score"] as? Int {
                    awayScore = score
                }

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

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

        return nil
    }
}

// MARK: - Sendable Conformance

extension MLBStatsProvider: Sendable {}
