#include <TimedUnitTest.h>

namespace Constants
{
constexpr auto sampleRate = 48000.0;
constexpr auto sineFreq = 1000.0;
constexpr int N = 140;
} // namespace Constants

class HilbertFilterTest : public TimedUnitTest
{
public:
    HilbertFilterTest() : TimedUnitTest ("Hilbert Filter Test") {}

    void phaseShiftTest()
    {
        using namespace Constants;

        constexpr auto phaseShiftDelaySamples = sampleRate / sineFreq * 0.25;

        chowdsp::HilbertFilter<double> hilbert;
        hilbert.reset();

        chowdsp::DelayLine<double> shifter { 1 << 18 };
        shifter.prepare ({ sampleRate, 128, 1 });
        shifter.setDelay (phaseShiftDelaySamples);

        for (int n = 0; n < N; ++n)
        {
            const auto inPhase = MathConstants<double>::twoPi * (double) n * sineFreq / sampleRate;
            const auto inSample = std::sin (inPhase);

            auto [out, out90] = hilbert.process (inSample);

            shifter.pushSample (0, out90);
            auto outCorr = shifter.popSample (0);

            //            std::cout << out << ", " << out90 << ", " << outCorr << std::endl;

            if (n > 64)
            {
                const auto error = std::abs (out - outCorr) / (1.0 + std::abs (out));
                expectLessThan (error, 0.1, "Phase shift error is too high!");
            }
        }
    }

    void runTestTimed() override
    {
        beginTest ("Phase Shift Test");
        phaseShiftTest();
    }
};

static HilbertFilterTest hilbertFilterTest;
