#include "presentation/pages/items/ItemCatalogModel.h"

#include <algorithm>
#include <iterator>
#include <utility>

#include "foundation/text/StringUtils.h"

namespace
{
    bool category_matches(const ta::features::items::contracts::ItemCategory category, const int filter)
    {
        using ta::features::items::contracts::ItemCategory;
        static constexpr ItemCategory categories[] = {
            ItemCategory::Weapon, ItemCategory::Ammo, ItemCategory::WeaponMod,
            ItemCategory::Equipment, ItemCategory::Medical, ItemCategory::Diet,
            ItemCategory::Key, ItemCategory::Container, ItemCategory::TradeGoods,
            ItemCategory::Other
        };
        if (filter <= 0)
            return true;
        const std::size_t index = static_cast<std::size_t>(filter - 1);
        return index < std::size(categories) && category == categories[index];
    }
}

namespace ta::presentation::pages::items
{
    void ItemCatalogModel::refresh(std::shared_ptr<const Snapshot> snapshot)
    {
        const std::string needle = ta::foundation::text::lower_copy(search_);
        if (filtered_catalog_ == snapshot &&
            filtered_needle_ == needle &&
            filtered_wishlist_only_ == wishlist_only_ &&
            filtered_category_ == category_filter_)
        {
            return;
        }

        filtered_catalog_ = std::move(snapshot);
        filtered_needle_ = needle;
        filtered_wishlist_only_ = wishlist_only_;
        filtered_category_ = category_filter_;
        visible_indices_.clear();
        wishlist_count_ = 0;

        if (!filtered_catalog_)
            return;

        visible_indices_.reserve(filtered_catalog_->items.size());
        for (std::size_t index = 0; index < filtered_catalog_->items.size(); ++index)
        {
            const Entry& item = filtered_catalog_->items[index];
            if (item.wishlisted)
                ++wishlist_count_;
            if ((!wishlist_only_ || item.wishlisted) &&
                category_matches(item.category, category_filter_) &&
                ta::features::items::contracts::matches_search(item, needle))
            {
                visible_indices_.push_back(index);
            }
        }
    }

    const ItemCatalogModel::Entry* ItemCatalogModel::find_by_id(
        const Snapshot& snapshot,
        const std::string& id) noexcept
    {
        const auto found = snapshot.index_by_id.find(id);
        if (found != snapshot.index_by_id.end() && found->second < snapshot.items.size())
            return &snapshot.items[found->second];

        return nullptr;
    }
}
