#include <gearlib.h>
#include <stdlib.h>
#include <slibs.h>

BatchList batches = { 0 };

RenderBatch* create_batch(size_t vert_size, uint32_t max_verts) {
    RenderBatch* batch = calloc(sizeof(RenderBatch), 1);
    sl_vec_push(batches, batch);
    
    glCreateBuffers(1, &batch->vbo);
    glCreateVertexArrays(1, &batch->vao);

    batch->vertex_size = vert_size;
    batch->max_vertices = max_verts;
    batch->vertices = calloc(vert_size, max_verts);
    batch->vertex_ptr = batch->vertices;
    glNamedBufferStorage(batch->vbo, vert_size * max_verts, NULL, GL_DYNAMIC_STORAGE_BIT); 
    
    return batch;
}

void flush() {
    for(int i = 0; i < batches.size; i++) {
        RenderBatch* batch = batches.data[i];

        batch->stats.total_verts = 0;
        batch->stats.draw_calls = 0;

        flush_batch(batch); 
    }
}

void flush_batch(RenderBatch* batch) {
    batch->stats.total_verts += batch->vertex_count;
        
    glUseProgram(batch->shader);

    /*glUniformMatrix4fv(0, 1, GL_FALSE, 
            mat4ToFloat(mat4Multiply(batch->camera->view, batch->camera->projection)));*/


    //glUniformMatrix4fv(1, 1, GL_FALSE, mat4ToFloat(batch->camera->view));
    //glUniformMatrix4fv(2, 1, GL_FALSE, mat4ToFloat(batch->camera->projection));

    if(batch->flush_callback != NULL)
        batch->flush_callback(batch);
        
    glNamedBufferSubData(batch->vbo, 0, batch->vertex_size * batch->vertex_count, batch->vertices);
    renderer_draw(batch->vao, batch->vertex_count);
    batch->vertex_count = 0;
    batch->vertex_ptr = batch->vertices;

    glUseProgram(0);

    batch->stats.draw_calls++;
}

void batch_add_attrib(RenderBatch* batch, VertexAttrib attr) {
    sl_vec_push(batch->layout, attr);
}

void batch_bind_attribs(RenderBatch* batch) {
    size_t stride = 0;
    for(int i = 0; i < batch->layout.size; i++) {
        VertexAttrib attr = batch->layout.data[i];

        glEnableVertexArrayAttrib(batch->vao, i);
        glVertexArrayAttribFormat(batch->vao, i, attr.count, attr.type, GL_FALSE, stride);
        glVertexArrayAttribBinding(batch->vao, i, 0);

        stride += attr.size * attr.count;
    }

    glVertexArrayVertexBuffer(batch->vao, 0, batch->vbo, 0, stride); 
}

bool batch_needs_flush(RenderBatch* batch, uint32_t vertex_add) {
    return batch->vertex_size * (batch->vertex_count + vertex_add) >= batch->vertex_size * batch->max_vertices;
}
