#pragma once
#include <cmath>

enum class LFODest { FilterCutoff = 0, OSC1Freq, OSC2Freq, BothOsc };
enum class LFOShape { Sine = 0, Triangle, Saw, Square };

class LFO {
public:
    void prepare(double sr) { sampleRate = sr; }

    void setParameters(float rate, float depth, LFOShape s, LFODest d) {
        lfoRate = rate;
        lfoDepth = depth;
        shape = s;
        dest = d;
    }

    float getNextSample() {
        float twoPi = 6.2831853f;
        phase += lfoRate / static_cast<float>(sampleRate);
        if (phase >= 1.0f) phase -= 1.0f;

        float out = 0.0f;
        float p = phase;

        switch (shape) {
            case LFOShape::Sine:
                out = std::sin(p * twoPi);
                break;
            case LFOShape::Triangle:
                out = 2.0f * std::abs(2.0f * (p - 0.5f)) - 1.0f;
                break;
            case LFOShape::Saw:
                out = 2.0f * p - 1.0f;
                break;
            case LFOShape::Square:
                out = p < 0.5f ? 1.0f : -1.0f;
                break;
        }

        return out * lfoDepth;
    }

    LFODest getDest() const { return dest; }
    void reset() { phase = 0.0f; }

private:
    double sampleRate = 44100.0;
    float phase = 0.0f;
    float lfoRate = 2.0f;
    float lfoDepth = 0.0f;
    LFOShape shape = LFOShape::Sine;
    LFODest dest = LFODest::FilterCutoff;
};
