#include "features/player/PlayerFeature.h"

#include <utility>

#include "foundation/diagnostics/ExecutionPath.h"

namespace ta::features::player
{
    void PlayerFeature::initialize()
    {
        settings_cache_.refresh(settings_);
    }

    void PlayerFeature::on_application_tick()
    {
        PlayerSettings next = settings_.read();
        if (input_.poll_speed_toggle(next.speed_hotkey))
        {
            settings_.set_speed_hack(!next.speed_hack);
            next = settings_.read();
        }
        if (input_.poll_fly_toggle(next.fly_hotkey))
        {
            settings_.set_fly_mode(!next.fly_mode);
            next = settings_.read();
        }

        settings_cache_.publish_if_changed(next);
    }

    void PlayerFeature::on_game_tick()
    {
        std::optional<PlayerCommand> command = commands_.consume();
        if (command)
        {
            diagnostics_.mark_action_consumed();
            ta::foundation::execution_path::step(command->trace_id, "PlayerFeature", "consume queued action", command->trace_action);
        }

        gateway_.game_tick(current_settings(), command);

        if (command)
            ta::foundation::execution_path::complete(command->trace_id, "PlayerFeature", "gateway call returned");
    }

    void PlayerFeature::reset_session() noexcept
    {
        if (auto command = commands_.consume())
            ta::foundation::execution_path::fail(command->trace_id, "PlayerFeature", "session reset before execution");
        diagnostics_.reset();
        input_.reset();
    }

    void PlayerFeature::submit(PlayerCommand command)
    {
        if (command.trace_action.empty())
            command.trace_action = "player command";
        if (command.trace_id == 0)
            command.trace_id = ta::foundation::execution_path::current_or_begin("Player", command.trace_action);

        diagnostics_.mark_action_requested();
        ta::foundation::execution_path::step(command.trace_id, "PlayerFeature", "queue action", command.trace_action);
        if (std::optional<PlayerCommand> replaced = commands_.submit(std::move(command)))
            ta::foundation::execution_path::fail(replaced->trace_id, "PlayerFeature", "superseded by a newer player action");
    }

    PlayerSettings PlayerFeature::current_settings() const
    {
        return settings_cache_.current_or_default();
    }
}
