#pragma once

#include <algorithm>
#include <cmath>

namespace deeppluck
{
struct DeepPluckEffectMixGains
{
    float dry = 1.0f;
    float wet = 0.0f;
};

inline constexpr float maximumEffectMixCompensation = 1.75f;

[[nodiscard]] inline DeepPluckEffectMixGains calculateEffectMixGains (
    float mixAmount,
    float wetCalibration,
    float bypassDry = 0.0f) noexcept
{
    const auto amount = std::isfinite (mixAmount)
                            ? std::clamp (mixAmount, 0.0f, 1.0f) : 0.0f;
    const auto calibration = std::isfinite (wetCalibration)
                                 ? std::clamp (wetCalibration, 0.0f, 1.0f) : 0.0f;
    const auto bypass = std::isfinite (bypassDry)
                            ? std::clamp (bypassDry, 0.0f, 1.0f) : 1.0f;

    if (amount <= 0.0f)
        return { 1.0f, 0.0f };

    constexpr auto halfPi = 1.57079632679489661923f;
    const auto baseDry = amount >= 1.0f ? 0.0f : std::cos (halfPi * amount);
    const auto baseWet = std::sin (halfPi * amount) * calibration;
    const auto nominalPower = std::sqrt (baseDry * baseDry + baseWet * baseWet);
    const auto compensation = nominalPower > 0.0f
                                  ? std::clamp (1.0f / nominalPower,
                                                1.0f,
                                                maximumEffectMixCompensation)
                                  : 1.0f;
    const auto activeDry = baseDry * compensation;

    return {
        activeDry + bypass * (1.0f - activeDry),
        baseWet * compensation
    };
}
}
