#pragma once
#include <cmath>
#include <algorithm>

class Limiter {
public:
    void prepare(double sr) {
        sampleRate = sr;
        envelope = 0.0f;
    }

    void setParameters(float threshold, float ceiling, float releaseMs) {
        thresholdGain = threshold;
        ceilingGain = ceiling;
        releaseCoeff = std::exp(-1.0f / (std::max(releaseMs, 1.0f) * 0.001f * static_cast<float>(sampleRate)));
        dryWet = 1.0f;
    }

    float process(float input) {
        float absIn = std::abs(input);
        if (absIn > envelope)
            envelope = absIn;
        else
            envelope = releaseCoeff * envelope + (1.0f - releaseCoeff) * absIn;

        float target = std::max(thresholdGain, ceilingGain);
        float gain = 1.0f;
        if (envelope > target && envelope > 1e-6f) {
            float desired = target / envelope;
            gain = std::min(1.0f, desired);
        }

        float wet = input * gain;
        return input + (wet - input) * dryWet;
    }

private:
    double sampleRate = 44100.0;
    float thresholdGain = 1.0f;
    float ceilingGain = 1.0f;
    float releaseCoeff = 0.0f;
    float dryWet = 1.0f;
    float envelope = 0.0f;
};
