
#pragma once

// #include "fl/stl/assert.h"
// #include "fl/stl/function.h"
// #include "fl/math/lut.h"
// #include "fl/map_range.h"
// #include "fl/math/math.h"
// #include "fl/gfx/raster.h"
// #include "fl/gfx/xypath.h"
#include "fl/stl/function.h"  // IWYU pragma: keep
#include "fl/stl/shared_ptr.h"         // For FASTLED_SHARED_PTR macros
#include "fl/gfx/tile2x2.h"  // IWYU pragma: keep
#include "fl/math/transform.h"
#include "fl/stl/noexcept.h"

namespace fl {

FASTLED_SHARED_PTR(XYPathGenerator);

class XYPathRenderer {
  public:
    XYPathRenderer(XYPathGeneratorPtr path,
                   TransformFloat transform = TransformFloat());
    virtual ~XYPathRenderer() FL_NOEXCEPT = default; // Add virtual destructor for proper cleanup
    vec2f at(float alpha);

    Tile2x2_u8 at_subpixel(float alpha);

    void rasterize(float from, float to, int steps, XYRasterU8Sparse &raster,
                   fl::function<u8(float)> *optional_alpha_gen = nullptr);

    // Overloaded to allow transform to be passed in.
    vec2f at(float alpha, const TransformFloat &tx);

    // Needed for drawing to the screen. When this called the rendering will
    // be centered on the width and height such that 0,0 -> maps to .5,.5,
    // which is convenient for drawing since each float pixel can be truncated
    // to an integer type.
    void setDrawBounds(u16 width, u16 height);
    bool hasDrawBounds() const { return mDrawBoundsSet; }

    void onTransformFloatChanged();

    TransformFloat &transform();

    void setTransform(const TransformFloat &transform) {
        mTransform = transform;
        onTransformFloatChanged();
    }

    void setScale(float scale);

    vec2f compute(float alpha);

  private:
    XYPathGeneratorPtr mPath;
    TransformFloat mTransform;
    TransformFloat mGridTransform;
    bool mDrawBoundsSet = false;
    vec2f compute_float(float alpha, const TransformFloat &tx);
};

} // namespace fl
