#include "OBJLoader.h"
#include <fstream>
#include <sstream>
#include <iostream>
#include <algorithm>

bool OBJLoader::LoadOBJ(const std::string& filepath) {
    std::ifstream file(filepath);
    if (!file.is_open()) {
        std::cerr << "Failed to open OBJ file: " << filepath << std::endl;
        return false;
    }
    
    std::string line;
    while (std::getline(file, line)) {
        // Skip empty lines and comments
        if (line.empty() || line[0] == '#') {
            continue;
        }
        
        ProcessLine(line);
    }
    
    file.close();
    BuildVertexArray();
    return true;
}

void OBJLoader::ProcessLine(const std::string& line) {
    std::istringstream iss(line);
    std::string prefix;
    iss >> prefix;
    
    if (prefix == "v") {
        ProcessVertex(line);
    } else if (prefix == "vt") {
        ProcessTexCoord(line);
    } else if (prefix == "vn") {
        ProcessNormal(line);
    } else if (prefix == "f") {
        ProcessFace(line);
    } else if (prefix == "mtllib") {
        iss >> materialFile;
    }
}

void OBJLoader::ProcessVertex(const std::string& line) {
    std::istringstream iss(line);
    std::string prefix;
    glm::vec3 vertex;
    
    iss >> prefix >> vertex.x >> vertex.y >> vertex.z;
    temp_vertices.push_back(vertex);
}

void OBJLoader::ProcessTexCoord(const std::string& line) {
    std::istringstream iss(line);
    std::string prefix;
    glm::vec2 texCoord;
    
    iss >> prefix >> texCoord.x >> texCoord.y;
    temp_texCoords.push_back(texCoord);
}

void OBJLoader::ProcessNormal(const std::string& line) {
    std::istringstream iss(line);
    std::string prefix;
    glm::vec3 normal;
    
    iss >> prefix >> normal.x >> normal.y >> normal.z;
    temp_normals.push_back(normal);
}

void OBJLoader::ProcessFace(const std::string& line) {
    // Handle faces like: f 1/1/1 2/2/2 3/3/3 or f 1//1 2//2 3//3 or f 1 2 3
    std::istringstream iss(line);
    std::string prefix;
    iss >> prefix;
    
    OBJFace face;
    std::string vertex;
    int vertexCount = 0;
    
    while (iss >> vertex && vertexCount < 3) {
        std::replace(vertex.begin(), vertex.end(), '/', ' ');
        std::istringstream vertexStream(vertex);
        
        int vertexIndex = 0, texIndex = 0, normalIndex = 0;
        
        vertexStream >> vertexIndex;
        if (vertexStream >> texIndex) {
            if (vertexStream >> normalIndex) {
                // All three indices present
            }
        }
        
        // OBJ indices start at 1, convert to 0-based
        face.vertexIndices[vertexCount] = vertexIndex - 1;
        face.texCoordIndices[vertexCount] = texIndex > 0 ? texIndex - 1 : -1;
        face.normalIndices[vertexCount] = normalIndex > 0 ? normalIndex - 1 : -1;
        
        vertexCount++;
    }
    
    if (vertexCount == 3) {
        faces.push_back(face);
    }
}

void OBJLoader::BuildVertexArray() {
    vertices.clear();
    indices.clear();
    
    for (const auto& face : faces) {
        for (int i = 0; i < 3; ++i) {
            OBJVertex vertex;
            
            // Position
            if (face.vertexIndices[i] >= 0 && face.vertexIndices[i] < temp_vertices.size()) {
                vertex.position = temp_vertices[face.vertexIndices[i]];
            }
            
            // Texture coordinates
            if (face.texCoordIndices[i] >= 0 && face.texCoordIndices[i] < temp_texCoords.size()) {
                vertex.texCoord = temp_texCoords[face.texCoordIndices[i]];
            } else {
                vertex.texCoord = glm::vec2(0.0f);
            }
            
            // Normal
            if (face.normalIndices[i] >= 0 && face.normalIndices[i] < temp_normals.size()) {
                vertex.normal = temp_normals[face.normalIndices[i]];
            } else {
                vertex.normal = glm::vec3(0.0f, 1.0f, 0.0f); // Default up normal
            }
            
            // Default white color
            vertex.color = glm::vec3(1.0f);
            
            vertices.push_back(vertex);
            indices.push_back(static_cast<unsigned int>(vertices.size() - 1));
        }
    }
}
