#pragma once

#include "ShaderPart.hpp"
#include <unordered_map>
#include <vector>
#include "Types.hpp"
#include "interfaces/IShader.hpp"
#include "elements/Transformable.hpp"
#include "TransformationStack.hpp"
#include "interfaces/IRenderer.hpp"

namespace TSE::OpenGL
{
    class Shader : public IShader
    {
    private:
        static uint activeProgramID;
        uint programID;
        mutable std::unordered_map<std::string, int> uniformLocations;

    protected:
        int PackageSize;
        virtual void OnEnable() const {};
        virtual void OnDisable() const {};
        virtual void OnFlush() {};
        virtual void OnDrawCall(int indexCount) {};
        virtual void OnPostDraw() {};
        virtual void OnSubmit(const Transformable& t, float*& target, TransformationStack& stack, void (*restartDrawcall)(IRenderer&), IRenderer& rnd) {};

    public:
        void Bind() const override;
        void Unbind() const override;
        void Enable(bool notify = false) const;
        void Disable(bool notify = false) const;
        void Flush();
        void DrawCall(int indexCount);
        void PostDraw();
        void Submit(const Transformable& t, float*& target, TransformationStack& stack, void (*restartDrawcall)(IRenderer&), IRenderer& rnd);
        bool IsEnabled() const;
        int packageSize();
        Shader(const std::vector<std::unique_ptr<ShaderPart>>& parts);
        virtual ~Shader();

    protected:
        int GetUniformLocation(const char* name);

    public:
        void SetUniform(const char* name, int value) override;
        void SetUniform(const char* name, const int* value, const int count) override;
        void SetUniform(const char* name, const Matrix4x4* value) override;
        void SetUniform(const char* name, float value) override;
        void SetUniform(const char* name, const float* value, const int count) override;
        void SetUniform(const char* name, const Vector2* value) override;
        void SetUniform(const char* name, const Vector3* value) override;
        void SetUniform(const char* name, const Vector4* value) override;
    };
} // namespace TSE::OpenGL
