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

#include <algorithm>
#include <ranges>
#include <utility>

#include "adapters/eft/items/catalog/ItemTemplateClassifier.h"
#include "adapters/eft/localization/EftLocalizationService.h"
#include "foundation/text/StringUtils.h"

namespace ta::adapters::eft::items
{
    void CatalogIndexBuilder::reset(const std::size_t expected_count)
    {
        pending_.clear();
        entries_.clear();
        category_by_id_.clear();
        max_stack_by_id_.clear();
        seen_ids_.clear();
        pending_.reserve(expected_count);
        entries_.reserve(expected_count);
        category_by_id_.reserve(expected_count);
        max_stack_by_id_.reserve(expected_count);
        seen_ids_.reserve(expected_count);
    }

    void CatalogIndexBuilder::append(ItemTemplateRecord record)
    {
        if (!seen_ids_.insert(record.id).second)
            return;

        ta::features::items::contracts::ItemCatalogEntry entry;
        entry.id = record.id;
        entry.name = record.id;
        entry.category = record.category;
        entry.max_stack_size = record.max_stack_size;
        entry.search_text = ItemTemplateClassifier::search_text(entry, record.type_name);

        category_by_id_.emplace(record.id, record.category);
        max_stack_by_id_.emplace(record.id, record.max_stack_size);
        pending_.push_back({std::move(record.type_name)});
        entries_.push_back(std::move(entry));
    }

    bool CatalogIndexBuilder::localize_batch(std::size_t& index, const std::size_t batch_size)
    {
        const std::size_t end = (std::min)(entries_.size(), index + batch_size);
        for (; index < end; ++index)
        {
            auto& entry = entries_[index];
            std::string name = ta::adapters::eft::localization::EftLocalizationService::item_name(entry.id);
            std::string short_name = ta::adapters::eft::localization::EftLocalizationService::item_short_name(entry.id);
            if (!name.empty())
                entry.name = std::move(name);
            entry.short_name = std::move(short_name);
            entry.search_text = ItemTemplateClassifier::search_text(entry, pending_[index].type_name);
        }
        return index >= entries_.size();
    }

    void CatalogIndexBuilder::finalize()
    {
        std::ranges::sort(entries_, [](const auto& left, const auto& right)
        {
            const std::string left_name = ta::foundation::text::lower_copy(left.name);
            const std::string right_name = ta::foundation::text::lower_copy(right.name);
            return left_name == right_name ? left.id < right.id : left_name < right_name;
        });
        pending_.clear();
        pending_.shrink_to_fit();
        seen_ids_.clear();
        seen_ids_.rehash(0);
    }

    const std::vector<ta::features::items::contracts::ItemCatalogEntry>& CatalogIndexBuilder::entries() const noexcept
    {
        return entries_;
    }

    ta::features::items::contracts::ItemCategory CatalogIndexBuilder::category_for(const std::string_view id) const
    {
        const auto found = category_by_id_.find(std::string(id));
        return found == category_by_id_.end()
            ? ta::features::items::contracts::ItemCategory::Other
            : found->second;
    }

    int CatalogIndexBuilder::max_stack_for(const std::string_view id) const noexcept
    {
        const auto found = max_stack_by_id_.find(std::string(id));
        return found == max_stack_by_id_.end() ? 0 : found->second;
    }
}
