#pragma once

#include "vertex_engine/utils/utils.hpp" // IWYU pragma: keep

namespace VE
{
  class shader_program
  {
    public:
      shader_program();
      virtual ~shader_program();
      
    public:
      bool add_shader(GLuint type, const std::filesystem::path& p);
      void link();
      void use();
      GLuint get_id() const noexcept;

    public:
      void set(std::string location, glm::vec2 value);
      void set(std::string location, glm::vec3 value);
      void set(std::string location, glm::vec4 value);
      void set(std::string location, glm::mat3 value);
      void set(std::string location, glm::mat4 value);
      void set(std::string location, float value);
      void set(std::string location, int value);

    private:
      std::pair<bool, GLuint> create(GLuint type, const std::filesystem::path& p);
      bool errors(unsigned int shader, GLuint type);

    private:
      GLuint m_id;
      std::vector<GLuint> m_shaders; 
  };
}

namespace VE
{
  inline std::pair<bool, std::string> get_shader_content(std::filesystem::path p)
  {
    std::string contents;
    std::ifstream in(p, std::ios::binary);
    if (in)
    {
      in.seekg(0, std::ios::end);
      contents.resize(in.tellg());
      in.seekg(0, std::ios::beg);
      in.read(&contents[0], contents.size());
      in.close();
      return std::pair{ false, contents };
    }
    else return std::pair {true , ""};
  }

  template<typename T>
  std::string type_to_name(T type)
  {
    std::string name;
    switch (type) 
    {
      case GL_VERTEX_SHADER:
        name = "vertex shader";
        break;
      case GL_FRAGMENT_SHADER:
        name = "fragment shader";
        break;
    }

    return name;
  }
}
