import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import UnivariateSpline, interp1d
from scipy.stats import norm
import re

# Read the data
df = pd.read_csv(r'[DF_14]')

# Prompt for manager with validation
while True:
    manager_id = input("Enter manager ID (e.g., mcgrj101): ").strip()
    # Check if manager exists
    if manager_id in df['mgrID'].values:
        break
    else:
        print(f"ERROR: Manager '{manager_id}' not found in data. Please try again.")
        print("(Hint: Manager IDs are case-sensitive)")

print(f"✓ Manager '{manager_id}' found!\n")

# Prompt for gradient color with validation
while True:
    color_input = input("Enter gradient color hex code (default=#808080 blue, try #9B2D30 cranberry): ").strip()
    if not color_input:
        gradient_color = '#808080'
        break
    # Validate hex color format
    if re.match(r'^#[0-9A-Fa-f]{6}$', color_input):
        gradient_color = color_input
        break
    else:
        print(f"ERROR: Invalid hex color '{color_input}'. Must be format #RRGGBB (e.g., #FF0000)")

print(f"✓ Using color: {gradient_color}\n")

# Prompt for figure dimensions
fig_height_input = input("Enter figure height in inches (default=7.5 (4:3), try 5.625 for 16:9): ").strip()
fig_height = float(fig_height_input) if fig_height_input else 7.5
fig_width = 10  # Keep width fixed at 10

# Prompt for reference line
show_reference = input("Show horizontal reference line at final estimate? (y/n, default=y): ").strip().lower()
show_reference_line = show_reference != 'n'

# Prompt for axis tick intervals
x_tick_input = input("X-axis tick interval (e.g., 500, 1000, or leave blank for default=150): ").strip()
x_tick_interval = int(x_tick_input) if x_tick_input else 150

y_tick_input = input("Y-axis tick interval (e.g., 2, 5, or leave blank for default=1): ").strip()
y_tick_interval = float(y_tick_input) if y_tick_input else 1

# Prompt for custom y-axis limits
y_limits_input = input("Enter custom y-axis limits as 'min max' (e.g., '-10 10', or leave blank for auto): ").strip()
if y_limits_input:
    try:
        y_min_custom, y_max_custom = map(float, y_limits_input.split())
        use_custom_ylim = True
        print(f"✓ Using custom y-axis: [{y_min_custom}, {y_max_custom}]\n")
    except ValueError:
        print("ERROR: Invalid format. Using automatic y-axis limits.\n")
        use_custom_ylim = False
else:
    use_custom_ylim = False

# Prompt for HDI bandwidth (z-score)
z_max_input = input("Enter HDI bandwidth z-score (default=1.0, try 1.96 for 95% CI, 2.5 for wider): ").strip()
z_max = float(z_max_input) if z_max_input else 1.0

# Validate z_max
if z_max < 0.15:
    print(f"Warning: z-score of {z_max} is too small (min 0.15). Using 2.0 instead.")
    z_max = 2.0

# Prompt for number of bands
n_bands_input = input("Enter number of gradient bands (default=65, more=smoother but slower): ").strip()
n_bands = int(n_bands_input) if n_bands_input else 65

# Prompt for alpha range
alpha_min_input = input("Enter minimum alpha/transparency (default=0.03, lower=lighter edges): ").strip()
alpha_min = float(alpha_min_input) if alpha_min_input else 0.03

alpha_max_input = input("Enter maximum alpha/transparency (default=0.15, higher=darker center): ").strip()
alpha_max = float(alpha_max_input) if alpha_max_input else 0.15

# Prompt for contrast exponent
contrast_input = input("Enter contrast exponent (default=4, higher=more dramatic, try 3-4 for narrow bands): ").strip()
contrast_exponent = float(contrast_input) if contrast_input else 4.0

# Prompt for spline smoothing parameter
smooth_input = input("Enter spline smoothing factor (default=0.1, higher=smoother, try 0.05-0.3): ").strip()
smooth_factor = float(smooth_input) if smooth_input else 0.1

aspect_ratio = fig_width / fig_height

print(f"\nPlotting manager '{manager_id}' with:")
print(f"  - Figure size: {fig_width} × {fig_height} inches (aspect ratio {aspect_ratio:.2f}:1)")
print(f"  - ±{z_max} z-score bands")
print(f"  - {n_bands} gradient bands")
print(f"  - Alpha range: {alpha_min} to {alpha_min + alpha_max}")
print(f"  - Contrast exponent: {contrast_exponent}")
print(f"  - Spline smoothing: {smooth_factor}")
print(f"  - Gradient color: {gradient_color}")
print(f"  - Reference line: {'Yes' if show_reference_line else 'No'}")
print(f"  - X-axis ticks: {x_tick_interval}")
print(f"  - Y-axis ticks: {y_tick_interval}")
if use_custom_ylim:
    print(f"  - Y-axis limits: [{y_min_custom}, {y_max_custom}] (custom)")
else:
    print(f"  - Y-axis limits: auto")
print()

# Filter to specific manager
df_mgr = df[df['mgrID'] == manager_id].copy()

if len(df_mgr) == 0:
    print(f"ERROR: No data found for manager '{manager_id}'")
    print("Please check the manager ID and try again.")
else:
    # Drop rows with NaN in key columns
    df_mgr = df_mgr.dropna(subset=['pHB_se', 'winsHB'])
    
    df_mgr = df_mgr.sort_values('cum_games').reset_index(drop=True)
    
    # ADD PRIOR POINT AT GAME 0
    # Prior mean is 0 wins over .500, with SE = 2.4 wins/162 games
    prior_row = pd.DataFrame({
        'cum_games': [0],
        'winsHB': [0],  # Prior mean
        'winsHB_se': [2.4]  # Prior SE in wins per 162, tau = 2.4 wins/162
    })
    
    # Prepend prior to the manager's career data
    df_mgr = pd.concat([prior_row, df_mgr], ignore_index=True)
    
    # Calculate the variables
    df_mgr['se_wins162_proj'] = df_mgr['winsHB_se']
    df_mgr['wins162_proj'] = df_mgr['winsHB']
    
    # Apply smoothing with cubic splines
    x = df_mgr['cum_games'].values
    y_center = df_mgr['wins162_proj'].values
    se = df_mgr['se_wins162_proj'].values
    
    # Fit cubic spline for center line only
    # s parameter controls smoothing: 0 = exact fit, higher = smoother
    s_factor = len(x) * smooth_factor  # User-adjustable smoothing
    
    spline_center = UnivariateSpline(x, y_center, s=s_factor, k=3)
    
    # Evaluate spline at the data points
    wins162_proj_s = spline_center(x)
    se_s = se  # Use raw SE, don't smooth it - this prevents artificial inflation

    # Get final value from RAW data for reference line only
    wins162_final = df_mgr['wins162_proj'].iloc[-1]

    # Create dense x-grid for smooth rendering
    x_dense = np.linspace(x.min(), x.max(), 500)  # 500 points for smooth curves

    # Interpolate center and SE at dense grid
    spline_center_dense = spline_center(x_dense)
    # Interpolate SE using linear interpolation
    se_interp = interp1d(x, se_s, kind='linear', fill_value='extrapolate')
    se_dense = se_interp(x_dense)

    # Use spline directly without tapering correction
    wins162_proj_s_dense = spline_center_dense
    
    # Create z-score levels for smooth gradient
    z_levels = np.linspace(z_max, 0.1, n_bands)
    
    # Calculate bounds on dense grid
    upper_bounds = []
    lower_bounds = []
    
    for z in z_levels:
        upper = wins162_proj_s_dense + z * se_dense
        lower = wins162_proj_s_dense - z * se_dense
        upper_bounds.append(upper)
        lower_bounds.append(lower)
    
    # Create the plot with custom aspect ratio
    fig, ax = plt.subplots(figsize=(fig_width, fig_height))
    
    # Plot confidence bands with smooth gradient
    # Using z-stretching to create more visual contrast for narrow bands
    for i, z in enumerate(z_levels):
        # STRETCH z-values to create dramatic visual separation
        # This makes narrow bands (z=1.0) behave like much wider bands visually
        z_stretched = z * 3.5  # Aggressive stretch for better contrast
        
        # Calculate density on stretched scale
        density_ratio = np.exp(-0.5 * z_stretched**2)
        density_adjusted = density_ratio ** contrast_exponent
        
        # Alpha proportional to stretched density
        alpha = alpha_min + density_adjusted * alpha_max
        
        ax.fill_between(
            x_dense,
            lower_bounds[i],
            upper_bounds[i],
            color=gradient_color,
            alpha=alpha,
            edgecolor='none',
            linewidth=0
        )
    
    # Plot optional horizontal reference line at final value
    if show_reference_line:
        ax.axhline(y=wins162_final, color='black', linestyle='--', linewidth=1, zorder=99)
    

    
    # Set y-axis limits - custom or dynamic
    if use_custom_ylim:
        ax.set_ylim(y_min_custom, y_max_custom)
    else:
        # Dynamic y-axis limits based on data
        y_min = min([lb.min() for lb in lower_bounds])
        y_max = max([ub.max() for ub in upper_bounds])
        y_padding = (y_max - y_min) * 0.1
        ax.set_ylim(y_min - y_padding, y_max + y_padding)
    
    # Clean white background
    ax.set_facecolor('white')
    fig.patch.set_facecolor('white')
    
    # Remove top and right spines
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    
    # Set custom tick intervals - starting from 0
    x_data_min = 0  # Always start at 0 now
    x_data_max = x.max()
    
    # Generate ticks from 0
    x_ticks = np.arange(0, x_data_max + x_tick_interval, x_tick_interval)
    ax.set_xticks(x_ticks)
    
    # Add small fixed padding on left, slight padding on right
    left_padding = 25  # Fixed padding in games
    ax.set_xlim(0 - left_padding, x_data_max * 1.02)
    
    y_min_ax, y_max_ax = ax.get_ylim()
    # Start from a nice round number
    y_start = np.floor(y_min_ax / y_tick_interval) * y_tick_interval
    y_ticks = np.arange(y_start, y_max_ax + y_tick_interval, y_tick_interval)
    ax.set_yticks(y_ticks)
    
    # Rotate x-axis labels - UPDATED FONT SIZE FOR POSTER
    plt.xticks(rotation=45, ha='right', fontsize=22)
    plt.yticks(fontsize=22)
    
    # Tight layout
    plt.tight_layout()
    
    # Save as SVG with manager ID as filename
    output_path = rf'C:\Users\dmk38\Documents\x5\{manager_id}.svg'
    plt.savefig(output_path, format='svg', bbox_inches='tight')
    print(f"\n✓ Plot saved to: {output_path}")
    
    # Show the plot
    plt.show()
    
    print(f"\nPlot complete!")
    print(f"Final estimate: {wins162_final:.2f} wins/162 over .500")
    print(f"Settings: z={z_max}, bands={n_bands}, alpha=[{alpha_min}, {alpha_min+alpha_max}], contrast={contrast_exponent}")
    print(f"          smoothing={smooth_factor}, color={gradient_color}, ref_line={show_reference_line}")
    print(f"          x_ticks={x_tick_interval}, y_ticks={y_tick_interval}")
    if use_custom_ylim:
        print(f"          y_limits=[{y_min_custom}, {y_max_custom}] (custom)")
    else:
        print(f"          y_limits=auto")
    print(f"          figure={fig_width}×{fig_height} (ratio={aspect_ratio:.2f}:1)")