#ifndef QUEUE_H
#define QUEUE_H

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

//This was vibecoded #FML

typedef struct {
    void *data;
    size_t head;
    size_t tail;
    size_t count;
    size_t capacity;
    size_t stride;   // Size of one element
    bool is_dynamic;
} queue_t;

// Public API
void queue_init_static(queue_t *q, void *buffer, size_t capacity, size_t stride);
bool queue_init_dynamic(queue_t *q, size_t initial_capacity, size_t stride);
void queue_free(queue_t *q);

bool queue_push(queue_t *q, const void *val); // The "try_push" version
bool queue_pop(queue_t *q, void *out_val);
bool queue_peek(queue_t *q, void *out_val);

#define queue_is_empty(q) ((q)->count == 0)
#define queue_is_full(q)  ((q)->count == (q)->capacity)

#ifdef QUEUE_IMPLEMENTATION

void queue_init_static(queue_t *q, void *buffer, size_t capacity, size_t stride) {
    q->data = buffer;
    q->head = 0;
    q->tail = 0;
    q->count = 0;
    q->capacity = capacity;
    q->stride = stride;
    q->is_dynamic = false;
}

bool queue_init_dynamic(queue_t *q, size_t initial_capacity, size_t stride) {
    q->capacity = (initial_capacity > 0) ? initial_capacity : 8;
    q->stride = stride;
    q->data = malloc(q->capacity * q->stride);
    if (!q->data) return false;
    
    q->head = 0;
    q->tail = 0;
    q->count = 0;
    q->is_dynamic = true;
    return true;
}

void queue_free(queue_t *q) {
    if (q->is_dynamic && q->data) {
        free(q->data);
    }
    q->data = NULL;
}

static bool _queue_grow(queue_t *q) {
    size_t new_cap = q->capacity * 2;
    void *new_data = malloc(new_cap * q->stride);
    if (!new_data) return false;

    // Copy data in order: from head to end, then from beginning to tail
    for (size_t i = 0; i < q->count; ++i) {
        size_t old_idx = (q->head + i) % q->capacity;
        memcpy((char*)new_data + (i * q->stride), 
               (char*)q->data + (old_idx * q->stride), 
               q->stride);
    }

    if (q->is_dynamic) free(q->data);
    
    q->data = new_data;
    q->head = 0;
    q->tail = q->count;
    q->capacity = new_cap;
    q->is_dynamic = true; // Even if it was static, it's dynamic now
    return true;
}

bool queue_push(queue_t *q, const void *val) {
    if (queue_is_full(q)) {
        if (q->is_dynamic) {
            if (!_queue_grow(q)) return false;
        } else {
            return false; // Static queue full
        }
    }

    memcpy((char*)q->data + (q->tail * q->stride), val, q->stride);
    q->tail = (q->tail + 1) % q->capacity;
    q->count++;
    return true;
}

bool queue_pop(queue_t *q, void *out_val) {
    if (queue_is_empty(q)) return false;

    if (out_val) {
        memcpy(out_val, (char*)q->data + (q->head * q->stride), q->stride);
    }
    q->head = (q->head + 1) % q->capacity;
    q->count--;
    return true;
}

bool queue_peek(queue_t *q, void *out_val) {
    if (queue_is_empty(q)) return false;
    memcpy(out_val, (char*)q->data + (q->head * q->stride), q->stride);
    return true;
}

#endif // QUEUE_IMPLEMENTATION
#endif // QUEUE_H
