#!/usr/bin/env python3
"""
Fetch NBA Lineup and On/Off Data from NBA.com Stats API
Captures:
- 5-man lineup combinations and their performance
- Player on/off court splits
- Plus/minus by lineup

This fills a critical gap for advanced betting analysis.

Run: Daily after games complete
"""
import requests
import psycopg2
import os
import time
import json
from datetime import datetime, timezone, timedelta
import argparse

NBA_STATS_BASE = 'https://stats.nba.com/stats'
REQUEST_DELAY = 1

# Headers required for NBA.com API
NBA_HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    'Accept': 'application/json, text/plain, */*',
    'Accept-Language': 'en-US,en;q=0.9',
    'Origin': 'https://www.nba.com',
    'Referer': 'https://www.nba.com/',
    'x-nba-stats-origin': 'stats',
    'x-nba-stats-token': 'true',
}


def load_db_url():
    env_path = '/var/www/html/eventheodds/.env'
    try:
        with open(env_path, 'r') as f:
            for line in f:
                if line.startswith('SPORTS_DATABASE_URL='):
                    return line.split('=', 1)[1].strip().split('?')[0]
    except FileNotFoundError:
        pass
    return os.environ.get('SPORTS_DATABASE_URL', '').split('?')[0]


def ensure_lineup_tables(cur):
    """Create lineup tracking tables"""
    # Team lineup combinations
    cur.execute('''
        CREATE TABLE IF NOT EXISTS "NBALineup" (
            id BIGSERIAL PRIMARY KEY,
            season VARCHAR(20),
            "teamId" INT,
            team VARCHAR(50),
            "lineupId" VARCHAR(100),
            player1 VARCHAR(100),
            player2 VARCHAR(100),
            player3 VARCHAR(100),
            player4 VARCHAR(100),
            player5 VARCHAR(100),
            minutes FLOAT,
            "plusMinus" FLOAT,
            "offRating" FLOAT,
            "defRating" FLOAT,
            "netRating" FLOAT,
            pace FLOAT,
            gp INT,
            wins INT,
            losses INT,
            "fgPct" FLOAT,
            "fg3Pct" FLOAT,
            "ftPct" FLOAT,
            "rebPct" FLOAT,
            "astPct" FLOAT,
            "tovPct" FLOAT,
            "updatedAt" TIMESTAMP DEFAULT NOW(),
            UNIQUE(season, "teamId", "lineupId")
        )
    ''')
    cur.execute('CREATE INDEX IF NOT EXISTS "NBALineup_team_idx" ON "NBALineup" ("teamId", season)')
    cur.execute('CREATE INDEX IF NOT EXISTS "NBALineup_netrating_idx" ON "NBALineup" ("netRating" DESC)')

    # Player on/off splits
    cur.execute('''
        CREATE TABLE IF NOT EXISTS "NBAPlayerOnOff" (
            id BIGSERIAL PRIMARY KEY,
            season VARCHAR(20),
            "playerId" INT,
            "playerName" VARCHAR(100),
            "teamId" INT,
            team VARCHAR(50),
            "onCourtMin" FLOAT,
            "onCourtPlusMinus" FLOAT,
            "onCourtOffRtg" FLOAT,
            "onCourtDefRtg" FLOAT,
            "onCourtNetRtg" FLOAT,
            "offCourtMin" FLOAT,
            "offCourtPlusMinus" FLOAT,
            "offCourtOffRtg" FLOAT,
            "offCourtDefRtg" FLOAT,
            "offCourtNetRtg" FLOAT,
            "onOffDiff" FLOAT,
            "updatedAt" TIMESTAMP DEFAULT NOW(),
            UNIQUE(season, "playerId")
        )
    ''')
    cur.execute('CREATE INDEX IF NOT EXISTS "NBAPlayerOnOff_team_idx" ON "NBAPlayerOnOff" ("teamId", season)')
    cur.execute('CREATE INDEX IF NOT EXISTS "NBAPlayerOnOff_diff_idx" ON "NBAPlayerOnOff" ("onOffDiff" DESC)')


def fetch_team_lineups(team_id, season='2025-26'):
    """Fetch lineup data for a team from NBA.com stats"""
    url = f'{NBA_STATS_BASE}/teamdashlineups'

    params = {
        'TeamID': team_id,
        'Season': season,
        'SeasonType': 'Regular Season',
        'MeasureType': 'Advanced',
        'PerMode': 'PerGame',
        'GroupQuantity': 5,
    }

    try:
        resp = requests.get(url, headers=NBA_HEADERS, params=params, timeout=30)

        if resp.status_code == 403:
            print(f"    Access denied (403) - NBA.com may be blocking")
            return []
        if resp.status_code != 200:
            print(f"    NBA.com returned {resp.status_code}")
            return []

        data = resp.json()
        result_sets = data.get('resultSets', [])

        lineups = []
        for rs in result_sets:
            if rs.get('name') == 'Lineups':
                headers = rs.get('headers', [])
                rows = rs.get('rowSet', [])

                for row in rows:
                    row_dict = dict(zip(headers, row))
                    lineups.append({
                        'lineup_id': row_dict.get('GROUP_ID'),
                        'team_id': team_id,
                        'player1': row_dict.get('GROUP_NAME', '').split(' - ')[0] if row_dict.get('GROUP_NAME') else None,
                        'players': row_dict.get('GROUP_NAME', '').split(' - ') if row_dict.get('GROUP_NAME') else [],
                        'minutes': row_dict.get('MIN'),
                        'plus_minus': row_dict.get('PLUS_MINUS'),
                        'off_rating': row_dict.get('OFF_RATING'),
                        'def_rating': row_dict.get('DEF_RATING'),
                        'net_rating': row_dict.get('NET_RATING'),
                        'pace': row_dict.get('PACE'),
                        'gp': row_dict.get('GP'),
                        'wins': row_dict.get('W'),
                        'losses': row_dict.get('L'),
                    })

        return lineups
    except Exception as e:
        print(f"    Error fetching lineups: {e}")
        return []


def fetch_player_on_off(team_id, season='2025-26'):
    """Fetch player on/off court splits"""
    url = f'{NBA_STATS_BASE}/teamplayeronoffdetails'

    params = {
        'TeamID': team_id,
        'Season': season,
        'SeasonType': 'Regular Season',
        'MeasureType': 'Advanced',
        'PerMode': 'PerGame',
    }

    try:
        resp = requests.get(url, headers=NBA_HEADERS, params=params, timeout=30)

        if resp.status_code != 200:
            return []

        data = resp.json()
        result_sets = data.get('resultSets', [])

        on_off = []
        on_court_data = {}
        off_court_data = {}

        for rs in result_sets:
            headers = rs.get('headers', [])
            rows = rs.get('rowSet', [])

            if rs.get('name') == 'PlayersOnCourtTeamPlayerOnOffDetails':
                for row in rows:
                    row_dict = dict(zip(headers, row))
                    player_id = row_dict.get('VS_PLAYER_ID')
                    on_court_data[player_id] = {
                        'player_id': player_id,
                        'player_name': row_dict.get('VS_PLAYER_NAME'),
                        'team_id': team_id,
                        'min': row_dict.get('MIN'),
                        'plus_minus': row_dict.get('PLUS_MINUS'),
                        'off_rating': row_dict.get('OFF_RATING'),
                        'def_rating': row_dict.get('DEF_RATING'),
                        'net_rating': row_dict.get('NET_RATING'),
                    }

            elif rs.get('name') == 'PlayersOffCourtTeamPlayerOnOffDetails':
                for row in rows:
                    row_dict = dict(zip(headers, row))
                    player_id = row_dict.get('VS_PLAYER_ID')
                    off_court_data[player_id] = {
                        'min': row_dict.get('MIN'),
                        'plus_minus': row_dict.get('PLUS_MINUS'),
                        'off_rating': row_dict.get('OFF_RATING'),
                        'def_rating': row_dict.get('DEF_RATING'),
                        'net_rating': row_dict.get('NET_RATING'),
                    }

        # Combine on/off data
        for player_id, on_data in on_court_data.items():
            off_data = off_court_data.get(player_id, {})
            on_net = on_data.get('net_rating') or 0
            off_net = off_data.get('net_rating') or 0

            on_off.append({
                **on_data,
                'off_court_min': off_data.get('min'),
                'off_court_plus_minus': off_data.get('plus_minus'),
                'off_court_off_rating': off_data.get('off_rating'),
                'off_court_def_rating': off_data.get('def_rating'),
                'off_court_net_rating': off_data.get('net_rating'),
                'on_off_diff': on_net - off_net if on_net and off_net else None,
            })

        return on_off
    except Exception as e:
        print(f"    Error fetching on/off: {e}")
        return []


def get_nba_teams():
    """Get list of NBA team IDs"""
    # NBA team IDs (2025-26 season)
    return {
        1610612737: 'ATL', 1610612738: 'BOS', 1610612751: 'BKN', 1610612766: 'CHA',
        1610612741: 'CHI', 1610612739: 'CLE', 1610612742: 'DAL', 1610612743: 'DEN',
        1610612765: 'DET', 1610612744: 'GSW', 1610612745: 'HOU', 1610612754: 'IND',
        1610612746: 'LAC', 1610612747: 'LAL', 1610612763: 'MEM', 1610612748: 'MIA',
        1610612749: 'MIL', 1610612750: 'MIN', 1610612740: 'NOP', 1610612752: 'NYK',
        1610612760: 'OKC', 1610612753: 'ORL', 1610612755: 'PHI', 1610612756: 'PHX',
        1610612757: 'POR', 1610612758: 'SAC', 1610612759: 'SAS', 1610612761: 'TOR',
        1610612762: 'UTA', 1610612764: 'WAS',
    }


def fetch_all_lineups(season='2025-26'):
    """Fetch lineups for all NBA teams"""
    db_url = load_db_url()
    if not db_url:
        raise RuntimeError('SPORTS_DATABASE_URL not set')

    conn = psycopg2.connect(db_url)
    cur = conn.cursor()

    ensure_lineup_tables(cur)
    conn.commit()

    print("=" * 60)
    print("FETCH NBA LINEUP DATA")
    print(f"Season: {season}")
    print(f"Time: {datetime.now(timezone.utc).isoformat()}")
    print("=" * 60)

    teams = get_nba_teams()
    total_lineups = 0
    total_on_off = 0

    for team_id, team_abbr in teams.items():
        print(f"\n{team_abbr}: Fetching lineups...")
        time.sleep(REQUEST_DELAY)

        # Fetch lineups
        lineups = fetch_team_lineups(team_id, season)
        if lineups:
            print(f"  Found {len(lineups)} lineup combinations")
            for lineup in lineups:
                players = lineup.get('players', [])
                try:
                    cur.execute('''
                        INSERT INTO "NBALineup" (
                            season, "teamId", team, "lineupId",
                            player1, player2, player3, player4, player5,
                            minutes, "plusMinus", "offRating", "defRating", "netRating",
                            pace, gp, wins, losses
                        )
                        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
                        ON CONFLICT (season, "teamId", "lineupId") DO UPDATE SET
                            minutes = EXCLUDED.minutes,
                            "plusMinus" = EXCLUDED."plusMinus",
                            "offRating" = EXCLUDED."offRating",
                            "defRating" = EXCLUDED."defRating",
                            "netRating" = EXCLUDED."netRating",
                            pace = EXCLUDED.pace,
                            gp = EXCLUDED.gp,
                            wins = EXCLUDED.wins,
                            losses = EXCLUDED.losses,
                            "updatedAt" = NOW()
                    ''', (
                        season, team_id, team_abbr, lineup.get('lineup_id'),
                        players[0] if len(players) > 0 else None,
                        players[1] if len(players) > 1 else None,
                        players[2] if len(players) > 2 else None,
                        players[3] if len(players) > 3 else None,
                        players[4] if len(players) > 4 else None,
                        lineup.get('minutes'), lineup.get('plus_minus'),
                        lineup.get('off_rating'), lineup.get('def_rating'), lineup.get('net_rating'),
                        lineup.get('pace'), lineup.get('gp'), lineup.get('wins'), lineup.get('losses'),
                    ))
                    total_lineups += 1
                except Exception as e:
                    print(f"    Insert error: {e}")
        else:
            print(f"  No lineup data returned (API may be blocking)")
            break  # Stop if blocked

        # Fetch on/off data
        time.sleep(REQUEST_DELAY)
        on_off = fetch_player_on_off(team_id, season)
        if on_off:
            print(f"  Found {len(on_off)} player on/off records")
            for player in on_off:
                try:
                    cur.execute('''
                        INSERT INTO "NBAPlayerOnOff" (
                            season, "playerId", "playerName", "teamId", team,
                            "onCourtMin", "onCourtPlusMinus", "onCourtOffRtg", "onCourtDefRtg", "onCourtNetRtg",
                            "offCourtMin", "offCourtPlusMinus", "offCourtOffRtg", "offCourtDefRtg", "offCourtNetRtg",
                            "onOffDiff"
                        )
                        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
                        ON CONFLICT (season, "playerId") DO UPDATE SET
                            "onCourtMin" = EXCLUDED."onCourtMin",
                            "onCourtPlusMinus" = EXCLUDED."onCourtPlusMinus",
                            "onCourtOffRtg" = EXCLUDED."onCourtOffRtg",
                            "onCourtDefRtg" = EXCLUDED."onCourtDefRtg",
                            "onCourtNetRtg" = EXCLUDED."onCourtNetRtg",
                            "offCourtMin" = EXCLUDED."offCourtMin",
                            "offCourtPlusMinus" = EXCLUDED."offCourtPlusMinus",
                            "offCourtOffRtg" = EXCLUDED."offCourtOffRtg",
                            "offCourtDefRtg" = EXCLUDED."offCourtDefRtg",
                            "offCourtNetRtg" = EXCLUDED."offCourtNetRtg",
                            "onOffDiff" = EXCLUDED."onOffDiff",
                            "updatedAt" = NOW()
                    ''', (
                        season, player.get('player_id'), player.get('player_name'),
                        team_id, team_abbr,
                        player.get('min'), player.get('plus_minus'),
                        player.get('off_rating'), player.get('def_rating'), player.get('net_rating'),
                        player.get('off_court_min'), player.get('off_court_plus_minus'),
                        player.get('off_court_off_rating'), player.get('off_court_def_rating'),
                        player.get('off_court_net_rating'), player.get('on_off_diff'),
                    ))
                    total_on_off += 1
                except Exception as e:
                    pass

        conn.commit()

    cur.close()
    conn.close()

    print(f"\n{'='*60}")
    print(f"TOTAL: {total_lineups} lineups, {total_on_off} player on/off records")
    print("=" * 60)

    return {'lineups': total_lineups, 'on_off': total_on_off}


def main():
    parser = argparse.ArgumentParser(description='Fetch NBA lineup data')
    parser.add_argument('--season', type=str, default='2025-26',
                        help='NBA season (e.g., 2025-26)')
    args = parser.parse_args()

    try:
        result = fetch_all_lineups(args.season)
        print(f"\nFetch complete: {result['lineups']} lineups, {result['on_off']} on/off")
    except Exception as e:
        print(f"ERROR: {e}")
        import traceback
        traceback.print_exc()


if __name__ == '__main__':
    main()
