#pragma once

#include <cstddef>
#include <cstdint>
#include <span>
#include <string>
#include <unordered_map>
#include <vector>

namespace radar::ipc {

struct Complex32 {
    float re = 0.0F;
    float im = 0.0F;
};

struct ComboKey {
    // Zero-based switch positions.
    std::uint32_t input_pos = 0;
    std::uint32_t output_pos = 0;

    [[nodiscard]] auto operator==(const ComboKey& other) const -> bool {
        return input_pos == other.input_pos && output_pos == other.output_pos;
    }
};

struct ComboKeyHash {
    [[nodiscard]] auto operator()(const ComboKey& key) const noexcept -> std::size_t {
        return (static_cast<std::size_t>(key.input_pos) << 32U) ^ static_cast<std::size_t>(key.output_pos);
    }
};

struct SweepTraceBlock {
    ComboKey combo{};
    // Frequency axis in Hz. Must have the same size as `s21`.
    std::vector<float> frequency_hz{};
    // Complex S21 samples for matching frequency points.
    std::vector<Complex32> s21{};
};

struct RawSweepCollection {
    std::uint64_t collection_id = 0;
    std::uint64_t monotonic_ns = 0;
    std::vector<SweepTraceBlock> traces{};
};

using PreprocessedCollection = RawSweepCollection;

enum class ResultKind : std::uint8_t {
    TraceComplex = 1,
    ScalarF32 = 2,
};

struct ResultPayload {
    std::string processing_name{};
    ResultKind kind = ResultKind::TraceComplex;
    // Valid for TraceComplex payloads.
    std::vector<float> frequency_hz{};
    // Valid for TraceComplex payloads.
    std::vector<Complex32> trace{};
    // Valid for ScalarF32 payloads.
    float scalar_value = 0.0F;
};

struct ResultBlock {
    ComboKey combo{};
    std::vector<ResultPayload> payloads{};
};

struct ResultCollection {
    std::uint64_t collection_id = 0;
    std::uint64_t monotonic_ns = 0;
    std::vector<ResultBlock> blocks{};
};

// Wire-format serialization helpers for IPC rings.
[[nodiscard]] auto serialize_raw_collection(const RawSweepCollection& collection) -> std::vector<std::uint8_t>;
[[nodiscard]] auto deserialize_raw_collection(std::span<const std::uint8_t> bytes) -> RawSweepCollection;

[[nodiscard]] auto serialize_preprocessed_collection(const PreprocessedCollection& collection)
    -> std::vector<std::uint8_t>;
[[nodiscard]] auto deserialize_preprocessed_collection(std::span<const std::uint8_t> bytes)
    -> PreprocessedCollection;

[[nodiscard]] auto serialize_result_collection(const ResultCollection& collection) -> std::vector<std::uint8_t>;
[[nodiscard]] auto deserialize_result_collection(std::span<const std::uint8_t> bytes) -> ResultCollection;

// Monotonic timestamp helper used for produced collections.
[[nodiscard]] auto current_monotonic_ns() -> std::uint64_t;

}  // namespace radar::ipc
