import ast
import random
import string
import sys
import os
from dataclasses import dataclass
from typing import List, Optional

sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from transpiler.transformer import transform
from transpiler.generator import generate
from transpiler.flags import CompilerFlags

class CodeGenerator:
    def __init__(self):
        self.depth = 0
        self.max_depth = 4
        self.vars = ["x", "y", "z"]
        
    def gen_expr(self):
        choice = random.random()
        if choice < 0.3 or self.depth > self.max_depth:
            if random.random() < 0.5:
                return str(random.randint(0, 100))
            else:
                return random.choice(self.vars)
        
        self.depth += 1
        if choice < 0.5:
            op = random.choice(["+", "-", "*", "/", "%"])
            res = f"({self.gen_expr()} {op} {self.gen_expr()})"
        elif choice < 0.7:
            res = f"(-{self.gen_expr()})"
        else:
            res = f"func({self.gen_expr()})"
        self.depth -= 1
        return res

    def gen_stmt(self, indent=0):
        prefix = "    " * indent
        choice = random.random()
        
        if choice < 0.4:
            # Assignment
            v = random.choice(self.vars)
            return f"{prefix}{v} = {self.gen_expr()}"
        elif choice < 0.6:
            # If
            cond = self.gen_expr()
            body = "\n".join([self.gen_stmt(indent + 1) for _ in range(random.randint(1, 2))])
            return f"{prefix}if {cond}:\n{body}"
        elif choice < 0.8:
            # While/For
            v = random.choice(self.vars)
            body = []
            for _ in range(random.randint(1, 2)):
                if random.random() < 0.2:
                    body.append(f"{prefix}    break")
                elif random.random() < 0.2:
                    body.append(f"{prefix}    continue")
                else:
                    body.append(self.gen_stmt(indent + 1))
            body_str = "\n".join(body)
            return f"{prefix}for {v} in range(5):\n{body_str}"
        else:
            return f"{prefix}print({self.gen_expr()})"

    def gen_program(self, length=10):
        return "\n".join([self.gen_stmt() for _ in range(length)])

def run_fuzzer(iterations=1000):
    gen = CodeGenerator()
    pass_count = 0
    fail_count = 0
    
    print(f"Starting Stress Fuzzer ({iterations} iterations)...")
    
    for i in range(iterations):
        source = gen.gen_program(random.randint(5, 20))
        try:
            tree = ast.parse(source)
            ir = transform(tree)
            flags = CompilerFlags(no_runtime=True, fast=True)
            code = generate(ir, flags=flags).code
            pass_count += 1
            if i % 100 == 0:
                print(f"Iteration {i}: PASS")
        except Exception as e:
            fail_count += 1
            print(f"Iteration {i}: FAIL")
            print("SOURCE:\n", source)
            print("ERROR:", e)
            # break  # Stop on first crash for debugging
            
    print(f"\nFuzzing Results: {pass_count} passed, {fail_count} failed.")
    return fail_count == 0

if __name__ == "__main__":
    success = run_fuzzer(1000)
    sys.exit(0 if success else 1)
