#pragma once

#include "basic.h"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stb_image.h>
#include <glm/gtc/type_ptr.hpp>
#include "render_data.h"
#include "user_interface.h"
#include "camera.h"
#include "timer.h"


struct Frame_Buffer {
  u32 width = 640;
  u32 height = 480;
  u32 buffer = 0;
  u32 color_tex = 0;
  u32 depth_buffer = 0;
};

struct Vertex_Buffer {
  u32 vao = 0;
  u32 vbo = 0;
};

struct Uniform_Buffer {
  u32 ubo_buffer = 0;
};

struct Texture {
  u32 texture = 0;
  s32 width = 0;
  s32 height = 0;
  s32 number_of_channels = 0;
  string name;
};

struct Shader {
  u32 program = 0;
};

struct Renderer {
  Shader shader;
  Shader alt_shader;
  Frame_Buffer frame_buffer;
  Vertex_Buffer vertex_buffer;
  Uniform_Buffer uniform_buffer;
  Texture texture;
  Mesh mesh;
  Matrix4 view_matrix = Matrix4(1.0f);
  Matrix4 projection_matrix = Matrix4(1.0f);
  User_Interface user_interface;
  Render_Data render_data;
  Timer timer;
};


bool init_renderer(Renderer *renderer, u32 width, u32 height);
void set_renderer_size(Renderer *renderer, u32 width, u32 height);
void draw_renderer(Renderer *renderer);
void upload_renderer_data(Renderer *renderer, Mesh *vertex_data);
void cleanup_renderer(Renderer *renderer);

bool init_frame_buffer(Frame_Buffer *frame_buffer, u32 width, u32 height);
bool resize_frame_buffer(Frame_Buffer *frame_buffer, u32 width, u32 height);
bool check_frame_buffer_complete(Frame_Buffer *frame_buffer);
void bind_frame_buffer(Frame_Buffer *frame_buffer);
void unbind_frame_buffer(Frame_Buffer *frame_buffer);
void draw_frame_buffer(Frame_Buffer *frame_buffer);
void cleanup_frame_buffer(Frame_Buffer *frame_buffer);

bool init_vertex_buffer(Vertex_Buffer *vertex_buffer);
void cleanup_vertex_buffer(Vertex_Buffer *vertex_buffer);
void upload_vertex_buffer_data(Vertex_Buffer *vertex_buffer, Mesh *vertex_data);
void bind_vertex_buffer(Vertex_Buffer *vertex_buffer);
void unbind_vertex_buffer();
void draw_vertex_buffer(u32 mode, u32 start, u32 num);

bool init_uniform_buffer(Uniform_Buffer *uniform_buffer);
void upload_uniform_buffer_data(Uniform_Buffer *uniform_buffer, Matrix4 view_matrix, Matrix4 projection_matrix);
void cleanup(Uniform_Buffer *uniform_buffer);

bool load_texture(Texture *texture, string filepath);
void bind_texture(Texture *texture);
void unbind_texture();
void cleanup_texture(Texture *texture);

bool load_shaders(Shader *shader, string vertex_shader_filepath, string fragment_shader_filepath);
u32 load_shader(string filepath, u32 shader_type);
void use_shader(Shader *shader);
void cleanup_shader(Shader *shader);
