#pragma once

#include <frostbite2D/types/type_alias.h>
#include <frostbite2D/types/type_math.h>
#include <frostbite2D/base/RefObject.h>
#include <string>
#include <unordered_map>

namespace frostbite2D {

class Shader : public RefObject {
public:
  Shader() = default;
  ~Shader();
  
  void use();
  void unuse();
  
  bool isValid() const { return programID_ != 0; }
  uint32_t getID() const { return programID_; }
  const std::string& getName() const { return name_; }
  
  void setInt(const std::string& name, int value);
  void setFloat(const std::string& name, float value);
  void setVec2(const std::string& name, const Vec2& value);
  void setVec3(const std::string& name, const glm::vec3& value);
  void setVec4(const std::string& name, const glm::vec4& value);
  void setMat3(const std::string& name, const glm::mat3& value);
  void setMat4(const std::string& name, const glm::mat4& value);
  void setTexture(const std::string& name, int slot);
  
 private:
  Shader(const std::string& name, uint32_t programID);
  
  friend class ShaderManager;
  
  bool compile(uint32_t type, const std::string& source);
  bool link(uint32_t vertexID, uint32_t fragmentID);
  int getUniformLocation(const std::string& name);
  
  uint32_t programID_ = 0;
  std::string name_;
  std::unordered_map<std::string, int> uniformLocations_;
  
  Shader(const Shader&) = delete;
  Shader& operator=(const Shader&) = delete;
};

}