#ifndef ITEM_CONTAINER_HPP_
#define ITEM_CONTAINER_HPP_

#include <ItemStore/ItemStore.hpp>
#include <functional>
#include <string>
#include <unordered_map>

/**
 * @brief A collection of named item stores.
 */
class ItemContainer final
{
public:
    using StackUpdatedCallback = std::function<void(const std::string &id, int slot, ItemStack &newStack)>;

private:
    std::unordered_map<std::string, ItemStore> stores;
    StackUpdatedCallback onStackUpdated = [](const std::string &id, int slot, ItemStack &newStack){};

public:
    using iterator = std::unordered_map<std::string, ItemStore>::iterator;
    using const_iterator = std::unordered_map<std::string, ItemStore>::const_iterator;

    template<typename... TArgs>
    ItemContainer& withStore(const std::string &id, TArgs&&... args)
    {
        stores.emplace(id, ItemStore(args...).withStackUpdatedCallback([this, id](int slot, ItemStack &stack)
        {
            onStackUpdated(id, slot, stack);
        }));

        return *this;
    }

    ItemContainer& withStackUpdatedCallback(const StackUpdatedCallback &callback);
    ItemStore& store(const std::string &id);

    iterator begin();
    iterator end();
    const_iterator cbegin() const;
    const_iterator cend() const;
    const_iterator begin() const;
    const_iterator end() const;

    friend struct SerialCodec<ItemContainer>;
};

template<>
struct SerialCodec<ItemContainer>
{
    static void encode(std::vector<uint8_t> &outBytes, const ItemContainer &obj);
    static size_t decode(const uint8_t *data, size_t size, ItemContainer &obj);
};

#endif