remake this windows python script but for nfl

import tkinter as tk
from tkinter import ttk
from nba_api.stats.endpoints import leaguedashplayerstats, leaguegamelog
import time
import pandas as pd

# Precomputed dictionary of team names to IDs
TEAM_IDS = {
    "Atlanta Hawks": 1610612737, "Boston Celtics": 1610612738, "Brooklyn Nets": 1610612751,
    "Charlotte Hornets": 1610612766, "Chicago Bulls": 1610612741, "Cleveland Cavaliers": 1610612739,
    "Dallas Mavericks": 1610612742, "Denver Nuggets": 1610612743, "Detroit Pistons": 1610612765,
    "Golden State Warriors": 1610612744, "Houston Rockets": 1610612745, "Indiana Pacers": 1610612754,
    "LA Clippers": 1610612746, "Los Angeles Lakers": 1610612747, "Memphis Grizzlies": 1610612763,
    "Miami Heat": 1610612748, "Milwaukee Bucks": 1610612749, "Minnesota Timberwolves": 1610612750,
    "New Orleans Pelicans": 1610612740, "New York Knicks": 1610612752, "Oklahoma City Thunder": 1610612760,
    "Orlando Magic": 1610612753, "Philadelphia 76ers": 1610612755, "Phoenix Suns": 1610612756,
    "Portland Trail Blazers": 1610612757, "Sacramento Kings": 1610612758, "San Antonio Spurs": 1610612759,
    "Toronto Raptors": 1610612761, "Utah Jazz": 1610612762, "Washington Wizards": 1610612764
}

def get_top_players_for_selected_teams(selected_teams, selected_stat, consistency_threshold, apply_consistency_filter, use_lowest_score):
    # Map selected team names to TEAM_IDs
    selected_team_ids = [TEAM_IDS[team] for team in selected_teams]
    
    # Fetch all players' stats for the current season
    NBA_SEASON = '2024-25'  # Adjust this to the desired season
    try:
        player_stats = leaguedashplayerstats.LeagueDashPlayerStats(
            season=NBA_SEASON,
            per_mode_detailed='PerGame',
            timeout=30
        )
        player_stats_df = player_stats.get_data_frames()[0]
    except Exception as e:
        print(f"Failed to fetch league player stats: {e}")
        return []
    
    # Filter players from selected teams
    filtered_players = player_stats_df[player_stats_df['TEAM_ID'].isin(selected_team_ids)]
    
    # Map TEAM_IDs to team names
    team_id_to_name = {v: k for k, v in TEAM_IDS.items()}
    
    # Map selected_stat to the corresponding column in player_stats_df
    stat_column_map = {'PPG': 'PTS', 'REB': 'REB', 'AST': 'AST'}
    stat_column = stat_column_map.get(selected_stat, 'PTS')
    
    # Fetch league game logs
    try:
        league_gamelog = leaguegamelog.LeagueGameLog(
            season=NBA_SEASON,
            season_type_all_star='Regular Season',
            player_or_team_abbreviation='P',
            timeout=30
        )
        league_gamelog_df = league_gamelog.get_data_frames()[0]
    except Exception as e:
        print(f"Failed to fetch league game logs: {e}")
        return []
    
    # Filter game logs for players from selected teams
    player_ids = filtered_players['PLAYER_ID'].unique()
    player_game_logs = league_gamelog_df[league_gamelog_df['PLAYER_ID'].isin(player_ids)]
    
    if use_lowest_score:
        # Compute minimum stat of the selected stat for each player
        player_stat_min = player_game_logs.groupby('PLAYER_ID')[stat_column].min().reset_index()
        player_stat_min = player_stat_min.rename(columns={stat_column: 'MIN_STAT'})
        # Merge the minimum stat back to filtered_players
        filtered_players = filtered_players.merge(player_stat_min, on='PLAYER_ID', how='left')
    else:
        # Use average per-game stats (already in filtered_players)
        pass
    
    if apply_consistency_filter:
        # Compute standard deviation of the selected stat for each player
        player_stat_std = player_game_logs.groupby('PLAYER_ID')[stat_column].std().reset_index()
        player_stat_std = player_stat_std.rename(columns={stat_column: 'STD_DEV'})
        # Merge the standard deviation back to filtered_players
        filtered_players = filtered_players.merge(player_stat_std, on='PLAYER_ID', how='left')
        filtered_players['STD_DEV'] = filtered_players['STD_DEV'].fillna(0)  # Handle NaN values
        # Filter out players whose standard deviation exceeds the threshold
        filtered_players = filtered_players[filtered_players['STD_DEV'] <= consistency_threshold]
    else:
        # Skip standard deviation computation
        pass
    
    # Create list of tuples: (team_name, player_name, season, stat_value, std_dev, games_played)
    all_player_stats = []
    for _, row in filtered_players.iterrows():
        team_name = team_id_to_name.get(row['TEAM_ID'], 'Unknown Team')
        player_name = row['PLAYER_NAME']
        season = NBA_SEASON
        games_played = row['GP']  # Number of games played
        if use_lowest_score:
            stat_value = row['MIN_STAT']
        else:
            stat_value = row[stat_column]
        if apply_consistency_filter:
            std_dev = row['STD_DEV']
        else:
            std_dev = None
        all_player_stats.append((team_name, player_name, season, stat_value, std_dev, games_played))
    
    # Remove players with missing stat_value (e.g., if MIN_STAT is NaN)
    all_player_stats = [x for x in all_player_stats if pd.notnull(x[3])]
    
    # Return sorted results by stat_value
    return sorted(all_player_stats, key=lambda x: x[3], reverse=True)

def display_top_players():
    selected_teams = [team_listbox.get(i) for i in team_listbox.curselection()]
    selected_stat_value = selected_stat.get()
    try:
        max_players = int(max_players_entry.get())
    except ValueError:
        result_label.config(text="Invalid number for max players.")
        return
    try:
        consistency_threshold = float(consistency_entry.get())
    except ValueError:
        result_label.config(text="Invalid number for consistency threshold.")
        return
    
    apply_consistency_filter = consistency_var.get()
    use_lowest_score = lowest_score_var.get()
    
    if not selected_teams:
        result_label.config(text="Please select at least one team.")
        return
    
    result_label.config(text="Fetching data...")
    root.update()  # Refresh UI during processing
    
    start_time = time.time()
    top_players = get_top_players_for_selected_teams(
        selected_teams, selected_stat_value, consistency_threshold,
        apply_consistency_filter, use_lowest_score
    )[:max_players]
    end_time = time.time()
    
    # Display results
    result_area.delete("1.0", tk.END)
    if not top_players:
        result_label.config(text="No top players found.")
        return
    
    result_label.config(text=f"Data fetched successfully in {end_time - start_time:.2f} seconds!")
    
    # Determine the appropriate label for the stat
    stat_label_map = {'PPG': 'PPG', 'REB': 'RPG', 'AST': 'APG'}
    stat_label_text = stat_label_map.get(selected_stat_value, 'PPG')
    
    if use_lowest_score:
        result_area.insert(tk.END, f"Top {len(top_players)} players based on lowest {stat_label_text}:\n")
    else:
        result_area.insert(tk.END, f"Top {len(top_players)} players based on average {stat_label_text}:\n")
    
    result_text = ""
    for i, (team, player, season, stat_value, std_dev, games_played) in enumerate(top_players, start=1):
        stat_line = f"{i}. {player} - {stat_value:.2f} {stat_label_text} (Games Played: {games_played})"
        if apply_consistency_filter and std_dev is not None:
            stat_line += f" (Std Dev: {std_dev:.2f})"
        stat_line += f" ({season} season) [{team}]"
        result_text += stat_line + "\n"
    result_area.insert(tk.END, result_text + "\n")

# UI Setup
root = tk.Tk()
root.title("NBA Best Players Comparison")
root.rowconfigure(8, weight=1)
root.columnconfigure(1, weight=1)

team_label = ttk.Label(root, text="Select Teams:")
team_label.grid(row=0, column=0, padx=10, pady=10, sticky="NW")

team_listbox = tk.Listbox(root, selectmode=tk.MULTIPLE, height=15, exportselection=False)
for team in TEAM_IDS.keys():
    team_listbox.insert(tk.END, team)
team_listbox.grid(row=0, column=1, padx=10, pady=10, sticky="NSEW")

max_players_label = ttk.Label(root, text="Max Players:")
max_players_label.grid(row=1, column=0, padx=10, pady=10, sticky="W")

max_players_entry = ttk.Entry(root, width=5)
max_players_entry.grid(row=1, column=1, padx=10, pady=10, sticky="W")
max_players_entry.insert(0, "5")

# Variable to hold the selected stat
selected_stat = tk.StringVar(value='PPG')

# Label and Radio Buttons for Stat Selection
stat_label = ttk.Label(root, text="Select Stat to Compare:")
stat_label.grid(row=2, column=0, padx=10, pady=10, sticky="W")

stat_frame = ttk.Frame(root)
stat_frame.grid(row=2, column=1, padx=10, pady=10, sticky="W")

rb_ppg = ttk.Radiobutton(stat_frame, text='Points Per Game', variable=selected_stat, value='PPG')
rb_ppg.pack(side='left')
rb_reb = ttk.Radiobutton(stat_frame, text='Rebounds Per Game', variable=selected_stat, value='REB')
rb_reb.pack(side='left')
rb_ast = ttk.Radiobutton(stat_frame, text='Assists Per Game', variable=selected_stat, value='AST')
rb_ast.pack(side='left')

consistency_label = ttk.Label(root, text="Consistency Threshold (Max Std Dev):")
consistency_label.grid(row=3, column=0, padx=10, pady=10, sticky="W")

consistency_entry = ttk.Entry(root, width=5)
consistency_entry.grid(row=3, column=1, padx=10, pady=10, sticky="W")
consistency_entry.insert(0, "5")

# Variables and Checkbuttons for Toggles
consistency_var = tk.BooleanVar(value=True)
consistency_toggle = ttk.Checkbutton(root, text="Apply Consistency Filter", variable=consistency_var)
consistency_toggle.grid(row=4, column=0, columnspan=2, padx=10, pady=5, sticky="W")

lowest_score_var = tk.BooleanVar(value=False)
lowest_score_toggle = ttk.Checkbutton(root, text="Use Player's Lowest Score", variable=lowest_score_var)
lowest_score_toggle.grid(row=5, column=0, columnspan=2, padx=10, pady=5, sticky="W")

submit_button = ttk.Button(root, text="Get Top Players", command=display_top_players)
submit_button.grid(row=6, column=0, columnspan=2, pady=10)

result_label = ttk.Label(root, text="")
result_label.grid(row=7, column=0, columnspan=2, padx=10, pady=10)

result_area = tk.Text(root, wrap="word")
result_area.grid(row=8, column=0, columnspan=2, padx=10, pady=10, sticky="NSEW")

scrollbar = ttk.Scrollbar(root, orient="vertical", command=result_area.yview)
scrollbar.grid(row=8, column=2, sticky="NS")
result_area.configure(yscrollcommand=scrollbar.set)

root.mainloop()