#pragma once

#include <memory>
#include <memory_resource>

#include "renderive/renderable/Renderable_Configuration.hpp"
#include "renderive/renderable/Renderable_Id.hpp"

class Frame_Strategy_Real_Time_Data_Observer;
class Real_Time_Data_Base;
class Real_Time_Data_Binding;
class Scene_Base;

class Renderable_Base {
public:
    virtual ~Renderable_Base();

    [[nodiscard]] Renderable_Id renderable_id() const noexcept;
    [[nodiscard]] bool is_visible() const noexcept;
    void set_visible(bool visible);
    void discard_stale_frame_on_latest_data_update(bool enabled) noexcept;

protected:
    class Impl;

    explicit Renderable_Base(
        Renderable_Configuration configuration = {},
        std::pmr::memory_resource& memory_resource =
            *std::pmr::get_default_resource());
    explicit Renderable_Base(
        std::unique_ptr<Impl> implementation,
        Renderable_Configuration configuration = {},
        std::pmr::memory_resource& memory_resource =
            *std::pmr::get_default_resource());

    template <class Implementation = Impl>
    Implementation& d_func() noexcept {
        return static_cast<Implementation&>(*d_ptr);
    }

    template <class Implementation = Impl>
    const Implementation& d_func() const noexcept {
        return static_cast<const Implementation&>(*d_ptr);
    }

private:
    friend class Frame_Strategy_Real_Time_Data_Observer;
    friend class Real_Time_Data_Base;
    friend class Real_Time_Data_Binding;
    friend class Scene_Base;

    std::unique_ptr<Impl> d_ptr;
};
