#pragma once

#include "uuid.h"
#include "interfaces/IShader.hpp"
#include <unordered_map>
#include <any>
#include <string>
#include <tuple>

namespace TSE
{
    struct Material
    {
        private:
            string name;
            uuids::uuid id;
            IShader* shader;

            std::unordered_map<string, std::tuple<std::any, string, string>> values;

        public:
            Material();
            Material(const string& name, IShader* shader);
            Material(const string& name, IShader* shader, uuids::uuid id);

            template<typename T>
            void SetValue(const string& key, const T& value);

            template<typename T>
            T GetValue(const string& key) const;

            template<typename T>
            void SetValue(const string& key, const T* value);

            bool HasValue(const string& key) const;
            int GetValueCount() const;

            std::tuple<std::any, string, string>& GetValueAt(int i);
            string& GetName();
            IShader* GetShader() const;
            void SetShader(IShader* shader);
            uuids::uuid GetID() const;
    };

    template<typename T>
    void Material::SetValue(const string& key, const T& value) {
        values[key] = std::make_tuple(value, typeid(T).name(), key);
    }

    template<typename T>
    T Material::GetValue(const string& key) const {
        auto it = values.find(key);
        if (it == values.end()) {
            throw std::runtime_error("Material::GetValue - key '" + key + "' not found");
        }
        auto [a,b,c] = it->second;
        return std::any_cast<T>(a);
    }

    template<typename T>
    void Material::SetValue(const string& key, const T* value) {
        values[key] = std::make_tuple(value, typeid(T).name(), key);
    }
    
} // namespace TSE
