#ifndef prototype1_src_l2_alice_model_file_h
#define prototype1_src_l2_alice_model_file_h

#include "../../l1/system/fileio.h"
#include "assets.h"
#include "stdalign.h"

static_assert(sizeof(float) == 4, "...");
static_assert(sizeof(GenericMeshVertexInc) == 4 * (3 + 2), "...");
static_assert(alignof(GenericMeshVertexInc) == 4, "...");
static_assert(sizeof(ShinyMeshVertexInc) == 4 * (3), "...");
static_assert(alignof(ShinyMeshVertexInc) == 4, "...");

/* Yes, at this point I really started thinking that maybe I should have written Alice as a template */

/* Works only within one machine. todo: rewrite to use .obj after the session is over */
void alice_write_generic_mesh_to_file(GenericMeshTopology model, VecU8 file_path){
    U64 byte_size = sizeof(U64) * 2 +
        sizeof(GenericMeshVertexInc) * model.vertices.len + sizeof(U32) * model.indexes.len;
    VecU8 res = VecU8_new_zeroinit(byte_size);
    U8* buf = res.buf;
    *(U64*)buf = model.vertices.len;
    buf += sizeof(U64);
    *(U64*)buf = model.indexes.len;
    buf += sizeof(U64);
    memcpy(buf, model.vertices.buf, model.vertices.len * sizeof(GenericMeshVertexInc));
    buf += model.vertices.len * sizeof(GenericMeshVertexInc);
    memcpy(buf, model.indexes.buf, model.indexes.len * sizeof(U32));
    VecU8_append(&file_path, 0);
    write_whole_file_or_abort((const char*)file_path.buf, VecU8_to_span(&res));
    GenericMeshTopology_drop(model);
    VecU8_drop(file_path);
    VecU8_drop(res);
}

GenericMeshTopology alice_expect_read_generic_mesh_from_file(VecU8 file_path){
    VecU8 read = read_file_by_path(file_path);
    U8* buf = read.buf;
    U64 remaining = read.len;
    if (remaining < sizeof(U64) * 2) {
        abortf("Too short\n");
    }
    U64 vertices_len = *(U64*)buf;
    buf += sizeof(U64);
    U64 indexes_len = *(U64*)buf;
    buf += sizeof(U64);
    if (vertices_len > 1000000 || indexes_len > 1000000) {
        abortf("Model is too big\n");
    }
    remaining -= sizeof(U64) * 2;
    if (remaining != vertices_len * sizeof(GenericMeshVertexInc) + indexes_len * sizeof(U32)) {
        abortf("Incorrect file size\n");
    }
    VecGenericMeshVertexInc vertices = VecGenericMeshVertexInc_new_zeroinit(vertices_len);
    memcpy(vertices.buf, buf, vertices_len * sizeof(GenericMeshVertexInc));
    buf += vertices_len * sizeof(GenericMeshVertexInc);
    VecU32 indexes = VecU32_new_zeroinit(indexes_len);
    memcpy(indexes.buf, buf, indexes_len * sizeof(U32));
    return (GenericMeshTopology){.vertices = vertices, .indexes = indexes};
}

void alice_write_shiny_mesh_to_file(ShinyMeshTopology model, VecU8 file_path){
    U64 byte_size = sizeof(U64) * 2 +
        sizeof(ShinyMeshVertexInc) * model.vertices.len + sizeof(U32) * model.indexes.len;
    VecU8 res = VecU8_new_zeroinit(byte_size);
    U8* buf = res.buf;
    *(U64*)buf = model.vertices.len;
    buf += sizeof(U64);
    *(U64*)buf = model.indexes.len;
    buf += sizeof(U64);
    memcpy(buf, model.vertices.buf, model.vertices.len * sizeof(ShinyMeshVertexInc));
    buf += model.vertices.len * sizeof(ShinyMeshVertexInc);
    memcpy(buf, model.indexes.buf, model.indexes.len * sizeof(U32));
    VecU8_append(&file_path, 0);
    write_whole_file_or_abort((const char*)file_path.buf, VecU8_to_span(&res));
    ShinyMeshTopology_drop(model);
    VecU8_drop(file_path);
    VecU8_drop(res);
}

ShinyMeshTopology alice_expect_read_shiny_mesh_from_file(VecU8 file_path){
    VecU8 read = read_file_by_path(file_path);
    U8* buf = read.buf;
    U64 remaining = read.len;
    if (remaining < sizeof(U64) * 2) {
        abortf("Too short\n");
    }
    U64 vertices_len = *(U64*)buf;
    buf += sizeof(U64);
    U64 indexes_len = *(U64*)buf;
    buf += sizeof(U64);
    if (vertices_len > 10000 || indexes_len > 10000)
        abortf("Model is too big\n");
    remaining -= sizeof(U64) * 2;
    if (remaining != vertices_len * sizeof(ShinyMeshVertexInc) + indexes_len * sizeof(U32)) {
        abortf("Incorrect file size\n");
    }
    VecShinyMeshVertexInc vertices = VecShinyMeshVertexInc_new_zeroinit(vertices_len);
    memcpy(vertices.buf, buf, vertices_len * sizeof(ShinyMeshVertexInc));
    buf += vertices_len * sizeof(ShinyMeshVertexInc);
    VecU32 indexes = VecU32_new_zeroinit(indexes_len);
    memcpy(indexes.buf, buf, indexes_len * sizeof(U32));
    return (ShinyMeshTopology){.vertices = vertices, .indexes = indexes};
}

/* No beauty, just pure brute force */

#endif