import numpy as np
import matplotlib.pyplot as plt

# -------------------------
# HDGL Superposition VM
# -------------------------
class HDGL_VM_32:
    def __init__(self, blend_factor=0.05):
        self.phi = 1.6180339887
        self.strands = ['A','B','C','D','E','F','G','H']
        self.D = np.zeros(32)  # 32 slots D1-D32
        self.omega = 0.0
        self.blend_factor = blend_factor
        self.ip = 0

        # Shared resonance mapping (example: D3,D7,D11,...)
        self.resonance_map = [2,6,10,14,18,22,26,30]

        # History for plotting
        self.history_D = []
        self.history_omega = []

        # Initialize filesystem and /bin
        self.fs = {}
        self.init_filesystem()
        self.init_bin()

        # Plotting setup
        self.fig, self.ax = plt.subplots(2,1, figsize=(12,6))
        self.lines_D = [self.ax[0].plot([],[],label=f"D{i+1}")[0] for i in range(32)]
        self.line_omega, = self.ax[1].plot([],[],label="Omega")
        self.ax[0].set_title("D1-D32 Registers"); self.ax[1].set_title("Omega")
        self.ax[0].set_xlabel("Step"); self.ax[1].set_xlabel("Step")
        self.ax[0].set_ylabel("Value"); self.ax[1].set_ylabel("Value")
        self.ax[0].legend(ncol=4, fontsize=8); self.ax[1].legend()
        plt.ion(); plt.show()

    # -------------------------
    # Step analog superposition
    # -------------------------
    def step(self):
        D_prev = self.D.copy()
        for i in range(32):
            res_val = np.sum([D_prev[r] for r in self.resonance_map if r != i])
            self.D[i] = np.tanh(D_prev[i] + self.blend_factor*(D_prev[i]*self.phi + res_val + self.omega))
        self.omega += 0.01 * self.blend_factor
        self.ip += 1
        # Store history
        self.history_D.append(self.D.copy())
        self.history_omega.append(self.omega)
        self.update_plot()

    # -------------------------
    # Run loop
    # -------------------------
    def run(self, steps=None):
        count = 0
        while steps is None or count < steps:
            self.step()
            count += 1

    # -------------------------
    # Numeric REPL
    # -------------------------
    def numeric_repl(self):
        self.print("HDGL VM 32-Slot Numeric REPL. Type 'help'.")
        while True:
            cmd = self.input("HDGL32-NUM> ").strip().split()
            if not cmd: continue
            instr = cmd[0].lower()
            if instr in ['quit','exit']: break
            elif instr=='help':
                self.print("step [n], run [n], add Dn Dm, mul Dn val, set Dn val, state, reset, fs <cmd>, bin <cmd>, help, exit")
            elif instr=='step': n=int(cmd[1]) if len(cmd)>1 else 1; [self.step() for _ in range(n)]; self.show_state()
            elif instr=='run': n=int(cmd[1]) if len(cmd)>1 else None; self.run(steps=n); self.show_state()
            elif instr=='add' and len(cmd)==3: i,j=self.parse_reg(cmd[1]),self.parse_reg(cmd[2]); self.D[i]=np.tanh(self.D[i]+self.D[j]); self.show_state()
            elif instr=='mul' and len(cmd)==3: i=self.parse_reg(cmd[1]); val=float(cmd[2]); self.D[i]=np.tanh(self.D[i]*val); self.show_state()
            elif instr=='set' and len(cmd)==3: i=self.parse_reg(cmd[1]); val=float(cmd[2]); self.D[i]=np.tanh(val); self.show_state()
            elif instr=='state': self.show_state()
            elif instr=='reset': self.__init__(blend_factor=self.blend_factor); self.print("VM reset.")
            elif instr[0:2]=='fs': self.fs_command(" ".join(cmd))
            elif instr=='bin' and len(cmd)>=2: self.bin_command(cmd[1:])
            else: self.print("Unknown instruction. Type 'help'.")

    # -------------------------
    # Register parser
    # -------------------------
    def parse_reg(self, reg_name):
        if reg_name.upper().startswith("D"):
            idx=int(reg_name[1:])-1
            if 0<=idx<32: return idx
        raise ValueError(f"Invalid register: {reg_name}")

    # -------------------------
    # Filesystem helpers
    # -------------------------
    def fs_command(self, cmd):
        parts=cmd.split()
        if len(parts)<2: return self.print("FS commands: ls, cat <file>, echo <file> 'text', rm <file>")
        fs_cmd=parts[1].lower()
        if fs_cmd=='ls': self.print(list(self.fs.keys()))
        elif fs_cmd=='cat' and len(parts)>=3: self.print(self.fs.get(parts[2],f"File '{parts[2]}' not found."))
        elif fs_cmd=='rm' and len(parts)>=3: self.print("Deleted "+parts[2] if self.fs.pop(parts[2],None) else f"File '{parts[2]}' not found.")
        elif fs_cmd=='echo' and len(parts)>=4: self.fs[parts[2]]=" ".join(parts[3:]); self.print(f"Written to {parts[2]}")
        else: self.print("Unknown FS command.")

    # -------------------------
    # /bin command helpers
    # -------------------------
    def init_bin(self):
        self.bin = {}

        # mkdir
        def mkdir(args):
            self.fs.setdefault(args[0], {})
            self.print(f"Directory '{args[0]}' created.")
        self.bin['mkdir'] = mkdir

        # rmdir
        def rmdir(args):
            if args[0] in self.fs and isinstance(self.fs[args[0]], dict) and not self.fs[args[0]]:
                self.fs.pop(args[0])
                self.print(f"Directory '{args[0]}' removed.")
            else:
                self.print(f"Cannot remove '{args[0]}'. Not empty or does not exist.")
        self.bin['rmdir'] = rmdir

        # echo
        def echo(args):
            if len(args) < 2:
                self.print("Usage: echo <file> <text>")
                return
            filename = args[0]
            text = " ".join(args[1:])
            self.fs[filename] = text
            self.print(f"Written to {filename}")
        self.bin['echo'] = echo

        # cat
        def cat(args):
            filename = args[0]
            self.print(self.fs.get(filename, f"File '{filename}' not found."))
        self.bin['cat'] = cat

        # ls
        def ls(args):
            self.print(list(self.fs.keys()))
        self.bin['ls'] = ls

        # run
        def run(args):
            cmd_name = args[0]
            cmd_args = args[1:]
            if cmd_name in self.bin:
                self.bin[cmd_name](cmd_args)
            else:
                self.print(f"Command '{cmd_name}' not found in /bin.")
        self.bin['run'] = run

    def bin_command(self, cmd_args):
        cmd_name = cmd_args[0]
        args = cmd_args[1:]
        if cmd_name in self.bin:
            self.bin[cmd_name](args)
        else:
            self.print(f"Unknown /bin command '{cmd_name}'")

    # -------------------------
    # Utility I/O & Plot
    # -------------------------
    def input(self, prompt=""): return input(prompt)
    def print(self, *args): print(*args)
    def show_state(self): self.print(f"D1-D32:{np.round(self.D,5)} Omega:{self.omega:.5f}")
    def update_plot(self):
        for i,line in enumerate(self.lines_D): line.set_data(range(len(self.history_D)), [h[i] for h in self.history_D])
        self.line_omega.set_data(range(len(self.history_omega)), self.history_omega)
        for ax in self.ax: ax.relim(); ax.autoscale_view()
        self.fig.canvas.draw(); self.fig.canvas.flush_events()

    # -------------------------
    # Filesystem init + bootloader
    # -------------------------
    def init_filesystem(self):
        self.fs['/boot']={
            'grub.cfg':{
                'menu':[
                    ("Standard Kernel", 0.1),
                    ("Fractal Kernel", 0.2)
                ]
            },
            'readme.txt':"Welcome to HDGL 32-Slot VM - Analog φ Lattice"
        }

# -------------------------
# Launch VM
# -------------------------
if __name__=="__main__":
    vm = HDGL_VM_32()
    vm.numeric_repl()
