

#ifndef PORYGONLANG_USERDATASCRIPTTYPE_HPP
#define PORYGONLANG_USERDATASCRIPTTYPE_HPP

#include <utility>
#include "../ScriptTypes/ScriptType.hpp"
#include "UserData.hpp"
#include "UserDataStorage.hpp"

namespace Porygon::UserData {
    class UserDataScriptType : public ScriptType {
        UserData* _userData;
    public:
        explicit UserDataScriptType(uint32_t id) : ScriptType(TypeClass::UserData) {
            _userData = UserDataStorage::GetUserDataType(id);
        }

        explicit UserDataScriptType(UserData* ud) : ScriptType(TypeClass::UserData) {
            _userData = ud;
        }

        bool CanBeIndexedWith(const ScriptType *indexer) const final {
            if (indexer->GetClass() != TypeClass::String) {
                return false;
            }
            auto str = dynamic_cast<const StringScriptType*>(indexer);
            if (!str->IsKnownAtBind())
                return false;
            return _userData->ContainsField(str->GetHashValue());
        }

        [[nodiscard]] inline bool CanBeIndexedWithIdentifier(uint32_t hash) const final {
            return _userData -> ContainsField(hash);
        }

        [[nodiscard]] inline UserDataField *GetField(uint32_t id) const{
            return _userData->GetField(id);
        }

        shared_ptr<const ScriptType> GetIndexedType(const ScriptType *indexer) const final {
            auto stringKey = dynamic_cast<const StringScriptType*>(indexer);
            if (stringKey->IsKnownAtBind()) {
                return _userData->GetField(stringKey->GetHashValue())->GetType();
            }
            throw "TODO: indexing with dynamic keys";
        }

        [[nodiscard]] inline shared_ptr<const ScriptType> GetIndexedType(uint32_t hash) const final {
            return _userData->GetField(hash)->GetType();
        }
    };
}


#endif //PORYGONLANG_USERDATASCRIPTTYPE_HPP
