# uf/modes.py
import time
import random
import os
import math
import string

# -----------------------------
# UF Mode (User Friendly / 10S)
# -----------------------------
class UFMode:
    def __init__(self, variables):
        self.variables = variables

    def show_commands(self):
        print("\n=== UF Commands ===")
        print("hi -> prints hello world")
        print("hip -> prints hi")
        print("hih {text} -> prints your text")
        print("hid {text} {number} -> repeat text")
        print("set {name} {value} -> assign variable")
        print("get {name} -> get variable value")
        print("add {a} {b} -> addition")
        print("sub {a} {b} -> subtraction")
        print("mul {a} {b} -> multiplication")
        print("div {a} {b} -> division")
        print("rand {min} {max} -> random number")
        print("time -> current time")
        print("sleep {seconds} -> pause execution")
        print("upper {text} -> uppercase")
        print("lower {text} -> lowercase")
        print("len {text} -> length of text")
        print("rev {text} -> reverse text")
        print("clear -> clear screen")
        print("rndchar -> random letter")
        print("sqrt {number} -> square root")
        print("pow {a} {b} -> exponentiation")
        print("round {number} -> round number")
        print("repeatf {times} {text} -> repeat text")
        print("exit -> quit REPL")
        print("==================\n")

    def execute(self, tokens):
        if not tokens:
            return
        cmd = tokens[0].lower()

        try:
            if cmd == "hi":
                print("hello world")
            elif cmd == "hip":
                print("hi")
            elif cmd == "hih":
                print(" ".join(tokens[1:]))
            elif cmd == "hid":
                times = int(tokens[-1])
                text = " ".join(tokens[1:-1])
                for _ in range(times):
                    print(text)
            elif cmd == "set":
                self.variables[tokens[1]] = " ".join(tokens[2:])
                print(f"{tokens[1]} = {self.variables[tokens[1]]}")
            elif cmd == "get":
                print(self.variables.get(tokens[1], "Variable not found"))
            elif cmd == "add":
                print(float(tokens[1]) + float(tokens[2]))
            elif cmd == "sub":
                print(float(tokens[1]) - float(tokens[2]))
            elif cmd == "mul":
                print(float(tokens[1]) * float(tokens[2]))
            elif cmd == "div":
                print(float(tokens[1]) / float(tokens[2]))
            elif cmd == "rand":
                print(random.randint(int(tokens[1]), int(tokens[2])))
            elif cmd == "time":
                print(time.ctime())
            elif cmd == "sleep":
                time.sleep(float(tokens[1]))
            elif cmd == "upper":
                print(" ".join(tokens[1:]).upper())
            elif cmd == "lower":
                print(" ".join(tokens[1:]).lower())
            elif cmd == "len":
                print(len(" ".join(tokens[1:])))
            elif cmd == "rev":
                print(" ".join(tokens[1:])[::-1])
            elif cmd == "clear":
                os.system("cls" if os.name == "nt" else "clear")
            elif cmd == "rndchar":
                print(random.choice(string.ascii_letters))
            elif cmd == "sqrt":
                print(math.sqrt(float(tokens[1])))
            elif cmd == "pow":
                print(math.pow(float(tokens[1]), float(tokens[2])))
            elif cmd == "round":
                print(round(float(tokens[1])))
            elif cmd == "repeatf":
                times = int(tokens[1])
                text = " ".join(tokens[2:])
                for _ in range(times):
                    print(text)
            else:
                print("Unknown UF command.")
        except Exception as e:
            print(f"Error: {e}")


# -----------------------------
# iUF Mode (Intermediate / 7S)
# -----------------------------
class iUFMode(UFMode):
    def show_commands(self):
        print("\n=== iUF Commands ===")
        print("print {text}")
        print("repeat {number} {text}")
        print("set {name} {value}")
        print("get {name}")
        print("add/sub/mul/div {a} {b}")
        print("len {text}")
        print("clear")
        print("upper {text}")
        print("lower {text}")
        print("rand {min} {max}")
        print("time")
        print("rev {text}")
        print("sleep {seconds}")
        print("rndchar")
        print("sqrt {number}")
        print("pow {a} {b}")
        print("round {number}")
        print("repeatf {times} {text}")
        print("==================\n")

    def execute(self, tokens):
        # all commands same as UF but "print" instead of "hi"/"hih"
        if not tokens:
            return
        cmd = tokens[0].lower()
        try:
            if cmd == "print":
                print(" ".join(tokens[1:]))
            else:
                super().execute(tokens)
        except Exception as e:
            print(f"Error: {e}")


# -----------------------------
# nUF Mode (Advanced / 3.6S)
# -----------------------------
class nUFMode(UFMode):
    def show_commands(self):
        print("\n=== nUF Commands ===")
        print("var x = value")
        print("show")
        print("calc {expression}")
        print("echo {text}")
        print("> {text}")
        print("sqrt {number}")
        print("pow {base} {exp}")
        print("round {number}")
        print("len {text}")
        print("repeatf {times} {text}")
        print("upper {text}")
        print("lower {text}")
        print("rev {text}")
        print("rand {min} {max}")
        print("time")
        print("sleep {seconds}")
        print("sys {command}")
        print("exec {python_code}")
        print("rndchar")
        print("==================\n")

    def evaluate_expression(self, expr):
        for var in self.variables:
            expr = expr.replace(var, str(self.variables[var]))
        try:
            return eval(expr, {"__builtins__": None}, {"math": math})
        except:
            return None

    def execute(self, tokens):
        if not tokens:
            return
        cmd = tokens[0].lower()
        try:
            if cmd == "var":
                name = tokens[1]
                if tokens[2] != "=":
                    print("Syntax: var x = value")
                    return
                value = " ".join(tokens[3:])
                self.variables[name] = value
                print(f"{name} = {value}")
            elif cmd == "show":
                print(self.variables)
            elif cmd == "calc":
                expr = " ".join(tokens[1:])
                print(self.evaluate_expression(expr))
            elif cmd in ["echo", ">"]:
                print(" ".join(tokens[1:]))
            elif cmd == "sys":
                os.system(" ".join(tokens[1:]))
            elif cmd == "exec":
                exec(" ".join(tokens[1:]))
            else:
                super().execute(tokens)
        except Exception as e:
            print(f"Error: {e}")


# -----------------------------
# dnUF Mode (Expert / 1S)
# -----------------------------
class dnUFMode(nUFMode):
    def show_commands(self):
        print("\n=== dnUF Commands ===")
        print("let x = value")
        print("vars")
        print("echo {text} (supports $variables)")
        print("calc {expression}")
        print("if {condition} then {command}")
        print("sleep {seconds}")
        print("sys {command}")
        print("exec {python_code}")
        print("len {text}")
        print("read {filename}")
        print("upper {text}")
        print("lower {text}")
        print("rev {text}")
        print("rand {min} {max}")
        print("time")
        print("rndchar")
        print("==================\n")

    def execute(self, tokens):
        if not tokens:
            return
        cmd = tokens[0].lower()
        try:
            if cmd == "let":
                name = tokens[1]
                if tokens[2] != "=":
                    print("Syntax: let x = value")
                    return
                value = " ".join(tokens[3:])
                self.variables[name] = value
                print(f"[OK] {name} = {value}")
            elif cmd == "vars":
                print(self.variables)
            elif cmd == "read":
                filename = tokens[1]
                with open(filename, "r") as f:
                    print(f.read())
            elif cmd == "if":
                idx = tokens.index("then")
                condition = " ".join(tokens[1:idx])
                for var in self.variables:
                    condition = condition.replace(var, str(self.variables[var]))
                if eval(condition, {"__builtins__": None}, {}):
                    action = " ".join(tokens[idx + 1:])
                    if action.startswith("echo"):
                        print(" ".join(action.split()[1:]))
            else:
                super().execute(tokens)
        except Exception as e:
            print(f"Error: {e}")