#pragma once
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <mutex>
#include <optional>
#include <vector>
#include "Capture_Types.hpp"
#include "renderive/render_graph/Frame_Analysis.hpp"

class Capture_Controller {
public:
    Capture_Session_Id capture_next_frame();
    Capture_Session_Id capture_frames(std::size_t count);
    [[nodiscard]] Capture_Frame_Ticket begin_frame() noexcept;
    void finish_frame(Capture_Frame_Ticket ticket, bool completed) noexcept;
    [[nodiscard]] Capture_Controller_State state() const noexcept;
private:
    struct Request {
        Request(Capture_Session_Id session_id, std::size_t count)
            : session_id(session_id), frames(pack(count, 0)) {}
        static std::uint64_t pack(std::size_t remaining, std::size_t in_flight) noexcept {
            return (static_cast<std::uint64_t>(remaining) << 32) |
                   static_cast<std::uint64_t>(in_flight);
        }
        static std::size_t remaining(std::uint64_t value) noexcept {
            return static_cast<std::uint32_t>(value >> 32);
        }
        static std::size_t in_flight(std::uint64_t value) noexcept {
            return static_cast<std::uint32_t>(value);
        }
        Capture_Session_Id session_id{};
        std::atomic<std::uint64_t> frames{};
    };
    std::atomic<Capture_Session_Id> next_session_id_{1};
    std::atomic<std::shared_ptr<Request>> request_;
};

struct Captured_Frame {
    std::shared_ptr<const Frame_Snapshot> snapshot;
    Frame_Analysis analysis;
};

struct Capture_Session {
    Capture_Session_Id session_id{};
    std::size_t requested_count{};
    std::vector<Captured_Frame> frames;
    [[nodiscard]] std::size_t captured_count() const noexcept {
        return frames.size();
    }
    [[nodiscard]] bool active() const noexcept {
        return frames.size() < requested_count;
    }
};

class Capture_Repository {
public:
    void begin_session(Capture_Session_Id session_id, std::size_t requested_count);
    void publish(Capture_Session_Id session_id,
                 std::shared_ptr<const Frame_Snapshot> snapshot,
                 Frame_Analysis analysis);
    [[nodiscard]] std::optional<Capture_Session> session(Capture_Session_Id session_id) const;
    [[nodiscard]] std::vector<Capture_Session_Id> sessions() const;
private:
    mutable std::mutex mutex_;
    std::vector<Capture_Session> sessions_;
};
