#ifndef FREERTOS_INTEGRATION_MODEL_HPP
#define FREERTOS_INTEGRATION_MODEL_HPP

#include <cstddef>
#include <cstdint>
#include <type_traits>

namespace integration
{

enum class MessageKind : std::uint32_t
{
    sample = 1U,
    end = 2U
};

struct Sample
{
    std::uint32_t sequence;
    std::uint32_t value;
    MessageKind kind;
};

struct Report
{
    std::uint32_t sequence;
    std::uint32_t transformed;
    MessageKind kind;
};

enum class TraceStage : std::uint32_t
{
    inventory = 1U,
    barrier = 2U,
    isr_kick = 3U,
    producer_kick = 4U,
    reporter_resume = 5U,
    timer_callback = 6U,
    input_queued = 7U,
    input_dropped = 8U,
    report_created = 9U,
    report_received = 10U,
    end_marker = 11U,
    final_report = 12U
};

struct TraceEvent
{
    std::uint32_t sequence;
    std::uint32_t tick;
    TraceStage stage;
    std::uint32_t value;
};

[[nodiscard]] constexpr Report transform( Sample sample ) noexcept
{
    return { sample.sequence, sample.value * 2U, sample.kind };
}

[[nodiscard]] inline std::uint32_t trace_digest( const TraceEvent * events,
                                                 std::size_t count ) noexcept
{
    std::uint32_t hash = 2166136261U;
    for( std::size_t index = 0U; index < count; ++index )
    {
        hash = ( hash ^ events[ index ].sequence ) * 16777619U;
        hash = ( hash ^ events[ index ].tick ) * 16777619U;
        hash = ( hash ^ static_cast< std::uint32_t >( events[ index ].stage ) ) *
               16777619U;
        hash = ( hash ^ events[ index ].value ) * 16777619U;
    }
    return hash;
}

static_assert( std::is_trivially_copyable_v< Sample > );
static_assert( std::is_trivially_copyable_v< Report > );

} // namespace integration

#endif
