#ifndef RENDER_INCLUDED
#define RENDER_INCLUDED

#include <common/node.hpp>
#include <edit/editor.hpp>
#include <gfx/camera.hpp>
#include <gfx/light.hpp>
#include <gfx/material.hpp>
#include <gfx/mesh.hpp>
#include <gfx/shader.hpp>

#include <iostream>
#include <map>
#include <vector>

using mesh_ptr = std::shared_ptr<Mesh>;
using shader_ptr = std::shared_ptr<Shader>;
using light_ptr = std::shared_ptr<Light>;

struct CameraUBO
{
    glm::mat4 view;
    glm::mat4 projection;
    glm::vec4 position;
};

struct LightUBO {
    LightUBO(glm::vec4 _position, glm::vec4 _ambient_color, glm::vec4 _diffuse_color, glm::vec4 _specular_color, glm::vec4 _cone_direction)
    : position{_position}, ambient_color{_ambient_color}, diffuse_color{_diffuse_color}, specular_color{_specular_color}, cone_direction{_cone_direction} {}

    glm::vec4 position;
    glm::vec4 ambient_color;
    glm::vec4 diffuse_color;
    glm::vec4 specular_color;
    // If |cone_direction| = 0, then the light isn't considered a cone light
    glm::vec4 cone_direction;
};

struct OpenGLContext
{
    GLuint camera_buffer = 0;
    GLuint material_buffer = 0;
    GLuint lights_buffer = 0;
    GLsizeiptr lights_buffer_size = 1;

    GLuint skybox_texture;

    CameraUBO camera_ubo;
    std::vector<LightUBO> lights_ubos;

    mutable glm::mat4 model_mat_holder;

    bool opaque_render;

    OpenGLContext();
    ~OpenGLContext();
};

void gfx_draw(std::map<std::string, shader_ptr> &my_shaders, 
              std::vector<light_ptr> &lights,
              camera_ptr camera,
              node_ptr skybox,
              const std::vector<node_ptr> &scene,
              OpenGLContext &gfx_context);

#endif