#ifndef PORYGONLANG_USERDATACOLLECTIONTYPE_HPP
#define PORYGONLANG_USERDATACOLLECTIONTYPE_HPP

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

namespace Porygon::UserData {
    class UserDataCollectionType : public ScriptType {
        shared_ptr<const ScriptType> _keyType;
        shared_ptr<const ScriptType> _valueType;
        const bool _indexable;
        const bool _iterable;
    public:
        UserDataCollectionType(shared_ptr<const ScriptType> keyType, shared_ptr<const ScriptType> valueType,
                               bool indexable, bool iterable)
                : ScriptType(TypeClass::Table),
                  _keyType(std::move(keyType)),
                  _valueType(std::move(valueType)),
                  _indexable(indexable),
                  _iterable(iterable)
        {}

        static shared_ptr<UserDataCollectionType> CreateIndexable(const shared_ptr<const ScriptType>& keyType, const shared_ptr<const ScriptType>& valueType){
            return make_shared<UserDataCollectionType>(keyType, valueType, true, true);
        }

        static UserDataCollectionType* CreateIndexable(const ScriptType* keyType, const ScriptType* valueType){
            return new UserDataCollectionType(shared_ptr<const ScriptType>(keyType),
                    shared_ptr<const ScriptType>(valueType), true, true);
        }

        static shared_ptr<UserDataCollectionType> CreateIterable(const shared_ptr<const ScriptType>& valueType){
            return make_shared<UserDataCollectionType>(nullptr, valueType, false, true);
        }

        static UserDataCollectionType * CreateIterable(const ScriptType* valueType){
            return new UserDataCollectionType(nullptr, shared_ptr<const ScriptType>(valueType),
                    false, true);
        }

        bool CanBeIndexedWith(const ScriptType* indexer) const final{
            if (!_indexable){
                return false;
            }
            return indexer->operator==(_keyType.get());
        }

        [[nodiscard]] shared_ptr<const ScriptType> GetIndexedType(const ScriptType* indexer) const final{
            return _valueType;
        }

        [[nodiscard]] bool CanBeIterated() const final{
            return _iterable;
        }

        [[nodiscard]] shared_ptr<const ScriptType> GetIteratorKeyType() const final{
            if (_indexable){
                return _keyType;
            } else{
                return _valueType;
            }
        }
    };
}

#endif //PORYGONLANG_USERDATACOLLECTIONTYPE_HPP
