//
// Created by sebastian on 07.02.26.
//

#include "OBJLoader.h"

#define TINYOBJLOADER_IMPLEMENTATION
#include <complex>

#include "tiny_obj_loader.h"

std::shared_ptr<TexturedModel> OBJLoader::loadModel(const std::string &modelPath, const std::string& texturePath, Loader &loader) {
    tinyobj::attrib_t attrib;
    std::vector<tinyobj::shape_t> shapes;
    std::vector<tinyobj::material_t> materials;
    std::string warn, err;
    if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, modelPath.c_str())) {
        throw std::runtime_error(warn + err);
    }

    if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, modelPath.c_str())) {
        throw std::runtime_error("Failed to load OBJ: " + warn + err);
    }

    std::vector<float> vertices;
    std::vector<float> normals;
    std::vector<float> uvs;
    std::vector<int> indices;

    int indexOffset = 0;
    for (const auto& shape : shapes) {
        for (const auto& index : shape.mesh.indices) {
            // Vertex-Position
            vertices.push_back(attrib.vertices[3*index.vertex_index + 0]);
            vertices.push_back(attrib.vertices[3*index.vertex_index + 1]);
            vertices.push_back(attrib.vertices[3*index.vertex_index + 2]);

            // UV-Koordinaten
            if (!attrib.texcoords.empty()) {
                uvs.push_back(attrib.texcoords[2*index.texcoord_index + 0]);
                uvs.push_back(attrib.texcoords[2*index.texcoord_index + 1]);
            } else {
                uvs.push_back(0.0f);
                uvs.push_back(0.0f);
            }

            normals.push_back(attrib.normals[3*index.normal_index + 0]);
            normals.push_back(attrib.normals[3*index.normal_index + 1]);
            normals.push_back(attrib.normals[3*index.normal_index + 2]);

            // Index
            indices.push_back(indexOffset);
            indexOffset++;
        }
    }

    RawModel rawModel = loader.loadToVAO(vertices, normals, uvs, indices);
    ModelTexture modelTexture = loader.loadTextureFromFile(texturePath);
    TexturedModel texturedModel = TexturedModel(std::make_shared<RawModel>(rawModel), std::make_shared<ModelTexture>(modelTexture));
    return std::make_shared<TexturedModel>(texturedModel);
}
