#include "ReplayPlayer.h"

#include <utility>

#include "Command.h"
#include "Simulation.h"

ReplayPlayer::ReplayPlayer(Simulation& simulation, std::vector<ReplayEntry> entries)
    : m_simulation(simulation)
    , m_entries(std::move(entries))
{
}

void ReplayPlayer::start()
{
    processEntriesAt(0);
}

void ReplayPlayer::advanceTo(Tick tick)
{
    processEntriesAt(tick);
}

bool ReplayPlayer::isFinished() const
{
    return m_desyncTick.has_value() || m_cursor >= m_entries.size();
}

std::optional<Tick> ReplayPlayer::getDesyncTick() const
{
    return m_desyncTick;
}

void ReplayPlayer::processEntriesAt(Tick tick)
{
    // Consume entries for this tick in file order. The recording writes, at a
    // given tick: the periodic checksum (if any) first, then command lines each
    // followed by their post-apply checksum — so applying/verifying in file order
    // reproduces the original sequence exactly.
    while (!m_desyncTick.has_value()
           && m_cursor < m_entries.size()
           && m_entries[m_cursor].tick == tick)
    {
        const ReplayEntry& entry = m_entries[m_cursor];
        ++m_cursor;

        if (entry.isCommand)
        {
            m_simulation.apply(*entry.command);
        }
        else if (m_simulation.getRngFingerprint() != entry.fingerprint)
        {
            m_desyncTick = tick;
        }
    }
}
