#pragma once
#include <Renderer.h>
#include <random>

class RaymarchRenderer : public RendererInterface<RaymarchRenderer> {
public:
    static inline const std::string class_identifier = "Raymarch";
    static std::unique_ptr<Renderer> create_func(int width, int height, int maxSamples, int samplesPerFrame,
                                                 const std::vector<CUDA::PointLight>& lightsVector) {
        return std::make_unique<RaymarchRenderer>(width, height, maxSamples, samplesPerFrame, lightsVector);
    }

    RaymarchRenderer(int width, int height, int maxSamples, int samplesPerFrame,
                     std::vector<CUDA::PointLight> lightsVector) {
        initRenderer(width, height, maxSamples, samplesPerFrame);
        numLights = lightsVector.size();
        CUDA::malloc(lights, numLights);
        CUDA::memcopyToDevice(lights, lightsVector.data(), numLights);
    }

    void render(cudaSurfaceObject_t surface, CUDA::Camera camera, CUDA::Volume volume,
                CUDA::OptimizationParameters optParams) override;
    void renderSimple(cudaSurfaceObject_t surface, CUDA::Camera camera, CUDA::Volume volume,
                      CUDA::OptimizationParameters optParams) override;

    void drawGui(float deltaTime, float frametime) override;

    void submit() override;

    std::string getType() override {
        return class_identifier;
    }

    void setParameters(RenderParameters params) override {
        if (params.lightSamples >= 0) {
            temp_stepSizeView = params.stepSizeView;
            temp_stepSizeLight = params.stepSizeLight;
        } else {
            temp_stepSizeView = 0.02;
            temp_stepSizeLight = 0.02;
        }
        submit();
    }

private:
    CUDA::PointLight* lights;
    int numLights;

    std::random_device dev;

    float stepSizeView;
    float temp_stepSizeView;
    float stepSizeLight;
    float temp_stepSizeLight;
    bool jittered = false;
    bool temp_jittered = false;
};
