#ifndef OCTREE_H
#define OCTREE_H

#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

//This was vibecoded #FML

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    float x, y, z;
} oct_vec3;

typedef struct {
    oct_vec3 min;
    oct_vec3 max;
} oct_box;

typedef struct {
    uint32_t first_child; // Index of first child in the pool, 0 if leaf
    uint16_t count;       // Number of items in this node
    uint16_t data_offset; // Index into the data array
} oct_node;

typedef struct {
    oct_node* nodes;
    uint32_t* data;       // Indices of your objects
    uint32_t node_count;
    uint32_t node_capacity;
    uint32_t data_count;
    uint32_t data_capacity;
    oct_box  bounds;
    int      max_depth;
} octree_t;

// --- Public API ---
void octree_init(octree_t* tree, oct_box bounds, int max_depth, uint32_t initial_cap);
void octree_free(octree_t* tree);
bool octree_insert(octree_t* tree, uint32_t item_id, oct_vec3 pos);
// Note: For thread safety, wrap insert in a mutex. Query can be lock-free if no inserts happen.

#ifdef __cplusplus
}
#endif
#endif // OCTREE_H

// --------------------------------------------------------------------------
#ifdef OCTREE_IMPLEMENTATION

static bool oct_box_contains(oct_box b, oct_vec3 p) {
    return (p.x >= b.min.x && p.x <= b.max.x &&
            p.y >= b.min.y && p.y <= b.max.y &&
            p.z >= b.min.z && p.z <= b.max.z);
}

void octree_init(octree_t* tree, oct_box bounds, int max_depth, uint32_t initial_cap) {
    tree->bounds = bounds;
    tree->max_depth = max_depth;
    tree->node_capacity = initial_cap;
    tree->nodes = (oct_node*)calloc(initial_cap, sizeof(oct_node));
    tree->node_count = 1; // Root is at index 0
    
    tree->data_capacity = initial_cap * 4;
    tree->data = (uint32_t*)malloc(tree->data_capacity * sizeof(uint32_t));
    tree->data_count = 0;
}

void octree_free(octree_t* tree) {
    free(tree->nodes);
    free(tree->data);
}

// Internal: Splits a node into 8 children
static void oct_node_split(octree_t* tree, uint32_t node_idx, oct_box node_box) {
    if (tree->node_count + 8 > tree->node_capacity) {
        tree->node_capacity *= 2;
        tree->nodes = (oct_node*)realloc(tree->nodes, tree->node_capacity * sizeof(oct_node));
    }

    tree->nodes[node_idx].first_child = tree->node_count;
    tree->node_count += 8;
    
    // Initialize children...
    for(int i = 0; i < 8; ++i) {
        tree->nodes[tree->nodes[node_idx].first_child + i] = (oct_node){0};
    }
}

// Implementation of octree_insert would go here...
// It would traverse indices and check oct_box_contains.

// Internal helper to get the bounding box of a specific child
static oct_box oct_get_child_box(oct_box parent, int child_idx) {
    oct_vec3 center = {
        (parent.min.x + parent.max.x) * 0.5f,
        (parent.min.y + parent.max.y) * 0.5f,
        (parent.min.z + parent.max.z) * 0.5f
    };
    oct_box child = parent;
    // Bit 0: X, Bit 1: Y, Bit 2: Z
    if (child_idx & 1) child.min.x = center.x; else child.max.x = center.x;
    if (child_idx & 2) child.min.y = center.y; else child.max.y = center.y;
    if (child_idx & 4) child.min.z = center.z; else child.max.z = center.z;
    return child;
}

// Recursive insert (Internal)
static bool oct_insert_internal(octree_t* tree, uint32_t node_idx, oct_box node_box, uint32_t item_id, oct_vec3 pos, int depth) {
    // 1. If we are at max depth or it's a leaf with space, store it
    // For simplicity, this version pushes everything to leaves:
    if (depth >= tree->max_depth) {
        // Handle data array resizing
        if (tree->data_count >= tree->data_capacity) {
            tree->data_capacity *= 2;
            tree->data = (uint32_t*)realloc(tree->data, tree->data_capacity * sizeof(uint32_t));
        }
        
        // In a real STB-style, you'd link data to the node here
        // For now, we'll just track that the node has data
        tree->nodes[node_idx].count++;
        tree->data[tree->data_count++] = item_id;
        return true;
    }

    // 2. If leaf, split it
    if (tree->nodes[node_idx].first_child == 0) {
        oct_node_split(tree, node_idx, node_box);
    }

    // 3. Determine which child the point belongs to
    oct_vec3 center = {
        (node_box.min.x + node_box.max.x) * 0.5f,
        (node_box.min.y + node_box.max.y) * 0.5f,
        (node_box.min.z + node_box.max.z) * 0.5f
    };

    int child_idx = 0;
    if (pos.x >= center.x) child_idx |= 1;
    if (pos.y >= center.y) child_idx |= 2;
    if (pos.z >= center.z) child_idx |= 4;

    uint32_t next_node = tree->nodes[node_idx].first_child + child_idx;
    oct_box next_box = oct_get_child_box(node_box, child_idx);
    
    return oct_insert_internal(tree, next_node, next_box, item_id, pos, depth + 1);
}

bool octree_insert(octree_t* tree, uint32_t item_id, oct_vec3 pos) {
    if (!oct_box_contains(tree->bounds, pos)) return false;
    return oct_insert_internal(tree, 0, tree->bounds, item_id, pos, 0);
}

// Thread-safe query (No writes/allocations)
void octree_query_sphere(const octree_t* tree, oct_vec3 center, float radius, void (*callback)(uint32_t)) {
    // This would implement a standard stack-based or recursive search
    // checking if the sphere overlaps the node_box.
}

#endif // OCTREE_IMPLEMENTATION
