#include "VoxelGame.h"
#include <iostream>
#include <GL/glew.h>

// Include stb_image implementation (ensure stb_image.h is in your include path)
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

VoxelGame::VoxelGame()
    : textureGrass(0), textureDirt(0), textureWood(0)
{
    // Initialize a 16x16x16 voxel grid with zeros
    voxelData.resize(16, std::vector<std::vector<int>>(16, std::vector<int>(16, 0)));
}

VoxelGame::~VoxelGame() {
    glDeleteTextures(1, &textureGrass);
    glDeleteTextures(1, &textureDirt);
    glDeleteTextures(1, &textureWood);
}

bool VoxelGame::init() {
    if (!loadTextures())
        return false;
    generateVoxelData();
    generateMesh();
    return true;
}

bool VoxelGame::loadTextures() {
    int width, height, nrChannels;
    unsigned char *data;

    // Load grass texture
    data = stbi_load("grass.jpg", &width, &height, &nrChannels, 0);
    if (data) {
        glGenTextures(1, &textureGrass);
        glBindTexture(GL_TEXTURE_2D, textureGrass);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
                     nrChannels == 4 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
        stbi_image_free(data);
    } else {
        std::cerr << "Failed to load grass texture\n";
        return false;
    }

    // Load dirt texture
    data = stbi_load("dirt.jpg", &width, &height, &nrChannels, 0);
    if (data) {
        glGenTextures(1, &textureDirt);
        glBindTexture(GL_TEXTURE_2D, textureDirt);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
                     nrChannels == 4 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
        stbi_image_free(data);
    } else {
        std::cerr << "Failed to load dirt texture\n";
        return false;
    }

    // Load wood texture
    data = stbi_load("wood.png", &width, &height, &nrChannels, 0);
    if (data) {
        glGenTextures(1, &textureWood);
        glBindTexture(GL_TEXTURE_2D, textureWood);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
                     nrChannels == 4 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
        stbi_image_free(data);
    } else {
        std::cerr << "Failed to load wood texture\n";
        return false;
    }
    return true;
}

void VoxelGame::generateVoxelData() {
    // For demo purposes:
    // - Fill the bottom layer with grass (value 1)
    // - Fill the next layer with dirt (value 2)
    // - Add a couple of wood blocks (value 3)
    for (int x = 0; x < 16; ++x) {
        for (int z = 0; z < 16; ++z) {
            voxelData[x][0][z] = 1; // grass layer
            voxelData[x][1][z] = 2; // dirt layer
        }
    }
    // Add some wood blocks as an example
    voxelData[5][2][5] = 3;
    voxelData[6][2][5] = 3;
}

void VoxelGame::generateMesh() {
    // Use the GreedyMesher to create mesh quads from voxel data.
    meshQuads = GreedyMesher::mesh(voxelData);
}

void VoxelGame::update(float deltaTime) {
    // Update game logic (animations, input, physics, etc.)
    // (This is left minimal for demo purposes)
}

void VoxelGame::render() {
    // Here you would typically bind a shader, set uniforms, bind textures,
    // and render the mesh (e.g. drawing quads as two triangles each).
    // For this demo, we simply output the number of quads.
    std::cout << "Rendering " << meshQuads.size() << " quads." << std::endl;
    // You can extend this function to perform real OpenGL drawing.
}

void VoxelGame::debugUI() {
    
    ImGui::Begin("Debug");
    ImGui::Text("Voxel Game Debug Window");
    ImGui::Text("Mesh quads count: %d", (int)meshQuads.size());
    ImGui::End();
}
