#include "features/items/ItemFeature.h"

#include <string>

#include "foundation/diagnostics/ExecutionPath.h"

namespace ta::features::items
{
    void ItemFeature::initialize()
    {
        settings_cache_.refresh(settings_);
    }

    void ItemFeature::on_application_tick()
    {
        const ta::features::items::contracts::ItemSettings next = settings_.read();
        settings_cache_.publish_if_changed(next);
        gateway_.application_tick(next);
    }

    void ItemFeature::on_game_tick()
    {
        std::optional<ta::features::items::contracts::ItemActionCommand> action = action_commands_.consume();
        if (action)
            diagnostics_.mark_action_consumed();
        gateway_.game_tick(current_settings(), drain_selector_commands(), std::move(action));
    }

    void ItemFeature::reset_session() noexcept
    {
        if (auto action = action_commands_.consume())
            ta::foundation::execution_path::fail(action->trace_id, "ItemFeature", "session reset before execution");
        while (selector_commands_.try_pop()) {}
        diagnostics_.reset();
        gateway_.reset_session();
    }

    std::shared_ptr<const ta::features::items::contracts::ItemCatalogSnapshot> ItemFeature::catalog() const noexcept
    {
        return gateway_.catalog();
    }

    bool ItemFeature::in_raid() const noexcept
    {
        return gateway_.in_raid();
    }

    std::uint64_t ItemFeature::navigation_revision() const noexcept
    {
        return navigation_revision_.load(std::memory_order_acquire);
    }

    void ItemFeature::open_selector()
    {
        navigation_revision_.fetch_add(1, std::memory_order_release);
        submit_selector({ta::features::items::contracts::ItemSelectorCommandType::SetActive, true, 0});
    }

    void ItemFeature::set_selector_active(const bool active)
    {
        submit_selector({ta::features::items::contracts::ItemSelectorCommandType::SetActive, active, 0});
    }

    void ItemFeature::submit_selector(ta::features::items::contracts::ItemSelectorCommand command)
    {
        selector_commands_.push(std::move(command));
    }

    void ItemFeature::request_action(ta::features::items::contracts::ItemActionCommand command)
    {
        if (command.trace_id == 0)
            command.trace_id = ta::foundation::execution_path::current_or_begin(
                "Items", std::string(ta::features::items::contracts::to_string(command.action)));
        diagnostics_.mark_action_requested();
        ta::foundation::execution_path::step(command.trace_id, "ItemFeature", "queue item action",
                                      std::string(ta::features::items::contracts::to_string(command.action)));
        if (auto replaced = action_commands_.submit(std::move(command)))
            ta::foundation::execution_path::fail(replaced->trace_id, "ItemFeature", "superseded by a newer item action");
    }

    ta::features::items::contracts::ItemSettings ItemFeature::current_settings() const
    {
        return settings_cache_.current_or_default();
    }

    std::vector<ta::features::items::contracts::ItemSelectorCommand> ItemFeature::drain_selector_commands()
    {
        std::vector<ta::features::items::contracts::ItemSelectorCommand> commands;
        while (auto command = selector_commands_.try_pop())
            commands.push_back(std::move(*command));
        return commands;
    }
}
