import math
import matplotlib.pyplot as plt
import matplotlib.animation as animation

# --- HDGL Machine Definition ---
class HDGLMachine:
    def __init__(self):
        self.upper_field = {
            "prism_state": 105.0,
            "recursion_mode": 99.9999999999,
            "positive_infinite": 9.9999999999,
            "P3": 4.2360679775,
            "pi": 3.1415926535,
            "phi_power_phi": 2.6180339887,
            "phi": 1.6180339887
        }

        self.analog_dims = {
            "D8": 8.0, "D7": 7.0, "D6": 6.0,
            "D5": 5.0, "D4": 4.0, "D3": 3.0,
            "D2": 2.0, "D1": 1.0,
            "dim_switch": 1.0,
            "P4": 6.8541019662, "P5": 11.0901699437,
            "P6": 17.94427191, "P7": 29.0344465435
        }

        self.void = 0.0

        self.lower_field = {
            "negative_infinite": 0.0000000001,
            "inv_P7": 0.0344465435,
            "inv_P6": 0.05572809,
            "inv_P5": 0.0901699437,
            "inv_P4": 0.1458980338,
            "inv_P3": 0.2360679775,
            "inv_phi_power_phi": 0.3819660113,
            "inv_phi": 0.6180339887
        }

        self.current_state = self.void
        self.dimension = self.analog_dims["dim_switch"]
        self.recursion_active = False

    def toggle_recursion(self):
        self.recursion_active = not self.recursion_active
        print(f"Recursion mode: {'ON' if self.recursion_active else 'OFF'}")

    def toggle_dimension(self):
        self.dimension = 1.0 if self.dimension != 1.0 else 0.0
        print(f"Dimensionality: {'2D double-helix' if self.dimension == 1.0 else '1D'}")

    def compute_harmonic_state(self, t):
        state = self.void
        for value in self.upper_field.values():
            state += value * math.sin(t * self.upper_field["phi"])
        for value in self.lower_field.values():
            state += value * math.cos(t * self.lower_field["inv_phi"])
        for value in self.analog_dims.values():
            state += value * math.sin(t * self.upper_field["phi_power_phi"])

        if self.dimension == 1.0:  # 2D double-helix
            state *= math.sin(t * self.upper_field["pi"])
        else:  # 1D
            state *= math.cos(t * self.upper_field["pi"])
        return state

    def step(self, t):
        if self.recursion_active:
            self.current_state = self.compute_harmonic_state(t)
            self.current_state *= self.analog_dims["P7"] / self.lower_field["inv_P7"]
        else:
            self.current_state = self.compute_harmonic_state(t)
        return self.current_state


# --- Live Visualizer ---
class HDGLVisualizer:
    def __init__(self, machine, dt=0.05, window=200):
        self.machine = machine
        self.dt = dt
        self.t = 0.0
        self.window = window
        self.times = []
        self.values = []

        # Matplotlib setup
        self.fig, self.ax = plt.subplots(figsize=(10, 5))
        self.line, = self.ax.plot([], [], lw=2)
        self.ax.set_xlim(0, self.window * self.dt)
        self.ax.set_ylim(-500, 500)  # adjustable range
        self.ax.set_xlabel("Time")
        self.ax.set_ylabel("HDGL State")
        self.ax.set_title("HDGL Machine Live State")

        # Bind keypress handler
        self.fig.canvas.mpl_connect("key_press_event", self.on_key)

    def on_key(self, event):
        if event.key == "r":  # toggle recursion
            self.machine.toggle_recursion()
        elif event.key == "d":  # toggle dimension
            self.machine.toggle_dimension()
        elif event.key == "q":  # quit
            print("Exiting...")
            plt.close(self.fig)

    def update(self, frame):
        self.t += self.dt
        val = self.machine.step(self.t)
        self.times.append(self.t)
        self.values.append(val)

        # Keep sliding window
        if len(self.times) > self.window:
            self.times.pop(0)
            self.values.pop(0)

        self.line.set_data(self.times, self.values)
        self.ax.set_xlim(self.times[0], self.times[-1])
        return self.line,

    def run(self):
        ani = animation.FuncAnimation(
            self.fig, self.update, blit=True, interval=self.dt * 1000
        )
        plt.show()


# --- Run ---
if __name__ == "__main__":
    machine = HDGLMachine()
    vis = HDGLVisualizer(machine, dt=0.05, window=200)
    print("HDGL Live Visualizer Controls:")
    print("  r = toggle recursion")
    print("  d = toggle dimension")
    print("  q = quit")
    vis.run()
