#pragma once

#include <juce_audio_basics/juce_audio_basics.h>

namespace deeppluck
{
enum class DeepPluckLfoWaveform
{
    sine = 0,
    triangle,
    saw,
    square
};

enum class DeepPluckLfoRestartMode
{
    freeRunning = 0,
    retriggerFirstNote
};

struct DeepPluckLfoParameters
{
    float freeRateHz = 0.25f;
    float tempoSync = 0.0f;
    float syncDivision = 4.0f;
    float waveform = 0.0f;
    float restartMode = 1.0f;
    double tempoBpm = 120.0;
};

class DeepPluckLfo final
{
public:
    void prepare (double newSampleRate) noexcept;
    void setParameters (DeepPluckLfoParameters newParameters) noexcept;
    void restart() noexcept;
    [[nodiscard]] float processSample() noexcept;

    [[nodiscard]] double getPhase() const noexcept { return phase; }
    [[nodiscard]] double getCurrentRateHz() const noexcept
    {
        return smoothedRateHz.getCurrentValue();
    }
    [[nodiscard]] double getTargetRateHz() const noexcept
    {
        return smoothedRateHz.getTargetValue();
    }
    [[nodiscard]] float getCurrentOutput() const noexcept { return smoothedOutput; }
    [[nodiscard]] DeepPluckLfoRestartMode getRestartMode() const noexcept
    {
        return restartMode;
    }

    [[nodiscard]] static float waveformValue (DeepPluckLfoWaveform waveform,
                                              double phase) noexcept;
    [[nodiscard]] static double beatsPerCycle (int divisionIndex) noexcept;
    [[nodiscard]] static double synchronisedRateHz (double tempoBpm,
                                                    int divisionIndex) noexcept;

private:
    [[nodiscard]] static double wrapPhase (double value) noexcept;

    double sampleRate = 44100.0;
    double phase = 0.0;
    juce::SmoothedValue<double, juce::ValueSmoothingTypes::Multiplicative>
        smoothedRateHz { 0.25 };
    DeepPluckLfoWaveform waveform = DeepPluckLfoWaveform::sine;
    DeepPluckLfoRestartMode restartMode = DeepPluckLfoRestartMode::retriggerFirstNote;
    float smoothedOutput = 0.0f;
    float outputSmoothingCoefficient = 1.0f;
};
}
