#pragma once
#include <cstdint>
#include <cmath>
#include <limits>
#include <mutex>
#include <utility>
struct Real_Time_Data_Observation;
class Frame_Control_Strategy_Base {
public:
    struct State {
        double frequency_hz{invalid_frequency_hz()};
        std::uint64_t next_refresh_interval_ns{};
        std::uint64_t update_revision{};
        std::uint64_t publish_revision{};
    };
    virtual ~Frame_Control_Strategy_Base() = default;
    virtual void swap() = 0;
    virtual double frequency_hz() const noexcept = 0;
    virtual std::uint64_t next_refresh_interval_ns() const noexcept = 0;
    virtual State frame_control_state() const = 0;
    virtual void on_real_time_data_update(const Real_Time_Data_Observation& observation) noexcept = 0;
    virtual bool discard_stale_latest_data_frame() noexcept {
        return false;
    }
    static constexpr double invalid_frequency_hz() noexcept {
        return std::numeric_limits<double>::quiet_NaN();
    }
    static std::uint64_t frequency_interval_ns(double frequency_hz) noexcept {
        if (!std::isfinite(frequency_hz) || frequency_hz <= 0.0) {
            return 0;
        }
        const double interval_ns = 1'000'000'000.0 / frequency_hz;
        if (!std::isfinite(interval_ns) || interval_ns >= static_cast<double>(std::numeric_limits<std::uint64_t>::max())) {
            return std::numeric_limits<std::uint64_t>::max();
        }
        return static_cast<std::uint64_t>(interval_ns);
    }
protected:
    explicit Frame_Control_Strategy_Base(double frequency_hz = invalid_frequency_hz(), std::uint64_t next_refresh_interval_ns = 0)
        : states_{{frequency_hz, next_refresh_interval_ns, 0, 0}, {frequency_hz, next_refresh_interval_ns, 0, 0}}, render_state_(&states_[0]), cache_state_(&states_[1]) {}
    void update_frame_control_state(double frequency_hz, std::uint64_t next_refresh_interval_ns) {
        std::lock_guard<std::mutex> lock(state_mutex_);
        cache_state_->frequency_hz = frequency_hz;
        cache_state_->next_refresh_interval_ns = next_refresh_interval_ns;
        ++cache_state_->update_revision;
    }
    void swap_frame_control_state() {
        std::lock_guard<std::mutex> lock(state_mutex_);
        std::swap(render_state_, cache_state_);
        ++render_state_->publish_revision;
        *cache_state_ = *render_state_;
    }
    State render_frame_control_state() const {
        std::lock_guard<std::mutex> lock(state_mutex_);
        return *render_state_;
    }
private:
    State states_[2];
    State* render_state_;
    State* cache_state_;
    mutable std::mutex state_mutex_;
};
