#include "Material.hpp"

#include <stdexcept>
#include "IdGenerator.hpp"
#include "interfaces/ITexture.hpp"
#include "Types.hpp"
#include "Vector2.hpp"
#include "Vector3.hpp"
#include "Vector4.hpp"
#include "Color.hpp"
#include "Matrix4x4.hpp"

namespace TSE
{
    Material::Material()
    : name(""), shader(nullptr)
    {
        id = GenerateRandomUUID();
    }
    Material::Material(const string& name, IShader* shader, uuids::uuid id)
    : name(name), shader(shader), id(id) {}

    Material::Material(const string &name, IShader *shader)
    : name(name), shader(shader)
    {
        id = GenerateRandomUUID();
    }
    bool Material::HasValue(const string &key) const
    {
        return values.find(key) != values.end();
    }
    int Material::GetValueCount() const
    {
        return values.size();
    }
    std::tuple<std::any, string, string> &Material::GetValueAt(int j)
    {
        auto it = values.begin();
        for (int i = 0; i < j; i++)
        {
            it++;
        }
        return it->second;
    }
    string &Material::GetName()
    {
        return name;
    }
    IShader *Material::GetShader() const
    {
        return shader;
    }
    void Material::SetShader(IShader *shader)
    {
        this->shader = shader;
    }
    uuids::uuid Material::GetID() const
    {
        return id;
    }

    template void Material::SetValue<int>(const string&, const int&);
    template void Material::SetValue<uint>(const string&, const uint&);
    template void Material::SetValue<float>(const string&, const float&);
    template void Material::SetValue<Vector2>(const string&, const Vector2&);
    template void Material::SetValue<Vector3>(const string&, const Vector3&);
    template void Material::SetValue<Vector4>(const string&, const Vector4&);
    template void Material::SetValue<Matrix4x4>(const string&, const Matrix4x4&);
    template void Material::SetValue<Color>(const string&, const Color&);
    template void Material::SetValue<string>(const string&, const string&);
    template void Material::SetValue<ITexture>(const string&, const ITexture*);

    template int Material::GetValue<int>(const string&) const;
    template uint Material::GetValue<uint>(const string&) const;
    template float Material::GetValue<float>(const string&) const;
    template Vector2 Material::GetValue<Vector2>(const string&) const;
    template Vector3 Material::GetValue<Vector3>(const string&) const;
    template Vector4 Material::GetValue<Vector4>(const string&) const;
    template Matrix4x4 Material::GetValue<Matrix4x4>(const string&) const;
    template Color Material::GetValue<Color>(const string&) const;
    template string Material::GetValue<string>(const string&) const;
    template ITexture* Material::GetValue<ITexture*>(const string&) const;
} // namespace TSE
