import numpy as np
import collections

try:
    import matplotlib.pyplot as plt
    import seaborn as sns
    from IPython.display import clear_output
    HAS_PLOTTING = True
except ImportError:
    HAS_PLOTTING = False

class RealTimePlotter:
    """Provides real-time matplotlib/seaborn charts tracking predictions, accuracy, and bankroll."""
    def __init__(self, max_points=200):
        self.max_points = max_points
        self.rolls = collections.deque(maxlen=max_points)
        self.predictions = collections.deque(maxlen=max_points)
        self.accuracy = collections.deque(maxlen=max_points)
        self.bankroll = collections.deque(maxlen=max_points)
        self.win_loss = collections.deque(maxlen=max_points)
        self.step_counter = 0
        
        if HAS_PLOTTING:
            sns.set_theme(style="darkgrid")
            plt.ion()  # Interactive mode
            self.fig, self.axs = plt.subplots(3, 1, figsize=(10, 12))
            self.fig.canvas.manager.set_window_title('Prophet ML Auditor Dashboard')
            plt.tight_layout(pad=3.0)
            
    def update(self, roll_result, prediction, current_accuracy, current_bankroll, won):
        """Update tracker with new data from the latest roll step."""
        self.rolls.append(roll_result)
        self.predictions.append(prediction)
        self.accuracy.append(current_accuracy)
        self.bankroll.append(current_bankroll)
        self.win_loss.append(1 if won else 0)
        self.step_counter += 1
        
        if HAS_PLOTTING:
            if self.step_counter % 25 == 0:
                self.fig.canvas.flush_events()
                
            if len(self.rolls) > 5:
                import time
                current_time = time.time()
                if not hasattr(self, 'last_draw_time'):
                    self.last_draw_time = 0
                    
                # Throttle redraws to max 10 FPS to prevent GUI freezes
                if current_time - self.last_draw_time > 0.1:
                    self._draw()
                    self.last_draw_time = current_time
            
    def _draw(self):
        """Redraws the matplot canvas."""
        for ax in self.axs:
            ax.clear()
            
        x_data = range(len(self.rolls))
        
        # Plot 1: Rolls vs Predictions
        self.axs[0].plot(x_data, self.rolls, label="Actual Roll", color="blue", alpha=0.6)
        pred_array = np.array(self.predictions)
        
        # Color correct predictions green, incorrect red
        colors = ['green' if w else 'red' for w in self.win_loss]
        self.axs[0].scatter(x_data, pred_array, c=colors, label="Prediction (G=Win, R=Loss)", s=15, zorder=5)
        self.axs[0].axhline(y=50, color='gray', linestyle='--', alpha=0.5)
        self.axs[0].set_title("Actual Rolls vs Predictions")
        self.axs[0].set_ylabel("Outcome")
        self.axs[0].legend(loc="upper left")
        
        # Plot 2: Model Accuracy (Moving Average)
        self.axs[1].plot(x_data, [a * 100 for a in self.accuracy], label="Overall Accuracy %", color="purple")
        self.axs[1].axhline(y=50, color='red', linestyle='--', alpha=0.5, label="Baseline (50%)")
        self.axs[1].set_title("Prediction Accuracy")
        self.axs[1].set_ylabel("Accuracy (%)")
        self.axs[1].set_ylim([0, 100])
        self.axs[1].legend(loc="upper left")
        
        # Plot 3: Bankroll
        self.axs[2].plot(x_data, self.bankroll, label="Bankroll", color="gold")
        self.axs[2].set_title("Bankroll Evolution")
        self.axs[2].set_ylabel("Balance")
        self.axs[2].set_xlabel("Roll Number")
        self.axs[2].legend(loc="upper left")
        
        self.fig.canvas.draw()
        self.fig.canvas.flush_events()
        
    def pause(self, seconds):
        """Pause execution while keeping the GUI event loop alive."""
        if HAS_PLOTTING:
            plt.pause(max(0.001, seconds))

    def show_final(self):
        """Blocking call to show final charts."""
        if HAS_PLOTTING:
            plt.ioff()
            plt.show()
