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

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

    void setParameters(float thresholdDb, float ratio, float attackMs, float releaseMs,
                       float makeupDb, float mix) {
        threshold = std::pow(10.0f, thresholdDb / 20.0f);
        compRatio = ratio;
        attackCoeff = std::exp(-1.0f / (attackMs * 0.001f * static_cast<float>(sampleRate)));
        releaseCoeff = std::exp(-1.0f / (releaseMs * 0.001f * static_cast<float>(sampleRate)));
        makeupGain = std::pow(10.0f, makeupDb / 20.0f);
        dryWet = mix;
    }

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

        float gain = 1.0f;
        if (envelope > threshold && compRatio > 1.0f) {
            float overDb = 20.0f * std::log10(envelope / threshold);
            float compressedDb = overDb / compRatio;
            gain = std::pow(10.0f, (compressedDb - overDb) / 20.0f);
        }

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

private:
    double sampleRate = 44100.0;
    float threshold = 0.1f;
    float compRatio = 4.0f;
    float attackCoeff = 0.0f;
    float releaseCoeff = 0.0f;
    float makeupGain = 1.0f;
    float dryWet = 1.0f;
    float envelope = 0.0f;
};
