#!/usr/bin/env python3
"""
Fetch player stats from BallDontLie API for player prop backtesting.

This script fetches player game-by-game stats for NBA, NFL, and MLB
which can be used for player prop backtesting.

Usage:
    python scripts/fetch_player_stats.py [sport]
    
    sport: nba, nfl, mlb, or all (default: all)
"""

import os
import sys
import json
import time
import hashlib
from datetime import datetime
from pathlib import Path

try:
    import requests
    USE_REQUESTS = True
except ImportError:
    import urllib.request
    USE_REQUESTS = False

# Configuration
API_BASE_URL = "https://api.balldontlie.io"
DATA_DIR = Path(__file__).parent.parent / "data" / "player_stats"

API_KEY = os.environ.get("BALLDONTLIE_API_KEY")
if not API_KEY:
    raise RuntimeError("BALLDONTLIE_API_KEY is not set. Put it in the environment (recommended: .env / systemd EnvironmentFile).")

SPORT_CONFIG = {
    "nba": {
        "api_prefix": "/v1",
        "stats_endpoint": "/stats",
        "season_param": "seasons[]",
        "output_file": "nba_player_stats.json"
    },
    "nfl": {
        "api_prefix": "/nfl/v1",
        "stats_endpoint": "/stats",
        "season_param": "season",
        "output_file": "nfl_player_stats.json"
    },
    "mlb": {
        "api_prefix": "/mlb/v1",
        "stats_endpoint": "/stats",
        "season_param": "season",
        "output_file": "mlb_player_stats.json"
    }
}


def make_request(url: str) -> dict:
    """Make an API request to BallDontLie."""
    headers = {"Authorization": API_KEY}
    
    if USE_REQUESTS:
        response = requests.get(url, headers=headers, timeout=30)
        response.raise_for_status()
        return response.json()
    else:
        req = urllib.request.Request(url, headers=headers)
        with urllib.request.urlopen(req, timeout=30) as response:
            return json.loads(response.read().decode())


def fetch_player_stats(sport: str, season: int = 2024, max_pages: int = 50) -> list:
    """Fetch player stats for a given sport and season."""
    config = SPORT_CONFIG.get(sport)
    if not config:
        print(f"Unknown sport: {sport}")
        return []
    
    all_stats = []
    page = 1
    
    print(f"Fetching {sport.upper()} player stats for {season} season...")
    
    while page <= max_pages:
        if sport == "nba":
            url = f"{API_BASE_URL}{config['api_prefix']}{config['stats_endpoint']}?{config['season_param']}={season}&per_page=100&page={page}"
        else:
            url = f"{API_BASE_URL}{config['api_prefix']}{config['stats_endpoint']}?{config['season_param']}={season}&per_page=100&page={page}"
        
        print(f"  Page {page}...", end=" ", flush=True)
        
        try:
            data = make_request(url)
            stats = data.get("data", [])
            
            if not stats:
                print("done (no more data)")
                break
            
            all_stats.extend(stats)
            print(f"{len(stats)} entries (total: {len(all_stats)})")
            
            meta = data.get("meta", {})
            if meta.get("next_page") is None:
                print(f"  ✓ Completed - all pages fetched")
                break
            
            page += 1
            time.sleep(0.3)
            
        except Exception as e:
            print(f"error: {e}")
            break
    
    return all_stats


def convert_nba_stat(stat: dict) -> dict:
    """Convert NBA stat to player prop format."""
    player = stat.get("player", {})
    game = stat.get("game", {})
    team = stat.get("team", {})
    
    return {
        "id": hashlib.md5(f"nba-{stat.get('id', '')}".encode()).hexdigest()[:8],
        "sport": "nba",
        "date": game.get("date", "")[:10] if game.get("date") else "",
        "season": game.get("season", 2024),
        "player": {
            "id": player.get("id"),
            "name": f"{player.get('first_name', '')} {player.get('last_name', '')}".strip(),
            "position": player.get("position"),
            "team": team.get("name", team.get("full_name", ""))
        },
        "game": {
            "id": game.get("id"),
            "home_team": game.get("home_team_id"),
            "away_team": game.get("visitor_team_id"),
            "home_score": game.get("home_team_score"),
            "away_score": game.get("visitor_team_score")
        },
        "stats": {
            # Points props
            "points": stat.get("pts", 0),
            "rebounds": stat.get("reb", 0),
            "assists": stat.get("ast", 0),
            "steals": stat.get("stl", 0),
            "blocks": stat.get("blk", 0),
            "turnovers": stat.get("turnover", 0),
            # Shooting
            "fg_made": stat.get("fgm", 0),
            "fg_attempts": stat.get("fga", 0),
            "fg_pct": stat.get("fg_pct", 0),
            "three_made": stat.get("fg3m", 0),
            "three_attempts": stat.get("fg3a", 0),
            "three_pct": stat.get("fg3_pct", 0),
            "ft_made": stat.get("ftm", 0),
            "ft_attempts": stat.get("fta", 0),
            # Combo props
            "pts_reb_ast": (stat.get("pts", 0) or 0) + (stat.get("reb", 0) or 0) + (stat.get("ast", 0) or 0),
            "pts_reb": (stat.get("pts", 0) or 0) + (stat.get("reb", 0) or 0),
            "pts_ast": (stat.get("pts", 0) or 0) + (stat.get("ast", 0) or 0),
            "reb_ast": (stat.get("reb", 0) or 0) + (stat.get("ast", 0) or 0),
            "stl_blk": (stat.get("stl", 0) or 0) + (stat.get("blk", 0) or 0),
            # Minutes
            "minutes": stat.get("min", "0"),
            "plus_minus": stat.get("plus_minus", 0)
        }
    }


def convert_nfl_stat(stat: dict) -> dict:
    """Convert NFL stat to player prop format."""
    player = stat.get("player", {})
    game = stat.get("game", {})
    team = stat.get("team", {})
    
    return {
        "id": hashlib.md5(f"nfl-{player.get('id', '')}-{game.get('id', '')}".encode()).hexdigest()[:8],
        "sport": "nfl",
        "date": game.get("date", "")[:10] if game.get("date") else "",
        "season": game.get("season", 2024),
        "player": {
            "id": player.get("id"),
            "name": f"{player.get('first_name', '')} {player.get('last_name', '')}".strip(),
            "position": player.get("position"),
            "team": team.get("name", team.get("full_name", ""))
        },
        "game": {
            "id": game.get("id"),
            "week": game.get("week")
        },
        "stats": {
            # Passing props
            "passing_yards": stat.get("passing_yards", 0),
            "passing_tds": stat.get("passing_touchdowns", 0),
            "passing_attempts": stat.get("passing_attempts", 0),
            "passing_completions": stat.get("passing_completions", 0),
            "interceptions": stat.get("passing_interceptions", 0),
            "qb_rating": stat.get("qb_rating", 0),
            # Rushing props
            "rushing_yards": stat.get("rushing_yards", 0),
            "rushing_tds": stat.get("rushing_touchdowns", 0),
            "rushing_attempts": stat.get("rushing_attempts", 0),
            # Receiving props
            "receptions": stat.get("receptions", 0),
            "receiving_yards": stat.get("receiving_yards", 0),
            "receiving_tds": stat.get("receiving_touchdowns", 0),
            "targets": stat.get("receiving_targets", 0),
            # Combo props
            "total_yards": (stat.get("passing_yards", 0) or 0) + (stat.get("rushing_yards", 0) or 0) + (stat.get("receiving_yards", 0) or 0),
            "total_tds": (stat.get("passing_touchdowns", 0) or 0) + (stat.get("rushing_touchdowns", 0) or 0) + (stat.get("receiving_touchdowns", 0) or 0),
            "rush_rec_yards": (stat.get("rushing_yards", 0) or 0) + (stat.get("receiving_yards", 0) or 0),
            # Defense
            "tackles": stat.get("total_tackles", 0),
            "sacks": stat.get("defensive_sacks", 0),
            "def_interceptions": stat.get("defensive_interceptions", 0),
            # Kicking
            "fg_made": stat.get("field_goals_made", 0),
            "total_points": stat.get("total_points", 0)
        }
    }


def convert_mlb_stat(stat: dict) -> dict:
    """Convert MLB stat to player prop format."""
    player = stat.get("player", {})
    game = stat.get("game", {})
    
    return {
        "id": hashlib.md5(f"mlb-{player.get('id', '')}-{game.get('id', '')}".encode()).hexdigest()[:8],
        "sport": "mlb",
        "date": game.get("date", "")[:10] if game.get("date") else "",
        "season": 2024,
        "player": {
            "id": player.get("id"),
            "name": f"{player.get('first_name', '')} {player.get('last_name', '')}".strip(),
            "position": player.get("position"),
            "team": stat.get("team_name", "")
        },
        "game": {
            "id": game.get("id")
        },
        "stats": {
            # Hitting props
            "hits": stat.get("hits", 0),
            "at_bats": stat.get("at_bats", 0),
            "runs": stat.get("runs", 0),
            "rbi": stat.get("rbi", 0),
            "home_runs": stat.get("hr", 0),
            "walks": stat.get("bb", 0),
            "strikeouts": stat.get("k", 0),
            "avg": stat.get("avg", 0),
            "obp": stat.get("obp", 0),
            "slg": stat.get("slg", 0),
            # Combo props
            "total_bases": (stat.get("hits", 0) or 0) + (stat.get("hr", 0) or 0) * 3,  # Simplified
            "hits_runs_rbi": (stat.get("hits", 0) or 0) + (stat.get("runs", 0) or 0) + (stat.get("rbi", 0) or 0),
            # Pitching props
            "innings_pitched": stat.get("ip", 0),
            "pitcher_strikeouts": stat.get("p_k", 0),
            "earned_runs": stat.get("er", 0),
            "era": stat.get("era", 0),
            "pitch_count": stat.get("pitch_count", 0),
            "pitcher_hits": stat.get("p_hits", 0),
            "pitcher_walks": stat.get("p_bb", 0)
        }
    }


def process_sport(sport: str, season: int = 2024):
    """Process player stats for a single sport."""
    config = SPORT_CONFIG.get(sport)
    if not config:
        print(f"Unknown sport: {sport}")
        return None
    
    print(f"\n{'=' * 60}")
    print(f"Processing {sport.upper()} Player Stats")
    print(f"{'=' * 60}")
    
    # Fetch stats
    stats = fetch_player_stats(sport, season)
    
    if not stats:
        print(f"No {sport.upper()} stats fetched.")
        return None
    
    # Convert to player prop format
    print(f"\nConverting {len(stats)} stat entries...")
    converted = []
    
    for stat in stats:
        try:
            if sport == "nba":
                converted.append(convert_nba_stat(stat))
            elif sport == "nfl":
                converted.append(convert_nfl_stat(stat))
            elif sport == "mlb":
                converted.append(convert_mlb_stat(stat))
        except Exception as e:
            pass  # Skip invalid entries
    
    print(f"Converted {len(converted)} stat entries")
    
    # Save to file
    output_file = DATA_DIR / config["output_file"]
    with open(output_file, "w") as f:
        json.dump(converted, f, indent=2)
    
    print(f"Saved to {output_file}")
    
    # Show sample
    if converted:
        sample = converted[0]
        print(f"\nSample {sport.upper()} player stat:")
        print(f"  Player: {sample['player']['name']} ({sample['player']['position']})")
        print(f"  Date: {sample['date']}")
        stats_sample = list(sample['stats'].items())[:5]
        for k, v in stats_sample:
            if v:
                print(f"  {k}: {v}")
    
    return {
        "sport": sport,
        "total_entries": len(converted),
        "unique_players": len(set(s["player"]["name"] for s in converted if s.get("player", {}).get("name")))
    }


def main():
    """Main entry point."""
    print("=" * 60)
    print("BallDontLie Player Stats Fetcher")
    print("=" * 60)
    
    # Ensure directory exists
    DATA_DIR.mkdir(parents=True, exist_ok=True)
    
    # Determine which sports to process
    all_sports = ["nba", "nfl", "mlb"]
    sports_to_process = all_sports
    
    if len(sys.argv) > 1:
        arg = sys.argv[1].lower()
        if arg == "all":
            sports_to_process = all_sports
        elif arg in SPORT_CONFIG:
            sports_to_process = [arg]
        else:
            print(f"Unknown sport: {arg}")
            print(f"Available: {', '.join(SPORT_CONFIG.keys())}, all")
            sys.exit(1)
    
    # Process each sport
    results = []
    for sport in sports_to_process:
        result = process_sport(sport, season=2024)
        if result:
            results.append(result)
    
    # Save metadata
    metadata = {
        "importedAt": datetime.now().isoformat(),
        "source": "BallDontLie API",
        "totalEntries": sum(r["total_entries"] for r in results),
        "sports": [r["sport"] for r in results],
        "season": 2024,
        "dataType": "player_game_stats"
    }
    
    metadata_file = DATA_DIR / "metadata.json"
    with open(metadata_file, "w") as f:
        json.dump(metadata, f, indent=2)
    
    print(f"\n{'=' * 60}")
    print("SUMMARY - Player Stats for Props")
    print(f"{'=' * 60}")
    for r in results:
        print(f"  {r['sport'].upper()}: {r['total_entries']} game stats from {r['unique_players']} players")
    print(f"  {'─' * 30}")
    print(f"  TOTAL: {metadata['totalEntries']} player game stats")
    print(f"\n✅ Done! Player stats saved for prop backtesting.")


if __name__ == "__main__":
    main()
