#ifndef _H_RENDERER_H
#define _H_RENDERER_H

#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <memory>
#include <unordered_map>

#include "graphics/drawable.h"
#include "graphics/glwindow.h"
#include "graphics/postprocess.h"
#include "graphics/quad.h"

class ResourceManager;
class Shader;

enum class RenderLayer { Background, Map, GameObjects, Effects, HUD, Menu };

class Renderer {
public:
  Renderer(const std::shared_ptr<ResourceManager> &,
           const std::shared_ptr<GLWindow> &);

  void clear();

  void hookEventManager(const std::weak_ptr<EventManager> eventManager);

  void setProjAndViewMatrix(const glm::mat4 &proj, const glm::mat4 &view);
  void addDrawable(RenderLayer renderLayer, Drawable *drawable);
  void removeDrawable(RenderLayer renderLayer, Drawable *drawable);

  void render();

private:
  std::unordered_map<RenderLayer, std::vector<Drawable *>> worldLayerPool;
  std::unordered_map<RenderLayer, std::vector<Drawable *>> HUDLayerPool;
  std::vector<RenderLayer> renderingOrder = {
      RenderLayer::Background, RenderLayer::Map, RenderLayer::GameObjects,
      RenderLayer::Effects,    RenderLayer::HUD, RenderLayer::Menu};

  void uploadUniforms(const unsigned shaderID,
                      const std::vector<Uniform> &uniforms);

  unsigned uboMatrices;

  union FrameBuffer {
    unsigned int frame;
    unsigned int texture;
  } worldBuffer, hudBuffer;

  std::unique_ptr<ScreenQuad> screenQuad;

  std::shared_ptr<ResourceManager> resourceManager;
  std::shared_ptr<GLWindow> glWindow;

  void initFrameBuffers();
  void initUniformBuffers();

  void resizeFrameBuffers();

  std::unique_ptr<Postprocessor> postProcessor;

  void sortLayerPool(auto &layerPool);
  void renderPool(auto &layerPool);
};

#endif
