#pragma once

#include <cstddef>
#include <cstdint>
#include <random>
#include <string>
#include <type_traits>

#include <QPoint>
#include <QPointF>
#include <QVector2D>

// FNV-1a 64-bit accumulator used to fingerprint simulation state for
// determinism verification (see docs/replay_design.md "Determinism").
//
// Subsystems contribute their own state through appendChecksum(Hasher&) so the
// hash stays close to the data it covers and no state knowledge is duplicated.
// The accumulator is order-sensitive; callers fold state in a deterministic
// order (sorted containers, fixed view iteration).
class Hasher
{
public:
    // Folds raw bytes into the running hash.
    void appendBytes(const void* data, std::size_t byteCount);

    // Trivially-copyable scalars (ints, enums) are hashed by object representation.
    // Floating-point and Qt types have dedicated overloads below and bypass this.
    template <typename T>
    void append(const T& value)
    {
        static_assert(std::is_trivially_copyable<T>::value,
                      "Hasher::append requires a trivially copyable type "
                      "(add a dedicated overload otherwise)");
        appendBytes(&value, sizeof(T));
    }

    // Floats are hashed by bit pattern so equal values always hash equally;
    // negative zero is normalized so -0.0 and +0.0 collapse to one value.
    void append(float value);
    void append(double value);
    void append(const QPoint& point);
    void append(const QPointF& point);
    void append(const QVector2D& vector);
    void append(const std::string& text);

    std::uint64_t getValue() const { return m_state; }

private:
    std::uint64_t m_state = 14695981039346656037ull;  // FNV-1a 64-bit offset basis
};

// Folds the full mt19937 internal state into a 64-bit fingerprint. mt19937 has a
// portable, bit-identical text serialization, so this fingerprint is stable
// across platforms (see docs/replay_design.md "Cross-platform").
std::uint64_t fingerprintRng(const std::mt19937& rng);
