import sys
import time
import math
import threading
import numpy as np
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
import GPUtil

# -------------------------------
# Left Brain: Prime Recursion Solver
# -------------------------------
class PrimeSolver(threading.Thread):
    def __init__(self):
        super().__init__()
        self.daemon = True
        self.running = True
        self.ops_per_sec = 0
        self.primes_found = 0
        self.max_depth = 10000
        self.depth_mod = 1
        self.lock = threading.Lock()

    def run(self):
        while self.running:
            start = time.time()
            count = 0
            primes = 0
            limit = int(min(self.max_depth * self.depth_mod, 200000))

            for n in range(2, limit):
                if self.is_prime(n):
                    primes += 1
                count += 1
            # Instead of resetting primes, accumulate them:
 #           self.primes_found += primes
    

            # for n in range(2, limit):
            #     if self.is_prime(n):
            #         primes += 1
            #     count += 1
            elapsed = max(time.time() - start, 1e-6)
            with self.lock:
                self.ops_per_sec = int(count / elapsed)
                self.primes_found += primes
            time.sleep(0.1)

    def is_prime(self, n):
        if n < 2: return False
        if n % 2 == 0: return n == 2
        r = int(math.sqrt(n))
        for i in range(3, r+1, 2):
            if n % i == 0: return False
        return True

    def get_stats(self):
        with self.lock:
            return self.ops_per_sec, self.primes_found

# -------------------------------
# Right Brain: HDGL Lattice
# -------------------------------
window = None
lattice_width = 128
num_instances = 1000
num_instances_max = 6000000
glow_phase = 0.0
solver = PrimeSolver()

# Auto-tune parameters
target_util = 0.85
target_margin = 0.05
scale_step = 250

# Last GPU stats
gpu_util = 0.0
gpu_mem = "0/0 MB"
gpu_clock = 0.0

def init_gl():
    glClearColor(0.0, 0.0, 0.0, 1.0)
    glEnable(GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    glPointSize(2.0)

def draw_lattice():
    global glow_phase, num_instances, gpu_util, gpu_mem, gpu_clock
    glClear(GL_COLOR_BUFFER_BIT)
    glLoadIdentity()

    # CPU stats
    ops, primes = solver.get_stats()

    # Glow intensity from ops/sec
    glow_intensity = min(1.0, ops / 20000.0)
    glow_phase += 0.05
    glow = (math.sin(glow_phase) * 0.5 + 0.5) * glow_intensity

    # Depth mod from GPU saturation
    solver.depth_mod = 1 + num_instances / num_instances_max

    # Draw lattice
    glBegin(GL_POINTS)
    for i in range(num_instances):
        x = (i % lattice_width) / lattice_width * 2 - 1
        y = (i // lattice_width) / lattice_width * 2 - 1
        glColor4f(glow, glow * 0.8, glow * 0.4, 0.7)
        glVertex2f(x, y)
    glEnd()

    # GPU telemetry
    gpu = GPUtil.getGPUs()[0] if GPUtil.getGPUs() else None
    if gpu:
        gpu_util = gpu.load
        gpu_mem = f"{gpu.memoryUsed}/{gpu.memoryTotal} MB"
        gpu_clock = gpu.clock
        if gpu_util < target_util - target_margin:
            num_instances = min(num_instances + scale_step, num_instances_max)
        elif gpu_util > target_util + target_margin:
            num_instances = max(num_instances - scale_step, lattice_width**2)
    else:
        num_instances = min(num_instances + scale_step, num_instances_max)

    # Overlay HUD
    draw_hud(num_instances, ops, primes)

    glutSwapBuffers()

def draw_hud(instances, ops, primes):
    """Draw overlay text HUD with telemetry"""
    glMatrixMode(GL_PROJECTION)
    glPushMatrix()
    glLoadIdentity()
    gluOrtho2D(0, 800, 0, 800)
    glMatrixMode(GL_MODELVIEW)
    glPushMatrix()
    glLoadIdentity()

    glColor3f(0.2, 1.0, 0.2)
    lines = [
        f"[HDGL] Instances: {instances}",
        f"GPU Load: {gpu_util*100:.1f}%",
        f"Mem: {gpu_mem}",
        f"Clock: {gpu_clock:.2f} MHz",
        f"[GRA] Ops/sec: {ops}",
        f"Primes found: {primes}",
        f"Depth mod: {solver.depth_mod:.2f}"
    ]
    y = 770
    for line in lines:
        glRasterPos2f(10, y)
        for ch in line:
            glutBitmapCharacter(GLUT_BITMAP_9_BY_15, ord(ch))
        y -= 18

    glMatrixMode(GL_MODELVIEW)
    glPopMatrix()
    glMatrixMode(GL_PROJECTION)
    glPopMatrix()
    glMatrixMode(GL_MODELVIEW)

def update(value):
    glutPostRedisplay()
    glutTimerFunc(33, update, 0)

def main():
    global window
    solver.start()

    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE)
    glutInitWindowSize(800, 800)
    glutInitWindowPosition(0, 0)
    window = glutCreateWindow(b"HDGL + GRA Auto-Tune HUD")
    init_gl()
    glutDisplayFunc(draw_lattice)
    glutTimerFunc(0, update, 0)
    glutMainLoop()

if __name__ == "__main__":
    main()
