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

enum class FilterType { LowPass12 = 0, LowPass24, BandPass, HighPass, Notch, NumTypes };

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

    void reset() {
        for (int i = 0; i < 4; ++i)
            stage[i] = 0.0f;
        gCoeff = 0.0f;
        gTarget = 0.0f;
        kCoeff = 2.0f;
        kTarget = 2.0f;
    }

    void setCoefficients(float cutoff, float res, FilterType type) {
        cutoff = std::clamp(cutoff, 50.0f, static_cast<float>(sampleRate * 0.49));
        resonance = std::clamp(res, 0.0f, 1.0f);
        filterType = type;

        gTarget = std::tan(static_cast<float>(pi) * cutoff / static_cast<float>(sampleRate));
        kTarget = 2.0f - 2.0f * resonance;
    }

    float process(float input) {
        // Per-sample coefficient smoothing (one-pole, ~0.002 = ~44 samples to ~63%)
        gCoeff += (gTarget - gCoeff) * 0.002f;
        kCoeff += (kTarget - kCoeff) * 0.002f;

        float g = gCoeff;
        float k = kCoeff;
        float denom = 1.0f + k * g + g * g;

        float hp = (input - (k + g) * stage[0] - stage[1]) / denom;
        float bp = g * hp + stage[0];
        float lp = g * bp + stage[1];

        stage[0] = g * hp + bp;
        stage[1] = g * bp + lp;

        float hp2 = (lp - (k + g) * stage[2] - stage[3]) / denom;
        float bp2 = g * hp2 + stage[2];
        float lp2 = g * bp2 + stage[3];

        stage[2] = g * hp2 + bp2;
        stage[3] = g * bp2 + lp2;

        switch (filterType) {
            case FilterType::LowPass12:  return lp;
            case FilterType::LowPass24:  return lp2;
            case FilterType::BandPass:   return bp;
            case FilterType::HighPass:   return hp;
            case FilterType::Notch:      return input - bp;
            case FilterType::NumTypes:   return input;
        }
        return lp;
    }

private:
    static constexpr float pi = 3.14159265358979323846f;
    double sampleRate = 44100.0;
    float stage[4] = {0.0f, 0.0f, 0.0f, 0.0f};

    float gCoeff = 0.0f, gTarget = 0.0f;
    float kCoeff = 2.0f, kTarget = 2.0f;
    float resonance = 0.0f;
    FilterType filterType = FilterType::LowPass12;
};
