using System;
using FluidSim.Core;

namespace FluidSim.Core
{
    /// <summary>
    /// Synthesises far‑field exhaust sound using the monopole model
    /// of Jones (1978).  The radiated pressure is proportional to the
    /// time derivative of the mass flow at the pipe exit.
    ///
    /// Reference:
    ///   Jones, A.D. (1978) "Noise characteristics and exhaust process
    ///   gas dynamics of a small 2-stroke engine", PhD thesis, Univ. Adelaide.
    /// </summary>
    public class SoundProcessor
    {
        private readonly double dt;
        private readonly double r;            // listener distance (m)
        private readonly double scaleFactor;  // 1 / (4π r)  (free-field monopole)

        // ---------- Mass‑flow derivative (identical to original) ----------
        private double flowLP;
        private readonly double lpAlpha;
        private double prevMassFlowOut;
        private double smoothDMdt;
        private readonly double alpha;

        public float Gain { get; set; } = 1.0f;

        /// <summary>
        /// </summary>
        /// <param name="sampleRate">Audio sample rate (Hz).</param>
        /// <param name="listenerDistanceMeters">Listener distance (m).</param>
        /// <param name="pipeDiameterMeters">Ignored in this model; kept for compatibility.</param>
        public SoundProcessor(int sampleRate,
                              double listenerDistanceMeters = 1.0,
                              double pipeDiameterMeters = 0.0217)
        {
            dt = 1.0 / sampleRate;
            r = listenerDistanceMeters;
            scaleFactor = 1.0 / (4.0 * Math.PI * r);   // free‑field monopole

            // ---- Smoothing time constants (unchanged) ----
            double tau = 0.02;                     // 2 ms for derivative
            alpha = Math.Exp(-dt / tau);

            double tauLP = 0.00001;                   // 5 ms low‑pass on mass flow
            lpAlpha = Math.Exp(-dt / tauLP);
        }

        /// <summary>
        /// Process one sample.  The OpenEndLink provides the instantaneous
        /// exit‑plane mass flow.
        /// </summary>
        public float Process(OpenEndLink openEnd)
        {
            double flowOut = openEnd.LastMassFlowRate;   // kg/s, positive = leaving pipe

            // Low‑pass the mass flow signal
            flowLP = lpAlpha * flowLP + (1.0 - lpAlpha) * flowOut;

            // Derivative of the smoothed mass flow
            double rawDerivative = (flowLP - prevMassFlowOut) / dt;
            prevMassFlowOut = flowLP;

            // Smooth the derivative
            smoothDMdt = alpha * smoothDMdt + (1.0 - alpha) * rawDerivative;

            // Far‑field monopole pressure (free‑field, Jones eq. 2.15 adapted)
            double pressure = smoothDMdt * scaleFactor * Gain;

            // Soft clip to ±1
            return (float)pressure;
        }
    }
}