#pragma once
#include <atomic>
#include <thread>
#include "node_border.h"
#include "rtt.h"
#include "brush.h"
#include "texture.h"
#include "legacy_node_stroke_preview_draw_services.h"
#include "legacy_node_stroke_preview_execution_services.h"
#include "legacy_node_stroke_preview_runtime_services.h"

class NodeStrokePreview : public NodeBorder
{
    using StrokeFrame = pp::panopainter::LegacyNodeStrokePreviewFrame;

    friend bool pp::panopainter::execute_legacy_node_stroke_preview_immediate_draw(NodeStrokePreview& preview);

    static RTT m_rtt;
    static RTT m_rtt_mixer;
    static Texture2D m_tex; // blending tmp texture
    static Texture2D m_tex_dual;
    static Texture2D m_tex_background;
    static Sampler m_sampler_linear;
    static Sampler m_sampler_linear_repeat;
    static Sampler m_sampler_mipmap;
    static DynamicShape m_brush_shape;
    Texture2D m_tex_preview;
public:
    using parent = NodeBorder;
    static std::atomic_int s_instances;
    static std::atomic_bool s_running;
    static std::mutex s_render_mutex;
    static std::jthread s_renderer;
    static BlockingQueue<std::shared_ptr<NodeStrokePreview>> s_queue;
    static void terminate_renderer();
    static void empty_queue();
    std::shared_ptr<Brush> m_brush;
    bool m_draw_first = false;
    glm::vec2 m_preview_size = { 0, 0 };
    float m_min_flow = 0.f;
    float m_max_size = 0.f;
    float m_pad_override = NAN;
    virtual Node* clone_instantiate() const override;
    virtual void clone_copy(Node* dest) const override;
    virtual void clone_children(Node* dest) const override;
    virtual void clone_finalize(Node* dest) const override;
    void init_controls();
    virtual void restore_context() override;
    virtual void clear_context() override;
    void stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz);
    // return rect {origin, size}
    glm::vec4 stroke_draw_samples(std::array<vertex_t, 4>& P, Texture2D& blend_tex, bool copy_stroke_destination);
    std::vector<StrokeFrame> stroke_draw_compute(const Stroke& stroke, float zoom) const;
    void draw_stroke();
    void draw_stroke_immediate();
    Image render_to_image();
    virtual void draw() override;
    virtual void handle_resize(glm::vec2 old_size, glm::vec2 new_size, float zoom) override;
    virtual void destroy() override;
    virtual void handle_on_screen(bool old_visibility, bool new_visibility) override;
};
