#include "adapters/eft/items/catalog/ItemTemplateReader.h"



#include "adapters/eft/common/EftMongoId.h"
#include "adapters/eft/items/catalog/ItemTemplateClassifier.h"
#include "adapters/il2cpp/Il2CppCollections.h"
#include "adapters/il2cpp/ManagedRuntime.h"
#include "adapters/unity/bindings/UnityTypes.h"
#include "foundation/diagnostics/OnceLogger.h"

namespace
{
    constexpr int kMaxTemplateCount = 20000;
    using TemplateDictionary = ta::adapters::unity::dict<
        ta::adapters::eft::common::EftMongoId,
        Il2CppObject*>;
}

namespace ta::adapters::eft::items
{
    bool ItemTemplateReader::begin(Il2CppObject* factory)
    {
        reset();
        const auto templates = ta::adapters::il2cpp::ManagedRuntime::read_field<Il2CppObject*>(
            factory, "ItemTemplates");
        if (!templates || !templates.value())
        {
            ta::foundation::diagnostics::OnceLogger::warn(
                "ITEM", "item-templates-field", "ItemFactory.ItemTemplates is unavailable");
            return false;
        }

        auto* dictionary = reinterpret_cast<TemplateDictionary*>(templates.value());
        if (!dictionary->m_p_entries || dictionary->m_i_count <= 0 ||
            dictionary->m_i_count > kMaxTemplateCount ||
            static_cast<std::size_t>(dictionary->m_i_count) > dictionary->m_p_entries->max_length)
        {
            ta::foundation::diagnostics::OnceLogger::warn(
                "ITEM", "item-templates-dictionary", "ItemTemplates dictionary failed validation");
            return false;
        }

        templates_object_ = templates.value();
        count_ = static_cast<std::size_t>(dictionary->m_i_count);
        return true;
    }

    void ItemTemplateReader::reset() noexcept
    {
        templates_object_ = nullptr;
        count_ = 0;
    }

    std::size_t ItemTemplateReader::count() const noexcept
    {
        return count_;
    }

    std::optional<ItemTemplateRecord> ItemTemplateReader::read(const std::size_t index) const
    {
        auto* dictionary = reinterpret_cast<TemplateDictionary*>(templates_object_);
        if (!dictionary || !dictionary->m_p_entries || index >= count_)
            return std::nullopt;

        const auto& entry = dictionary->get_entry()[index];
        if (entry.m_i_hash_code < 0 || !entry.m_t_value || !entry.m_t_value->klass)
            return std::nullopt;

        const std::string id = ta::adapters::eft::common::mongo_id_string(entry.m_t_key);
        if (!ta::features::items::contracts::looks_like_template_id(id))
            return std::nullopt;

        const auto node_type = ta::adapters::il2cpp::ManagedRuntime::invoke<int>(
            entry.m_t_value, "get__type", ta::adapters::il2cpp::LookupPolicy::IncludeBaseClasses);
        if (!node_type || node_type.value() != 0)
            return std::nullopt;

        const auto max_stack = ta::adapters::il2cpp::ManagedRuntime::read_field<int>(
            entry.m_t_value, "StackMaxSize");
        if (!max_stack)
            return std::nullopt;

        ItemTemplateRecord result;
        result.id = id;
        result.type_name = ItemTemplateClassifier::type_name(entry.m_t_value->klass);
        result.category = ItemTemplateClassifier::classify(entry.m_t_value->klass);
        result.max_stack_size = max_stack.value() > 0 && max_stack.value() < 1000000
            ? max_stack.value()
            : 1;
        return result;
    }
}
