#!/usr/bin/env python3
"""
NBA Data Service for Backtesting AI
Integrates NBA API with caching to avoid repulling data
"""

import os
import sys
import json
import time
import hashlib
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any
import pandas as pd

# Add the virtual environment to Python path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'nba_api_env', 'lib', 'python3.13', 'site-packages'))

try:
    from nba_api.stats.endpoints import (
        playercareerstats,
        leaguegamefinder,
        teamgamelogs,
        playergamelogs,
        scoreboardv2,
        commonteamroster,
        commonplayerinfo
    )
    from nba_api.live.nba.endpoints import scoreboard
    from nba_api.stats.static import players, teams
    import requests
except ImportError as e:
    print(f"Error importing NBA API: {e}")
    print("Make sure NBA API is installed: pip install nba_api")
    sys.exit(1)

class NBACacheManager:
    """Manages caching of NBA data to avoid repulling"""

    def __init__(self, cache_dir: str = "data/nba_cache"):
        self.cache_dir = cache_dir
        os.makedirs(cache_dir, exist_ok=True)
        self.cache_metadata_file = os.path.join(cache_dir, "cache_metadata.json")
        self.load_metadata()

    def load_metadata(self):
        """Load cache metadata"""
        if os.path.exists(self.cache_metadata_file):
            with open(self.cache_metadata_file, 'r') as f:
                self.metadata = json.load(f)
        else:
            self.metadata = {}

    def save_metadata(self):
        """Save cache metadata"""
        with open(self.cache_metadata_file, 'w') as f:
            json.dump(self.metadata, f, indent=2, default=str)

    def get_cache_key(self, endpoint: str, params: Dict[str, Any]) -> str:
        """Generate cache key from endpoint and parameters"""
        param_str = json.dumps(params, sort_keys=True)
        cache_content = f"{endpoint}:{param_str}"
        return hashlib.md5(cache_content.encode()).hexdigest()

    def is_cached(self, cache_key: str, max_age_hours: int = 24) -> bool:
        """Check if data is cached and not expired"""
        if cache_key not in self.metadata:
            return False

        cached_time = datetime.fromisoformat(self.metadata[cache_key]['timestamp'])
        age_hours = (datetime.now() - cached_time).total_seconds() / 3600

        return age_hours < max_age_hours

    def get_cached_data(self, cache_key: str) -> Optional[Any]:
        """Retrieve cached data"""
        if not self.is_cached(cache_key):
            return None

        cache_file = os.path.join(self.cache_dir, f"{cache_key}.json")
        if os.path.exists(cache_file):
            with open(cache_file, 'r') as f:
                return json.load(f)
        return None

    def cache_data(self, cache_key: str, data: Any, metadata: Dict[str, Any] = None):
        """Cache data with metadata"""
        # Save data
        cache_file = os.path.join(self.cache_dir, f"{cache_key}.json")
        with open(cache_file, 'w') as f:
            json.dump(data, f, indent=2, default=str)

        # Update metadata
        self.metadata[cache_key] = {
            'timestamp': datetime.now().isoformat(),
            'size': len(json.dumps(data)),
            'metadata': metadata or {}
        }
        self.save_metadata()

    def get_cache_stats(self) -> Dict[str, Any]:
        """Get cache statistics"""
        total_size = 0
        total_entries = len(self.metadata)
        oldest_entry = None
        newest_entry = None

        for entry in self.metadata.values():
            total_size += entry.get('size', 0)
            timestamp = datetime.fromisoformat(entry['timestamp'])

            if oldest_entry is None or timestamp < oldest_entry:
                oldest_entry = timestamp
            if newest_entry is None or timestamp > newest_entry:
                newest_entry = timestamp

        return {
            'total_entries': total_entries,
            'total_size_mb': total_size / (1024 * 1024),
            'oldest_entry': oldest_entry.isoformat() if oldest_entry else None,
            'newest_entry': newest_entry.isoformat() if newest_entry else None,
            'cache_dir': self.cache_dir
        }

class NBADataService:
    """NBA Data Service with caching"""

    def __init__(self):
        self.cache = NBACacheManager()
        self.base_url = "https://stats.nba.com"
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
            'Accept': 'application/json',
            'Accept-Language': 'en-US,en;q=0.9',
            'Referer': 'https://www.nba.com/',
        }

    def _cached_request(self, endpoint: str, params: Dict[str, Any] = None,
                       max_age_hours: int = 24) -> Optional[Any]:
        """Make cached API request"""
        params = params or {}
        cache_key = self.cache.get_cache_key(endpoint, params)

        # Check cache first
        cached_data = self.cache.get_cached_data(cache_key)
        if cached_data is not None:
            print(f"✅ Cache hit for {endpoint}", file=sys.stderr)
            return cached_data

        print(f"🔄 Fetching fresh data for {endpoint}", file=sys.stderr)
        try:
            # Make actual API call (this would be the NBA API call)
            # For now, we'll simulate with a placeholder
            data = self._fetch_from_nba_api(endpoint, params)

            # Cache the result
            self.cache.cache_data(cache_key, data, {
                'endpoint': endpoint,
                'params': params,
                'timestamp': datetime.now().isoformat()
            })

            return data

        except Exception as e:
            print(f"❌ Error fetching {endpoint}: {e}", file=sys.stderr)
            return None

    def _fetch_from_nba_api(self, endpoint: str, params: Dict[str, Any]) -> Any:
        """Actual NBA API call implementation"""
        if endpoint == "players":
            return self._get_all_players()
        elif endpoint == "teams":
            return self._get_all_teams()
        elif endpoint == "games":
            return self._get_games(params)
        elif endpoint == "player_stats":
            return self._get_player_stats(params)
        elif endpoint == "team_stats":
            return self._get_team_stats(params)
        elif endpoint == "live_games":
            return self._get_live_games()
        else:
            raise ValueError(f"Unknown endpoint: {endpoint}")

    def _get_all_players(self) -> List[Dict[str, Any]]:
        """Get all NBA players with caching"""
        try:
            all_players = players.get_players()
            return [{
                'id': player['id'],
                'full_name': player['full_name'],
                'first_name': player['first_name'],
                'last_name': player['last_name'],
                'is_active': player['is_active'],
                'last_updated': datetime.now().isoformat()
            } for player in all_players]
        except Exception as e:
            print(f"Error fetching players: {e}", file=sys.stderr)
            return []

    def _get_all_teams(self) -> List[Dict[str, Any]]:
        """Get all NBA teams with caching"""
        try:
            all_teams = teams.get_teams()
            return [{
                'id': team['id'],
                'full_name': team['full_name'],
                'abbreviation': team['abbreviation'],
                'nickname': team['nickname'],
                'city': team['city'],
                'state': team['state'],
                'year_founded': team['year_founded'],
                'last_updated': datetime.now().isoformat()
            } for team in all_teams]
        except Exception as e:
            print(f"Error fetching teams: {e}", file=sys.stderr)
            return []

    def _get_games(self, params: Dict[str, Any]) -> List[Dict[str, Any]]:
        """Get games data with parameters"""
        try:
            season = params.get('season', '2023-24')
            season_type = params.get('season_type', 'Regular Season')

            # Use NBA API to get games
            gamefinder = leaguegamefinder.LeagueGameFinder(
                season_nullable=season,
                season_type_nullable=season_type
            )

            df = gamefinder.get_data_frames()[0]

            # Convert to our format
            games = []
            for _, row in df.iterrows():
                games.append({
                    'game_id': str(row['GAME_ID']),
                    'game_date': str(row['GAME_DATE']),
                    'home_team_id': str(row['TEAM_ID']),
                    'home_team_name': row['TEAM_NAME'],
                    'home_team_score': int(row['PTS']) if pd.notna(row['PTS']) else None,
                    'away_team_id': str(row['MATCHUP'].split(' ')[0] if ' @ ' in row['MATCHUP'] else row['MATCHUP'].split(' vs. ')[1]),
                    'away_team_score': None,  # Would need to calculate from matchup
                    'season': season,
                    'season_type': season_type,
                    'last_updated': datetime.now().isoformat()
                })

            return games

        except Exception as e:
            print(f"Error fetching games: {e}", file=sys.stderr)
            return []

    def _get_player_stats(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Get player statistics"""
        try:
            player_id = params.get('player_id')
            if not player_id:
                return {'error': 'player_id required'}

            # Get player career stats
            career = playercareerstats.PlayerCareerStats(player_id=player_id)
            df = career.get_data_frames()[0]

            # Convert to our format
            stats = []
            for _, row in df.iterrows():
                stats.append({
                    'player_id': str(player_id),
                    'season': row['SEASON_ID'],
                    'team': row['TEAM_ABBREVIATION'],
                    'games_played': int(row['GP']),
                    'points': float(row['PTS']) if pd.notna(row['PTS']) else 0,
                    'rebounds': float(row['REB']) if pd.notna(row['REB']) else 0,
                    'assists': float(row['AST']) if pd.notna(row['AST']) else 0,
                    'steals': float(row['STL']) if pd.notna(row['STL']) else 0,
                    'blocks': float(row['BLK']) if pd.notna(row['BLK']) else 0,
                    'last_updated': datetime.now().isoformat()
                })

            return {
                'player_id': str(player_id),
                'stats': stats,
                'total_seasons': len(stats)
            }

        except Exception as e:
            print(f"Error fetching player stats: {e}", file=sys.stderr)
            return {'error': str(e)}

    def _get_team_stats(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Get team statistics"""
        try:
            team_id = params.get('team_id')
            season = params.get('season', '2023-24')

            if not team_id:
                return {'error': 'team_id required'}

            # Get team game logs
            team_logs = teamgamelogs.TeamGameLogs(
                team_id_nullable=team_id,
                season_nullable=season
            )

            df = team_logs.get_data_frames()[0]

            # Convert to our format
            games = []
            for _, row in df.iterrows():
                games.append({
                    'game_id': str(row['GAME_ID']),
                    'game_date': str(row['GAME_DATE']),
                    'team_id': str(team_id),
                    'opponent': row['MATCHUP'].replace(team_logs.get_data_frames()[0]['TEAM_ABBREVIATION'].iloc[0], '').replace(' vs. ', '').replace(' @ ', '').strip(),
                    'points': int(row['PTS']) if pd.notna(row['PTS']) else 0,
                    'opponent_points': int(row['PTS']) - (int(row['PLUS_MINUS']) if pd.notna(row['PLUS_MINUS']) else 0),
                    'result': 'W' if row['WL'] == 'W' else 'L',
                    'home_away': 'HOME' if ' vs. ' in row['MATCHUP'] else 'AWAY',
                    'last_updated': datetime.now().isoformat()
                })

            return {
                'team_id': str(team_id),
                'season': season,
                'games': games,
                'total_games': len(games)
            }

        except Exception as e:
            print(f"Error fetching team stats: {e}", file=sys.stderr)
            return {'error': str(e)}

    def _get_live_games(self) -> Dict[str, Any]:
        """Get live game data"""
        try:
            # Get today's scoreboard
            games = scoreboard.ScoreBoard()
            data = games.get_dict()

            live_games = []
            for game in data.get('scoreboard', {}).get('games', []):
                live_games.append({
                    'game_id': game['gameId'],
                    'home_team': game['homeTeam']['teamName'],
                    'home_score': game['homeTeam']['score'],
                    'away_team': game['awayTeam']['teamName'],
                    'away_score': game['awayTeam']['score'],
                    'status': game['gameStatusText'],
                    'period': game.get('period', 0),
                    'game_clock': game.get('gameClock', ''),
                    'last_updated': datetime.now().isoformat()
                })

            return {
                'games': live_games,
                'total_games': len(live_games),
                'last_updated': datetime.now().isoformat()
            }

        except Exception as e:
            print(f"Error fetching live games: {e}", file=sys.stderr)
            return {'error': str(e)}

    # Public API methods
    def get_players(self, use_cache: bool = True) -> List[Dict[str, Any]]:
        """Get all NBA players"""
        if not use_cache:
            return self._get_all_players()
        return self._cached_request("players") or []

    def get_teams(self, use_cache: bool = True) -> List[Dict[str, Any]]:
        """Get all NBA teams"""
        if not use_cache:
            return self._get_all_teams()
        return self._cached_request("teams") or []

    def get_games(self, season: str = "2023-24", season_type: str = "Regular Season",
                  use_cache: bool = True) -> List[Dict[str, Any]]:
        """Get games for a season"""
        params = {'season': season, 'season_type': season_type}
        if not use_cache:
            return self._get_games(params)
        return self._cached_request("games", params) or []

    def get_player_stats(self, player_id: str, use_cache: bool = True) -> Dict[str, Any]:
        """Get player statistics"""
        params = {'player_id': player_id}
        if not use_cache:
            return self._get_player_stats(params)
        return self._cached_request("player_stats", params, max_age_hours=6) or {}

    def get_team_stats(self, team_id: str, season: str = "2023-24",
                      use_cache: bool = True) -> Dict[str, Any]:
        """Get team statistics"""
        params = {'team_id': team_id, 'season': season}
        if not use_cache:
            return self._get_team_stats(params)
        return self._cached_request("team_stats", params, max_age_hours=6) or {}

    def get_live_games(self, use_cache: bool = True) -> Dict[str, Any]:
        """Get live game data"""
        if not use_cache:
            return self._get_live_games()
        return self._cached_request("live_games", {}, max_age_hours=0.1) or {}  # 6 minutes for live data

    def get_cache_stats(self) -> Dict[str, Any]:
        """Get cache statistics"""
        return self.cache.get_cache_stats()

    def clear_cache(self, pattern: str = None) -> int:
        """Clear cache entries"""
        # This would need implementation in cache manager
        print("Cache clearing not yet implemented", file=sys.stderr)
        return 0

def main():
    """Main function for API calls or testing"""
    import sys

    if len(sys.argv) > 1:
        # API mode - called from Next.js
        endpoint = sys.argv[1]
        params = json.loads(sys.argv[2]) if len(sys.argv) > 2 else {}

        service = NBADataService()
        result = None

        try:
            if endpoint == "players":
                result = service.get_players(params.get('use_cache', True))
                # Apply filters
                if params.get('active_only', True):
                    result = [p for p in result if p.get('is_active', True)]
                if 'limit' in params:
                    offset = params.get('offset', 0)
                    limit = params['limit']
                    result = result[offset:offset + limit]

            elif endpoint == "teams":
                result = service.get_teams(params.get('use_cache', True))

            elif endpoint == "games":
                result = service.get_games(
                    params.get('season', '2023-24'),
                    params.get('season_type', 'Regular Season'),
                    params.get('use_cache', True)
                )

            elif endpoint == "player_stats":
                result = service.get_player_stats(
                    params['player_id'],
                    params.get('use_cache', True)
                )

            elif endpoint == "team_stats":
                result = service.get_team_stats(
                    params['team_id'],
                    params.get('season', '2023-24'),
                    params.get('use_cache', True)
                )

            elif endpoint == "live_games":
                result = service.get_live_games(params.get('use_cache', True))

            elif endpoint == "cache_stats":
                result = service.get_cache_stats()

            else:
                result = {"error": f"Unknown endpoint: {endpoint}"}

            # Output JSON for API consumption
            print(json.dumps(result))

        except Exception as e:
            print(json.dumps({"error": str(e)}))
            sys.exit(1)

    else:
        # Test mode - standalone testing
        service = NBADataService()

        print("🏀 NBA Data Service Test")
        print("=" * 50)

        # Test cache stats
        print("\n📊 Cache Statistics:")
        cache_stats = service.get_cache_stats()
        print(json.dumps(cache_stats, indent=2))

        # Test getting players
        print("\n🏃 Testing Players API:")
        players_data = service.get_players()
        print(f"✅ Retrieved {len(players_data)} players")
        if players_data:
            print(f"Sample player: {players_data[0]['full_name']} (ID: {players_data[0]['id']})")

        # Test getting teams
        print("\n🏀 Testing Teams API:")
        teams_data = service.get_teams()
        print(f"✅ Retrieved {len(teams_data)} teams")
        if teams_data:
            print(f"Sample team: {teams_data[0]['full_name']} ({teams_data[0]['abbreviation']})")

        # Test getting games
        print("\n📅 Testing Games API:")
        games_data = service.get_games()
        print(f"✅ Retrieved {len(games_data)} games")
        if games_data:
            print(f"Sample game: {games_data[0]['home_team_name']} vs {games_data[0]['away_team_id']}")

        # Test live games
        print("\n🔴 Testing Live Games API:")
        live_data = service.get_live_games()
        games_count = live_data.get('games', [])
        print(f"✅ Retrieved {len(games_count)} live games")

        print("\n✅ NBA Data Service test completed!")

if __name__ == "__main__":
    main()
