#pragma once

#include <glad/gl.h>

#include <cstdint>
#include <filesystem>
#include <memory>
#include <string_view>

namespace kuiper
{

namespace gl
{

    enum class shader_type : std::uint8_t {
        none = 0,
        vertex,
        fragment,
        compute
    };

    class shader {
      public:
        using s_ptr = std::shared_ptr<shader>;

        explicit shader(GLuint id, GLenum type)
            : m_id(id), m_type(type) {}
        ~shader() {
            destroy();
        }

        shader(const shader& other)                = delete;
        shader& operator=(const shader& other)     = delete;
        shader(shader&& other) noexcept            = default;
        shader& operator=(shader&& other) noexcept = default;

        static s_ptr make(shader_type type) noexcept;
        static s_ptr from_path(const std::filesystem::path& shader_path, shader_type type = shader_type::none) noexcept;
        static s_ptr from_source(std::string_view source, shader_type type) noexcept;

      public:
        void   destroy() noexcept;
        void   attach_source(std::string_view source) noexcept;
        void   compile() noexcept;
        GLuint id() const noexcept {
            return m_id;
        }

      private:
        GLuint m_id {0};
        GLenum m_type {0};
    };

} // namespace gl

} // namespace kuiper
