#pragma once

#include "foundation/result.h"

#include <cstdint>
#include <span>
#include <string>
#include <string_view>
#include <vector>

namespace pp::foundation {

using TraceSpanId = std::uint64_t;

struct TraceSpanDesc {
    std::string_view component;
    std::string_view name;
    std::uint64_t thread_id = 0;
    std::uint64_t frame_id = 0;
    std::uint64_t stroke_id = 0;
};

struct TraceEvent {
    std::string component;
    std::string name;
    std::uint64_t thread_id = 0;
    std::uint64_t frame_id = 0;
    std::uint64_t stroke_id = 0;
    std::uint64_t start_us = 0;
    std::uint64_t duration_us = 0;
};

class TraceRecorder {
public:
    [[nodiscard]] Result<TraceSpanId> begin_span(TraceSpanDesc desc, std::uint64_t start_us);
    [[nodiscard]] Status end_span(TraceSpanId id, std::uint64_t end_us);

    [[nodiscard]] std::span<const TraceEvent> events() const noexcept;
    [[nodiscard]] std::size_t active_span_count() const noexcept;

    void clear() noexcept;

private:
    struct ActiveSpan {
        TraceSpanId id = 0;
        TraceSpanDesc desc;
        std::string component;
        std::string name;
        std::uint64_t start_us = 0;
        bool active = false;
    };

    [[nodiscard]] ActiveSpan* find_active_span(TraceSpanId id) noexcept;

    std::vector<ActiveSpan> active_spans_;
    std::vector<TraceEvent> events_;
    TraceSpanId next_id_ = 1;
};

}
