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

class Delay {
public:
    void prepare(double sr) {
        sampleRate = sr;
        int maxSamples = static_cast<int>(sr * 2.0);
        bufferL.resize(maxSamples, 0.0f);
        bufferR.resize(maxSamples, 0.0f);
        writePos = 0;
    }

    void setParameters(float timeMs, float fb, float mx, bool pp, float spr) {
        timeSamples = static_cast<int>(timeMs * 0.001f * sampleRate);
        int bufMax = static_cast<int>(bufferL.size()) - 1;
        timeSamples = std::clamp(timeSamples, 1, bufMax);
        feedback = std::clamp(fb, 0.0f, 0.95f);
        mix = std::clamp(mx, 0.0f, 1.0f);
        pingpong = pp;
        spread = std::clamp(spr, 0.25f, 0.75f);
    }

    void process(float& left, float& right) {
        int bufSize = static_cast<int>(bufferL.size());

        if (pingpong) {
            int timeR = std::max(1, static_cast<int>(timeSamples * spread));
            int readL = (writePos - timeSamples + bufSize) % bufSize;
            int readR = (writePos - timeR + bufSize) % bufSize;

            float outL = bufferR[readR];
            float outR = bufferL[readL];

            bufferL[writePos] = left + outR * feedback;
            bufferR[writePos] = right + outL * feedback;

            writePos = (writePos + 1) % bufSize;

            left = left * (1.0f - mix) + outL * mix;
            right = right * (1.0f - mix) + outR * mix;
        } else {
            int readPos1 = (writePos - timeSamples + bufSize) % bufSize;
            int time2 = std::max(1, static_cast<int>(timeSamples * spread));
            int readPos2 = (writePos - time2 + bufSize) % bufSize;

            float tap1L = bufferL[readPos1];
            float tap1R = bufferR[readPos1];
            float tap2L = bufferL[readPos2];
            float tap2R = bufferR[readPos2];

            float outL = tap1L + tap2L * 0.6f;
            float outR = tap1R + tap2R * 0.6f;

            bufferL[writePos] = left + outL * feedback;
            bufferR[writePos] = right + outR * feedback;

            writePos = (writePos + 1) % bufSize;

            left = left * (1.0f - mix) + outL * mix;
            right = right * (1.0f - mix) + outR * mix;
        }
    }

private:
    std::vector<float> bufferL, bufferR;
    int writePos = 0;
    double sampleRate = 44100;
    int timeSamples = 8820;
    float feedback = 0.3f;
    float mix = 0.25f;
    bool pingpong = false;
    float spread = 0.5f;
};
