#pragma once
#include "GraphicsOperator.hpp"
#include "MayaFlux/Nodes/Graphics/PathGeneratorNode.hpp"

namespace MayaFlux::Nodes::Network {

class MAYAFLUX_API PathOperator : public GraphicsOperator {
public:
    explicit PathOperator(
        Kinesis::InterpolationMode mode = Kinesis::InterpolationMode::CATMULL_ROM,
        Eigen::Index samples_per_segment = 32);

    ~PathOperator() override { m_shutdown.store(true, std::memory_order_release); }

    /**
     * @brief Initialize a single path with given control points and properties.
     */
    void initialize(const std::vector<LineVertex>& vertices);

    /**
     * @brief Initialize multiple paths with given control points and properties.
     * @param paths Vector of control point vectors, one per path.
     * @param mode Interpolation mode for all paths.
     */
    void initialize_paths(
        const std::vector<std::vector<LineVertex>>& paths,
        Kinesis::InterpolationMode mode);

    /**
     * @brief Add a new path with given control points and properties.
     * @param control_points Vector of control points for the path.
     * @param mode Interpolation mode for the path.
     * @param default_samples_per_segment Number of samples to generate per segment (between control points).
     * @param max_control_points Maximum number of control points to store in history for this path
     * @param tension Tension parameter for applicable interpolation modes (e.g. Catmull-Rom)
     */
    void add_path(
        const std::vector<LineVertex>& control_vertices,
        Kinesis::InterpolationMode mode, uint32_t default_samples_per_segment = 32, size_t max_control_points = 64, double tension = 0.5);

    void process(float dt) override;

    [[nodiscard]] std::span<const uint8_t> get_vertex_data() const override;
    [[nodiscard]] std::span<const uint8_t> get_vertex_data_for_collection(uint32_t idx) const override;
    [[nodiscard]] Kakshya::VertexLayout get_vertex_layout() const override;
    [[nodiscard]] size_t get_vertex_count() const override;
    [[nodiscard]] bool is_vertex_data_dirty() const override;
    void mark_vertex_data_clean() override;

    /**
     * @brief Extract current vertex data as LineVertex array
     * @return Vector of LineVertex with current positions, colors, thicknesses
     */
    [[nodiscard]] std::vector<LineVertex> extract_vertices() const;

    void set_parameter(std::string_view param, double value) override;
    [[nodiscard]] std::optional<double> query_state(std::string_view query) const override;
    [[nodiscard]] std::string_view get_type_name() const override { return "Path"; }
    [[nodiscard]] size_t get_point_count() const override;

    /**
     * @brief Access a specific path node directly.
     * @param i Collection index.
     * @return Shared pointer to the PathGeneratorNode, or nullptr if out of range.
     */
    [[nodiscard]] std::shared_ptr<GpuSync::PathGeneratorNode> get_path(size_t i) const
    {
        if (i >= m_paths.size()) {
            return nullptr;
        }
        return m_paths[i];
    }

    /**
     * @brief Set the number of samples per segment for all paths.
     * @param samples Number of samples to generate per segment between control points.
     */
    void set_samples_per_segment(Eigen::Index samples);

    /**
     * @brief Set the tension parameter for all paths (if supported by mode).
     * @param tension Tension value (e.g., for cubic Hermite interpolation).
     */
    void set_tension(double tension);

    /**
     * @brief Set the global thickness for all paths.
     * @param thickness Thickness value to apply to all paths.
     */
    void set_global_thickness(float thickness);

    /**
     * @brief Set the global color tint for all paths.
     * @param color Color tint to apply to all paths (multiplied with individual tints).
     */
    void set_global_color(const glm::vec3& color);

    /**
     * @brief Get the number of paths currently managed by this operator.
     * @return Number of path collections.
     */
    [[nodiscard]] size_t get_path_count() const { return m_paths.size(); }

    const char* get_vertex_type_name() const override { return "PathVertex"; }

protected:
    void* get_data_at(size_t global_index) override;

private:
    std::vector<std::shared_ptr<GpuSync::PathGeneratorNode>> m_paths;

    mutable std::vector<uint8_t> m_vertex_data_aggregate;

    Kinesis::InterpolationMode m_default_mode;
    Eigen::Index m_default_samples_per_segment;
    float m_default_thickness { 2.0F };

    mutable std::atomic<uint32_t> m_access_token { 0 };
    std::atomic<bool> m_shutdown { false };
};

} // namespace MayaFlux::Nodes::Network
