import random
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

# -------------------------------
# Prediction Algorithm
# -------------------------------
def predict_next(sequence):
    """
    Predicts the next number in a sequence of numbers using a simple linear regression.
    If there's only one number (or none), return the last value.
    
    Parameters:
      sequence (list of float): the list of historical numbers.
      
    Returns:
      float: the predicted next number.
    """
    # Not enough data to perform a regression — just return last value.
    if len(sequence) < 2:
        return sequence[-1] if sequence else 0
    
    # Create an array of indices corresponding to the sequence
    x_vals = np.arange(len(sequence))
    
    # Compute a linear fit (degree 1 polynomial: y = m*x + b)
    m, b = np.polyfit(x_vals, sequence, 1)
    
    # Predict at the next index (x = len(sequence))
    return m * len(sequence) + b

# -------------------------------
# Data and Parameters for Plotting
# -------------------------------
# Lists to store the actual random numbers and the predictions.
x_data = []         # x-axis indices
y_data = []         # actual random numbers
predictions = []    # predicted values

max_points = 10000     # maximum number of data points to show on the graph

# -------------------------------
# Set Up the Plot
# -------------------------------
fig, ax = plt.subplots()
line_actual, = ax.plot([], [], 'bo-', label="Actual Random Numbers")
line_pred, = ax.plot([], [], 'ro--', label="Predicted Next Number")

ax.set_xlim(0, max_points)
ax.set_ylim(0, 110)
ax.set_xlabel("Time (Index)")
ax.set_ylabel("Value")
ax.set_title("Sequence Prediction")
ax.legend(loc='upper left')

# -------------------------------
# Update Function for Animation
# -------------------------------
def update(frame):
    # Append next index.
    next_index = len(x_data)
    x_data.append(next_index)
    
    new_value = random.randint(0, 100)
    y_data.append(new_value)
    
    pred_value = predict_next(y_data)
    predictions.append(pred_value)
    
    if next_index > max_points:
        ax.set_xlim(next_index - max_points, next_index)
    
    line_actual.set_data(x_data, y_data)
    line_pred.set_data(x_data, predictions)
    
    return line_actual, line_pred

ani = animation.FuncAnimation(fig, update, interval=10, blit=True)

# -------------------------------
# Run the Plot
# -------------------------------
plt.show()