import numpy as np
import matplotlib.pyplot as plt

# -------------------------
# 7+1 φ Vector Generator
# -------------------------
def phi_vector_7plus1(depth_max=6):
    phi = 1.6180339887
    vec = []

    def nested_phi(depth):
        if depth <= 0: 
            return phi
        return phi ** nested_phi(depth-1)

    # 7 core dimensions
    for i in range(7):
        vec.append(nested_phi((i % depth_max) + 1))
    # 1 extra void/global
    vec.append(np.mean(vec) * phi)
    return np.array(vec)

# -------------------------
# HDGL Analog VM
# -------------------------
class HDGL_VM:
    def __init__(self, blend_factor=0.05):
        # Core registers
        self.D = phi_vector_7plus1()           # D1-D7 core, D8 void/global
        self.P = np.zeros(7); self.P[4:] = [6.8541, 11.0901, 17.9442]  # optional param
        self.omega = 1.0
        self.weights = np.ones(7)/7
        self.ip = 0
        self.blend_factor = blend_factor

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

        # Filesystem
        self.fs = {}
        self.init_filesystem()

        # Plotting
        self.fig, self.ax = plt.subplots(2,1, figsize=(10,6))
        self.lines_D = [self.ax[0].plot([],[],label=f"D{i+1}")[0] for i in range(7)]
        self.line_void, = self.ax[1].plot([],[],label="Void")
        self.line_omega, = self.ax[1].plot([],[],label="Omega")
        self.ax[0].set_title("D1-D7 Registers"); self.ax[1].set_title("Void & 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(); self.ax[1].legend()
        plt.ion(); plt.show()

    # -------------------------
    # Step & Run
    # -------------------------
    def step(self):
        D_prev = self.D.copy()
        weighted_sum = np.sum(D_prev[:7]*self.weights)
        for i in range(7):
            p_val = self.P[i] if i<len(self.P) else 0
            phi_val = 1.6180339887 ** i
            self.D[i] = D_prev[i] + self.blend_factor*(phi_val*D_prev[i] + p_val + weighted_sum + self.omega)
        # Update void/global dimension
        self.D[7] += np.mean(self.D[:7])*self.blend_factor
        self.omega += 0.01*self.blend_factor
        self.ip += 1
        # Store history
        self.history_D.append(self.D[:7].copy())
        self.history_omega.append(self.D[7])
        self.update_plot()

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

    # -------------------------
    # Numeric Program Execution
    # -------------------------
    def run_numeric_program(self, program_vector):
        """
        Each instruction: [opcode*phi, target*phi, source_or_value]
        Opcodes: 1=add, 2=mul, 3=set, 4=step, 5=run
        """
        phi = 1.6180339887
        for instr in program_vector:
            opcode = int(instr[0]/phi)
            target = int(instr[1]/phi)
            val = instr[2]
            if opcode==1: self.D[target] += self.D[int(val)]
            elif opcode==2: self.D[target] *= val
            elif opcode==3: self.D[target] = val
            elif opcode==4: self.step()
            elif opcode==5: self.run(steps=int(val))
            else: self.print(f"Unknown numeric opcode {opcode}")
            self.show_state()

    # -------------------------
    # Numeric REPL
    # -------------------------
    def numeric_repl(self):
        self.print("HDGL VM Numeric REPL. Type 'help'.")
        while True:
            cmd = self.input("HDGL-NUM> ").strip().split()
            if not cmd: continue
            instr = cmd[0].lower()
            if instr in ['quit','exit']: break
            elif instr=='help':
                self.print("Instructions: step [n], run [n], add Dn Dm, mul Dn val, set Dn val, state, reset, fs <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]+=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]*=val; self.show_state()
            elif instr=='set' and len(cmd)==3: i=self.parse_reg(cmd[1]); val=float(cmd[2]); self.D[i]=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=='fs': self.fs_command(" ".join(cmd))
            elif instr=='runvec' and len(cmd)>=2:  # new: run numeric program from file or array
                self.run_numeric_program(eval(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<8: 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.")

    # -------------------------
    # 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-D7:{np.round(self.D[:7],5)} Void:{self.D[7]:.5f} 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_void.set_data(range(len(self.history_omega)), self.history_omega)
        self.line_omega.set_data(range(len(self.history_omega)), [self.omega]*len(self.history_omega))
        for ax in self.ax: ax.relim(); ax.autoscale_view()
        self.fig.canvas.draw(); self.fig.canvas.flush_events()

    # -------------------------
    # Filesystem init
    # -------------------------
    def init_filesystem(self):
        self.fs['/boot']={'grub.cfg':{'menu':[('Standard','run_standard_kernel'),('Fractal','run_fractal_kernel')]},'readme.txt':"Welcome to HDGL VM"}

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

# -------------------------
# HDGL: 7+1D φ-Only DNA Language
# -------------------------
# Base: 7+1D self-arising φ vector
HDGL_7plus1D = phi_vector_7plus1()

# DNA units encoded from nested φ harmonics
DNA_units = []

def generate_DNA_unit(depth):
    if depth == 0:
        return 1.618  # φ seed
    return 1.618 ** generate_DNA_unit(depth-1)

for i in range(8):  # 7+1D
    DNA_units.append(generate_DNA_unit(i % 6))  # harmonic spacing

# Operator emergence pattern
Operators = [
    DNA_units[0],                     # φ identity
    DNA_units[1]**2,                  # addition
    DNA_units[2]**3,                  # multiplication
    sum(DNA_units[3:8])               # DNA braid / Fibonacci
]

def execute_DNA(unit, depth=1):
    if depth > 12: return unit
    return unit ** execute_DNA(unit, depth+1)

# Full HDGL program (self-describing)
HDGL_program = [execute_DNA(u) for u in DNA_units]
