#include "pxl8_mesh.h"
#include <stdlib.h>
#include <string.h>

pxl8_mesh* pxl8_mesh_create(u32 vertex_capacity, u32 index_capacity) {
    if (vertex_capacity > PXL8_MESH_MAX_VERTICES) vertex_capacity = PXL8_MESH_MAX_VERTICES;
    if (index_capacity > PXL8_MESH_MAX_INDICES) index_capacity = PXL8_MESH_MAX_INDICES;

    pxl8_mesh* mesh = calloc(1, sizeof(pxl8_mesh));
    if (!mesh) return NULL;

    mesh->vertices = calloc(vertex_capacity, sizeof(pxl8_vertex));
    mesh->indices = calloc(index_capacity, sizeof(u16));

    if (!mesh->vertices || !mesh->indices) {
        free(mesh->vertices);
        free(mesh->indices);
        free(mesh);
        return NULL;
    }

    mesh->vertex_capacity = vertex_capacity;
    mesh->index_capacity = index_capacity;
    mesh->vertex_count = 0;
    mesh->index_count = 0;

    return mesh;
}

void pxl8_mesh_destroy(pxl8_mesh* mesh) {
    if (!mesh) return;
    free(mesh->vertices);
    free(mesh->indices);
    free(mesh);
}

void pxl8_mesh_clear(pxl8_mesh* mesh) {
    if (!mesh) return;
    mesh->vertex_count = 0;
    mesh->index_count = 0;
}

u16 pxl8_mesh_push_vertex(pxl8_mesh* mesh, pxl8_vertex v) {
    if (!mesh || mesh->vertex_count >= mesh->vertex_capacity) return 0;
    u16 idx = (u16)mesh->vertex_count;
    mesh->vertices[mesh->vertex_count++] = v;
    return idx;
}

void pxl8_mesh_push_triangle(pxl8_mesh* mesh, u16 i0, u16 i1, u16 i2) {
    if (!mesh || mesh->index_count + 3 > mesh->index_capacity) return;
    mesh->indices[mesh->index_count++] = i0;
    mesh->indices[mesh->index_count++] = i1;
    mesh->indices[mesh->index_count++] = i2;
}

void pxl8_mesh_push_quad(pxl8_mesh* mesh, u16 i0, u16 i1, u16 i2, u16 i3) {
    pxl8_mesh_push_triangle(mesh, i0, i1, i2);
    pxl8_mesh_push_triangle(mesh, i0, i2, i3);
}

void pxl8_mesh_push_box(pxl8_mesh* mesh, pxl8_vec3 center, pxl8_vec3 half, u8 color) {
    pxl8_mesh_push_box_uv(mesh, center, half, color, 1.0f, 1.0f);
}

void pxl8_mesh_push_box_uv(pxl8_mesh* mesh, pxl8_vec3 center, pxl8_vec3 half, u8 color, f32 u_scale, f32 v_scale) {
    if (!mesh) return;

    pxl8_vec3 corners[8] = {
        {center.x - half.x, center.y - half.y, center.z - half.z},
        {center.x + half.x, center.y - half.y, center.z - half.z},
        {center.x + half.x, center.y + half.y, center.z - half.z},
        {center.x - half.x, center.y + half.y, center.z - half.z},
        {center.x - half.x, center.y - half.y, center.z + half.z},
        {center.x + half.x, center.y - half.y, center.z + half.z},
        {center.x + half.x, center.y + half.y, center.z + half.z},
        {center.x - half.x, center.y + half.y, center.z + half.z},
    };

    pxl8_vec3 normals[6] = {
        { 0,  0, -1}, // front
        { 0,  0,  1}, // back
        {-1,  0,  0}, // left
        { 1,  0,  0}, // right
        { 0, -1,  0}, // bottom
        { 0,  1,  0}, // top
    };

    i32 faces[6][4] = {
        {0, 1, 2, 3}, // front
        {5, 4, 7, 6}, // back
        {4, 0, 3, 7}, // left
        {1, 5, 6, 2}, // right
        {4, 5, 1, 0}, // bottom
        {3, 2, 6, 7}, // top
    };

    f32 uvs[4][2] = {
        {0, v_scale},
        {u_scale, v_scale},
        {u_scale, 0},
        {0, 0},
    };

    for (i32 face = 0; face < 6; face++) {
        u16 base = (u16)mesh->vertex_count;

        for (i32 v = 0; v < 4; v++) {
            pxl8_vertex vert = {
                .position = corners[faces[face][v]],
                .normal = normals[face],
                .u = uvs[v][0],
                .v = uvs[v][1],
                .color = color,
                .light = 255,
            };
            pxl8_mesh_push_vertex(mesh, vert);
        }

        pxl8_mesh_push_quad(mesh, base, base + 1, base + 2, base + 3);
    }
}
