import { lerp } from "../../../../core/math/lerp.js";

/**
 * Locomotor-respiratory coupling — compute the breath-rate target by
 * blending the metabolic-demand rate with a stride-aligned sub-multiple.
 *
 * Empirical basis: in steady-state running, breath naturally locks to a
 * sub-multiple of stride (2:1, 3:1, 4:1 depending on speed — see Bramble &
 * Carrier 1983, Bernasconi & Kohl 1993). In *dynamic* activity (varied
 * terrain, sports, untrained) the coupling is much weaker and the breath
 * rate is dictated mostly by metabolic demand.
 *
 * We blend the two: at low exertion (or below the strideFreq threshold)
 * the output is purely metabolic. At high exertion AND active gait, the
 * output is pulled toward the integer-ratio aligned rate. This is
 * FREQUENCY-only coupling — no phase lock — so the breath "rides" the
 * gait without being constrained to it, matching loose dynamic-activity
 * coupling rather than tight steady-state coupling.
 *
 * @param {number} metabolicRate the rate driven by exertion alone (Hz)
 * @param {number} strideFreqHz current stride frequency (Hz, 0 if not striding)
 * @param {number} exertion in [0..1]
 * @param {number} couplingMax coupling strength at exertion=1
 * @param {number} minStrideFreqHz coupling does not engage below this
 * @returns {number} target breath rate (Hz)
 */
export function computeLRCBreathRate(
    metabolicRate,
    strideFreqHz,
    exertion,
    couplingMax,
    minStrideFreqHz,
) {
    if (strideFreqHz < minStrideFreqHz || metabolicRate <= 1e-3) {
        return metabolicRate;
    }
    const stridesPerBreath = Math.max(1, Math.round(strideFreqHz / metabolicRate));
    const strideAlignedRate = strideFreqHz / stridesPerBreath;
    const coupling = couplingMax * exertion;
    return lerp(metabolicRate, strideAlignedRate, coupling);
}
