#pragma once

#include <string>
#include <unordered_map>
#include <glm/glm.hpp>
#include <GL/glew.h>
#include <filesystem>
#include "systems/Profiler.h"

namespace OX
{
    class Shader
    {
    public:
        Shader() = default;

        Shader(const std::string &vertexPath, const std::string &fragmentPath);

        void SetName(const std::string &name) { m_name = name; };

        bool LoadFromFiles(const std::string &vertexPath, const std::string &fragmentPath);

        bool LoadFromSource(const std::string &vertexSrc, const std::string &fragmentSrc);

        void Reload();

        void Use() const;

        void CheckHotReload();

        GLuint GetID() const { return m_programID; }

        void SetInt(const std::string &name, int value);

        void SetFloat(const std::string &name, float value);

        void SetVec2(const std::string &name, const glm::vec2 &value);

        void SetVec3(const std::string &name, const glm::vec3 &value);

        void SetVec4(const std::string &name, const glm::vec4 &value);

        void SetMat4(const std::string &name, const glm::mat4 &value);

        void SetBool(const std::string &name, bool value);

    private:
        std::string m_name{"Default Shader"};
        GLuint m_programID = 0;
        std::string m_vertexPath;
        std::string m_fragmentPath;

        std::unordered_map<std::string, GLint> m_uniformCache;

        std::filesystem::file_time_type m_vertTimestamp;
        std::filesystem::file_time_type m_fragTimestamp;

        GLuint CompileShader(GLenum type, const std::string &source);

        std::string ReadFile(const std::string &path);

        GLint GetUniformLocation(const std::string &name);
    };
}
