#pragma once

#include "external/il2cpp/il2cpp-api-types.h"
#include "external/il2cpp/il2cpp-object-internals.h"

namespace ta::adapters::unity
{

    template <typename TKey, typename TValue>
    struct dict : Il2CppObject
    {
        struct entry
        {
            int m_i_hash_code;
            int m_i_next;
            TKey m_t_key;
            TValue m_t_value;
        };

        Il2CppArray* m_p_buckets;
        Il2CppArray* m_p_entries;
        int m_i_count;
        int m_i_version;
        int m_i_free_list;
        int m_i_free_count;
        void* m_p_comparer;
        void* m_p_keys;
        void* m_p_values;

        entry* get_entry()
        {
            return reinterpret_cast<entry*>(&m_p_entries->data);
        }

        TKey get_key_by_index(int i_index)
        {
            TKey t_key = {0};

            entry* p_entry = get_entry();
            if (p_entry)
                t_key = p_entry[i_index].m_t_key;

            return t_key;
        }

        TValue get_value_by_index(int i_index)
        {
            TValue t_value = {0};

            entry* p_entry = get_entry();
            if (p_entry)
                t_value = p_entry[i_index].m_t_value;

            return t_value;
        }

        TValue get_value_by_key(TKey t_key)
        {
            TValue t_value = {0};
            for (int i = 0; i < m_i_count; i++)
            {
                if (get_entry()[i].m_t_key == t_key)
                    t_value = get_entry()[i].m_t_value;
            }
            return t_value;
        }
    };

    struct list : Il2CppObject
    {
        Il2CppArray* m_p_list_array;
        int m_i_size;
        int m_i_version;

    };

    template <typename T>
    struct hashset : Il2CppObject
    {
        struct slot
        {
            int m_i_hash_code;
            int m_i_next;
            T m_t_value;
        };

        Il2CppArray* m_p_buckets;
        Il2CppArray* m_p_slots;
        int m_i_count;
        int m_i_last_index;
        int m_i_free_list;
        void* m_p_comparer;
        int m_i_version;

        slot* get_slots()
        {
            return m_p_slots ? reinterpret_cast<slot*>(&m_p_slots->data) : nullptr;
        }
    };
}
