#pragma once

#include "Datoviz_Scene_Binding.h"
#include "Frame_Target_Pool.h"
#include "Render_3D_Core.h"

#include <datoviz/drp2/runtime.h>
#include <datoviz/vk/gpu_ctx.h>

#include <cstddef>
#include <cstdint>
#include <memory>

namespace renderive::detail {

class Datoviz_Frame_Executor;
struct Datoviz_Transaction_Api;
inline constexpr std::uint64_t Datoviz_Color_Target_Id = 4242;

class Datoviz_Backend final {
public:
    Datoviz_Backend(
        std::uint32_t gpu_index, bool validation_enabled, const Render_3D_State& initial_state);
    ~Datoviz_Backend();

    Datoviz_Backend(const Datoviz_Backend&) = delete;
    Datoviz_Backend& operator=(const Datoviz_Backend&) = delete;

    [[nodiscard]] std::unique_ptr<Frame_Target_Pool> create_target_pool(std::size_t slot_count);
    [[nodiscard]] bool render(const Render_3D_Frame_Data& frame, Frame_Target_Pool& targets);

    void destroy_runtime() noexcept;
    void destroy_scene() noexcept;
    void destroy_gpu_context() noexcept;

private:
    friend class Datoviz_Frame_Executor;
    friend struct Datoviz_Transaction_Api;

    void create_runtime();
    void create_scene(Extent_2D extent);
    [[nodiscard]] bool rebuild(const Render_3D_Frame_Data& frame, Frame_Target_Pool& targets) noexcept;
    [[nodiscard]] DvzSceneFrameArtifact* emit(const DvzFramePlanEmitConfig& configuration);
    [[nodiscard]] bool attach(const DvzStreamFrame& frame);
    [[nodiscard]] bool execute(const DvzDrp2CommandStream& stream);

    DvzGpuCtx* gpu_context_{};
    DvzDrp2Runtime* runtime_{};
    DvzScene* scene_{};
    std::unique_ptr<Datoviz_Scene_Binding> scene_binding_;
};

} // namespace renderive::detail
