#pragma once
#include <atomic>
#include <cstdint>
#include <memory>
#include <mutex>
#include <vector>
#include "renderive/frame_control/Frame_Control.hpp"
#include "renderive/real_time_data/Real_Time_Data.hpp"
struct Low_Latency_Test_Frame {
    int value{};
};
struct Low_Latency_Test_Time_Source {
    std::shared_ptr<std::atomic<std::uint64_t>> time_ns{std::make_shared<std::atomic<std::uint64_t>>(100)};
    std::uint64_t now_ns() const noexcept {
        return time_ns->load(std::memory_order_relaxed);
    }
    void advance_ns(std::uint64_t duration_ns) const noexcept {
        time_ns->fetch_add(duration_ns, std::memory_order_relaxed);
    }
    void set_ns(std::uint64_t value_ns) const noexcept {
        time_ns->store(value_ns, std::memory_order_relaxed);
    }
};
struct Low_Latency_Recorded_Observation {
    int event{};
    std::uint64_t sequence{};
    std::uint64_t frame_render_count{};
    std::uint64_t real_time_data_update_sequence{};
    std::uint64_t paint_duration_ns{};
    std::uint64_t render_duration_ns{};
    std::uint64_t ready_wait_ns{};
    std::uint64_t frame_age_at_render_ns{};
    std::uint64_t end_to_end_ns{};
    std::uint64_t published_frame_count{};
    std::uint64_t render_pass_count{};
    std::uint64_t abandoned_frame_count{};
    std::uint64_t manually_discarded_frame_count{};
    std::uint64_t swap_failure_count{};
    double frequency_hz{};
    int limit_state{};
    std::uint64_t target_interval_ns{};
    std::uint64_t bottleneck_duration_ns{};
    std::uint64_t consumer_interval_ns{};
    std::uint64_t next_refresh_interval_ns{};
    std::uint64_t completed_lifecycle_count{};
};
struct Low_Latency_Observer_Data {
    std::mutex mutex;
    std::vector<Low_Latency_Recorded_Observation> observations;
};
struct Low_Latency_Test_Observer {
    static constexpr bool enabled = true;
    std::shared_ptr<Low_Latency_Observer_Data> data{std::make_shared<Low_Latency_Observer_Data>()};
    template <class Observation>
    void observe(const Observation& observation) noexcept {
        const auto& statistics = observation.statistics;
        const auto& counters = statistics.counters;
        std::lock_guard lock(data->mutex);
        data->observations.push_back({
            static_cast<int>(observation.event),
            statistics.sequence,
            statistics.frame_render_count,
            statistics.real_time_data_update_sequence,
            statistics.timing.paint_duration_ns,
            statistics.timing.render_duration_ns,
            statistics.timing.ready_wait_ns,
            statistics.timing.frame_age_at_render_ns,
            statistics.timing.end_to_end_ns,
            counters.published_frame_count,
            counters.render_pass_count,
            counters.abandoned_frame_count,
            counters.manually_discarded_frame_count,
            counters.swap_failure_count,
            observation.state.frequency_hz,
            static_cast<int>(observation.state.limit_state),
            observation.state.target_interval_ns,
            observation.state.bottleneck_duration_ns,
            observation.state.consumer_interval_ns,
            observation.state.next_refresh_interval_ns,
            observation.state.completed_lifecycle_count
        });
    }
};
using Low_Latency_Test_Observer_State = Observer_State<Low_Latency_Test_Observer, Low_Latency_Test_Time_Source>;
using Low_Latency_Test_Strategy = Low_Latency_Strategy<Low_Latency_Test_Frame, std::mutex, Low_Latency_Test_Observer_State>;
inline Low_Latency_Test_Strategy make_low_latency_test_strategy(const Low_Latency_Test_Time_Source& time_source, const Low_Latency_Test_Observer& observer) {
    return Low_Latency_Test_Strategy(Low_Latency_Test_Observer_State(observer, time_source));
}
inline std::vector<Low_Latency_Recorded_Observation> low_latency_observations(const std::shared_ptr<Low_Latency_Observer_Data>& data) {
    std::lock_guard lock(data->mutex);
    return data->observations;
}
