import pyopencl as cl
import numpy as np

# -------------------------------
# Setup OpenCL Context
# -------------------------------
platforms = cl.get_platforms()
gpu_devices = platforms[0].get_devices(cl.device_type.GPU)
ctx = cl.Context(devices=gpu_devices)
queue = cl.CommandQueue(ctx)

# Lattice dimensions
D_TOTAL = 4096
lattice_host = np.zeros(D_TOTAL, dtype=np.float32)

# Slot mapping (simplified)
slots_control = np.arange(0, 8, dtype=np.int32)
slots_kernel = np.arange(32, 128, dtype=np.int32)
slots_user = np.arange(128, 1024, dtype=np.int32)
slots_workspace = np.arange(1024, 2048, dtype=np.int32)
slots_console = np.arange(24, 32, dtype=np.int32)

# OpenCL buffers
mf = cl.mem_flags
lattice_buf = cl.Buffer(ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, hostbuf=lattice_host)

# -------------------------------
# OpenCL Kernel
# -------------------------------
kernel_source = """
__kernel void lattice_evolve(__global float *lattice,
                             const int D_TOTAL,
                             __global const int *slots_control,
                             const int n_control,
                             __global const int *slots_workspace,
                             const int n_workspace,
                             const float phi) {
    int gid = get_global_id(0);
    
    // Wave interference for control slots
    if (gid < n_control) {
        int idx = slots_control[gid];
        int left = (idx == 0) ? idx : idx-1;
        int right = (idx == D_TOTAL-1) ? idx : idx+1;
        lattice[idx] += 0.5f * (lattice[left] - lattice[right]);
    }

    // Strand blending: control -> workspace
    if (gid < n_control && gid < n_workspace) {
        int c_idx = slots_control[gid];
        int w_idx = slots_workspace[gid];
        if (lattice[c_idx] > sqrt(phi)) {
            lattice[w_idx] += 1.0f;
        }
    }

    // Threshold projection for workspace
    if (gid < n_workspace) {
        int w_idx = slots_workspace[gid];
        lattice[w_idx] = (lattice[w_idx] >= sqrt(phi)) ? 1.0f : 0.0f;
    }
}

    // Threshold projection for workspace
    if (gid < n_workspace) {
        int w_idx = slots_workspace[gid];
        lattice[w_idx] = (lattice[w_idx] >= sqrt(phi)) ? 1.0f : 0.0f;
    }
}
"""

program = cl.Program(ctx, kernel_source).build()

# -------------------------------
# Prepare slot buffers
# -------------------------------
slots_control_buf = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=slots_control)
slots_workspace_buf = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=slots_workspace)

# -------------------------------
# Minimal snapshot injection
# -------------------------------
kernel_snapshot = np.random.rand(len(slots_kernel)).astype(np.float32)
user_snapshot = np.random.rand(len(slots_user)).astype(np.float32)
console_snapshot = np.zeros(len(slots_console), dtype=np.float32)

# Inject into lattice
cl.enqueue_copy(queue, lattice_buf, lattice_host)
lattice_host[slots_kernel] = kernel_snapshot
lattice_host[slots_user] = user_snapshot
lattice_host[slots_console] = console_snapshot
cl.enqueue_copy(queue, lattice_buf, lattice_host)

# -------------------------------
# Lattice Evolution Loop
# -------------------------------
EVOLUTION_TICKS = 1000
for tick in range(EVOLUTION_TICKS):
    program.lattice_evolve(
        queue, (len(slots_workspace),), None,
        lattice_buf,
        np.int32(D_TOTAL),
        slots_control_buf, np.int32(len(slots_control)),
        slots_workspace_buf, np.int32(len(slots_workspace)),
        np.float32(PHI)
    )

    # Optionally read back console every 100 ticks
    if tick % 100 == 0:
        cl.enqueue_copy(queue, lattice_host, lattice_buf)
        console_out = ''.join(['#' if lattice_host[i] > 0 else '.' for i in slots_console])
        print(f"[Tick {tick}] Console: {console_out}")

# -------------------------------
# Final lattice dump
# -------------------------------
cl.enqueue_copy(queue, lattice_host, lattice_buf)
print("HDGL-native Debian Bootstrap Complete (OpenCL)")
print("Control + first 16 workspace slots:")
print(lattice_host[:8+16])
