#pragma once

#include <atomic>
#include <cstdint>
#include <utility>

#include "foundation/concurrency/CopySnapshotPublisher.h"

namespace ta::features
{
    template <typename Settings,
              typename Publisher = ta::foundation::CopySnapshotPublisher<Settings>>
    class SettingsCache final
    {
    public:
        template <typename Source>
        bool refresh(Source& source)
        {
            return publish_if_changed(source.read());
        }

        bool publish_if_changed(Settings next)
        {
            const auto current = publisher_.latest();
            if (current && *current == next)
                return false;

            publisher_.publish(std::move(next));
            revision_.fetch_add(1, std::memory_order_release);
            return true;
        }

        [[nodiscard]] auto latest() const noexcept(noexcept(publisher_.latest()))
        {
            return publisher_.latest();
        }

        [[nodiscard]] Settings current_or_default() const
        {
            const auto current = publisher_.latest();
            return current ? *current : Settings{};
        }

        [[nodiscard]] std::uint64_t revision() const noexcept
        {
            return revision_.load(std::memory_order_acquire);
        }

        void clear() noexcept(noexcept(publisher_.clear()))
        {
            publisher_.clear();
        }

    private:
        Publisher publisher_;
        std::atomic<std::uint64_t> revision_{0};
    };
}
