#ifndef SHADER_INCLUDED
#define SHADER_INCLUDED

#include <osi/opengl.hpp>
#include <utils/math.hpp>

#include <string>
#include <iostream>
#include <filesystem>

// NOTE: code is largely from https://github.com/JoeyDeVries/LearnOpenGL
// for now I decided not to apply naming_conventions here.

/* Enum value decides the order in which shader programs are used to render the scene */
enum shader_type { skybox, basic, lit, interface};

class Shader
{
    //private
    unsigned int ID;
    shader_type type;
    // utility function for checking shader compilation/linking errors.
    // ------------------------------------------------------------------------
    void checkCompileErrors(unsigned int shader, std::string const& type);

public:
    //constructor
    Shader(std::filesystem::path const& vertexPath, std::filesystem::path const& fragmentPath, shader_type _type);

    //shader activation
    void use() const;

    // utility uniform functions
    void setBool(const GLint location, bool value) const;
    void setInt(const GLint location, int value) const;
    void setFloat(const GLint location, float value) const;
    void setVec3(const GLint location, const glm::vec3 &value) const;
    void setVec4(const GLint location, const glm::vec4 &value) const;
    void setMat4(const GLint location, const glm::mat4 &value) const;
    void setUBO(const GLint binding, GLuint buffer) const;
    void setSSBO(const GLint binding, GLuint buffer) const;
    void setTU(const GLint binding, GLuint texture) const;

    const unsigned int getID() const {return ID;} // Why do we need to expose ID???
    const shader_type getType() const { return type; }

    ~Shader();
};


#endif