
#pragma once

// Std. Includes
#include <vector>

// GL Includes
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "shader.hpp"
#include "texture.hpp"
#include "camera.hpp"

class Thing {
    public:
        Camera *camera;
        GLuint VBO;
        GLuint VAO;
        Shader *shader;
        Texture *texture;
        glm::vec3 position;
        glm::vec3 rotation;
        float rotation_angle;
        glm::vec3 scale;

        glm::vec3 lightning_position;
        glm::vec3 lightning_color;
        glm::vec3 cube_color;

        Thing(Camera *camera, GLuint VBO, Shader *shader, Texture *texture, glm::vec3 position) {
            this->camera = camera;
            this->VBO = VBO;   
            this->shader = shader;
            this->texture = texture;
            this->position = position;
            this->rotation = glm::vec3(1.0f, 1.0f, 1.0f);
            this->rotation_angle = 0.0f;
            this->scale = glm::vec3(1.0f, 1.0f, 1.0f);

            this->lightning_position = glm::vec3(1.0f, 1.0f, 1.0f);
            this->lightning_color = glm::vec3(1.0f, 1.0f, 1.0f);
            this->cube_color = glm::vec3(1.0f, 1.0f, 1.0f);

            init();
        }

        void set_light_position(glm::vec3 pos) {
            this->lightning_position = pos;
        }
        
        void set_light_color(glm::vec3 col) {
            this->lightning_color = col;
        }

        void set_cube_color(glm::vec3 col) {
            this->cube_color = col;
        }

        void set_position(glm::vec3 position) {
            this->position = position;
        }
        void modify_position(glm::vec3 position) {
            this->position += position;
        }

        void set_rotation(glm::vec3 rot, float rot_angle) {
            this->rotation = rot; 
            this->rotation_angle = rot_angle;
        }

        void set_scale(glm::vec3 sc) {
            this->scale = sc;
        }

        void render() {
            glm::mat4 view;
            glm::mat4 projection;
            glm::mat4 model;

            view = camera->GetViewMatrix();
            projection = glm::perspective(camera->Zoom, (float)1920/(float)1080, 0.1f, 1000.0f);
            model = glm::translate(model, this->position);
            model = glm::rotate(model, this->rotation_angle, this->rotation);
            model = glm::scale(model, this->scale);

            shader->use();

            glActiveTexture(GL_TEXTURE0);
            texture->bind();
            glUniform1i(glGetUniformLocation(shader->Program, "tex0"), 0);
            
            GLint light_color = glGetUniformLocation(shader->Program, "lightColor");
            glUniform3f(light_color, this->lightning_color.x, this->lightning_color.y, this->lightning_color.z);

            GLint light_pos = glGetUniformLocation(shader->Program, "lightPos");
            glUniform3f(light_pos, this->lightning_position.x, this->lightning_position.y, this->lightning_position.z);

            GLint view_pos = glGetUniformLocation(shader->Program, "viewPos");
            glUniform3f(view_pos, camera->Position.x, camera->Position.y, camera->Position.z);

            GLint modelLoc = glGetUniformLocation(shader->Program, "model");
            GLint viewLoc = glGetUniformLocation(shader->Program, "view");
            GLint projLoc = glGetUniformLocation(shader->Program, "projection");

            glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
            glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
            glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));

            glBindVertexArray(VAO);
            glDrawArrays(GL_TRIANGLES, 0, 36);
            glBindVertexArray(0); 

            texture->unbind();
        }

        int init() {
            glGenVertexArrays(1, &VAO);
            glBindVertexArray(VAO);

            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
            glEnableVertexAttribArray(0);

            glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
            glEnableVertexAttribArray(1);

            glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
            glEnableVertexAttribArray(2);

            glBindVertexArray(0); 

            return 0;
        }
    private:

};
