#include "gfx/mesh_gpu.h"

#include <vector>

namespace fn::gfx {

MeshGpu mesh_gpu_upload(const Mesh& mesh) {
    MeshGpu g{};
    if (mesh.positions.empty() || mesh.indices.empty()) return g;
    if (mesh.normals.size() != mesh.positions.size()) return g;

    const size_t nverts = mesh.positions.size() / 3;

    // Interleave pos.xyz + normal.xyz, stride 6 floats.
    std::vector<float> interleaved;
    interleaved.resize(nverts * 6);
    for (size_t i = 0; i < nverts; ++i) {
        interleaved[i*6 + 0] = mesh.positions[i*3 + 0];
        interleaved[i*6 + 1] = mesh.positions[i*3 + 1];
        interleaved[i*6 + 2] = mesh.positions[i*3 + 2];
        interleaved[i*6 + 3] = mesh.normals[i*3 + 0];
        interleaved[i*6 + 4] = mesh.normals[i*3 + 1];
        interleaved[i*6 + 5] = mesh.normals[i*3 + 2];
    }

    glGenVertexArrays(1, &g.vao);
    glGenBuffers(1, &g.vbo);
    glGenBuffers(1, &g.ebo);

    glBindVertexArray(g.vao);

    glBindBuffer(GL_ARRAY_BUFFER, g.vbo);
    glBufferData(GL_ARRAY_BUFFER,
                 (GLsizeiptr)(interleaved.size() * sizeof(float)),
                 interleaved.data(),
                 GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g.ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                 (GLsizeiptr)(mesh.indices.size() * sizeof(uint32_t)),
                 mesh.indices.data(),
                 GL_STATIC_DRAW);

    // location 0 = a_pos (vec3)
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
                          (GLsizei)(6 * sizeof(float)),
                          (const void*)0);
    // location 1 = a_normal (vec3)
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
                          (GLsizei)(6 * sizeof(float)),
                          (const void*)(3 * sizeof(float)));

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    g.index_count = (int)mesh.indices.size();
    return g;
}

void mesh_gpu_destroy(MeshGpu& g) {
    if (g.ebo) { glDeleteBuffers(1, &g.ebo); g.ebo = 0; }
    if (g.vbo) { glDeleteBuffers(1, &g.vbo); g.vbo = 0; }
    if (g.vao) { glDeleteVertexArrays(1, &g.vao); g.vao = 0; }
    g.index_count = 0;
}

} // namespace fn::gfx
