import tkinter as tk
from tkinter import ttk
import math
import matplotlib
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt

matplotlib.use("TkAgg")

# ----------------- HDGL Machine -----------------
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

    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:
            state *= math.sin(t * self.upper_field["pi"])
        else:
            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

# ----------------- GUI -----------------
class HDGLCalculatorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("HDGL Machine + Calculator")

        self.machine = HDGLMachine()
        self.expression = ""

        # Display
        self.display = tk.Entry(root, font=("Consolas", 18), bd=5, relief="sunken", justify="right")
        self.display.pack(fill="x", padx=10, pady=5)

        # Calculator buttons
        btns_frame = ttk.Frame(root)
        btns_frame.pack(padx=10, pady=5)

        buttons = [
            "7", "8", "9", "/",
            "4", "5", "6", "*",
            "1", "2", "3", "-",
            "0", ".", "=", "+"
        ]
        for i, text in enumerate(buttons):
            b = ttk.Button(btns_frame, text=text, command=lambda t=text: self.on_button(t))
            b.grid(row=i // 4, column=i % 4, sticky="nsew", padx=2, pady=2)

        for i in range(4):
            btns_frame.columnconfigure(i, weight=1)
        for i in range(4):
            btns_frame.rowconfigure(i, weight=1)

        # Control buttons
        ctrl_frame = ttk.Frame(root)
        ctrl_frame.pack(padx=10, pady=5, fill="x")
        ttk.Button(ctrl_frame, text="C", command=self.clear).pack(side="left", expand=True, fill="x")
        ttk.Button(ctrl_frame, text="Recursion", command=self.toggle_recursion).pack(side="left", expand=True, fill="x")

        # Waveform Plot
        self.fig, self.ax = plt.subplots(figsize=(6, 3))
        self.canvas = FigureCanvasTkAgg(self.fig, master=root)
        self.canvas.get_tk_widget().pack(fill="both", expand=True)
        self.line, = self.ax.plot([], [], lw=2)
        self.ax.set_xlim(0, 10)
        self.ax.set_ylim(-500, 500)
        self.t_vals = np.linspace(0, 10, 500)
        self.update_plot()

    def on_button(self, char):
        if char == "=":
            try:
                result = eval(self.expression)
                self.display.delete(0, tk.END)
                self.display.insert(0, str(result))
                self.expression = str(result)
            except Exception:
                self.display.delete(0, tk.END)
                self.display.insert(0, "Error")
                self.expression = ""
        else:
            self.expression += str(char)
            self.display.delete(0, tk.END)
            self.display.insert(0, self.expression)

    def clear(self):
        self.expression = ""
        self.display.delete(0, tk.END)

    def toggle_recursion(self):
        self.machine.toggle_recursion()

    def update_plot(self):
        y_vals = [self.machine.step(t) for t in self.t_vals]
        self.line.set_data(self.t_vals, y_vals)
        self.ax.set_ylim(min(y_vals) - 10, max(y_vals) + 10)
        self.canvas.draw()
        self.root.after(200, self.update_plot)

# ----------------- Run -----------------
if __name__ == "__main__":
    root = tk.Tk()
    app = HDGLCalculatorApp(root)
    root.mainloop()
