import { vec2 } from "./lorenz_mie_coefs.js";

/**
 * Computes the normalized Mie phase function value for a specific angle.
 *
 * The phase function P(theta) is normalized such that the integral over 4pi solid angle is 4pi.
 * This implementation uses the recurrence relations for angular functions pi_n and tau_n as described by Bohren & Huffman.
 *
 * @param {Float32Array} ab - The flat array of a_n, b_n coefficients from LorenzMie_coefs.
 * @param {number} C_sca total scattering cross-section for normalization
 * @param {number} wavelength - Wavelength of light in vacuum (in meters).
 * @param {vec2} n_med - Complex refractive index of the medium.
 * @param {number} cos_theta - Cosine of the angle between incoming light and observation angle.
 * @returns {number} The normalized phase function value P(theta).
 */
export function compute_mie_phase(
    ab,
    C_sca,
    n_med,
    wavelength,
    cos_theta,
) {

    // If there is effectively no scattering, return isotropic phase (1.0)
    if (C_sca < 1e-30) return 1.0;

    const M = ab.length / 4;

    // Initialize sums as scalars (faster than array access)
    // S1 = Real + Imaginary parts
    let S1_r = 0.0;
    let S1_i = 0.0;

    // S2 = Real + Imaginary parts
    let S2_r = 0.0;
    let S2_i = 0.0;

    // Angular function recurrence initialization
    let pi_prev = 0.0; // pi_0 = 0
    let pi_cur = 1.0;  // pi_1 = 1

    for (let n = 1; n < M; ++n) {
        // 1. Load Coefficients directly (Zero Allocation)
        const idx = 4 * n;
        const an_r = ab[idx];
        const an_i = ab[idx + 1];
        const bn_r = ab[idx + 2];
        const bn_i = ab[idx + 3];

        // 2. Angular Recurrence
        // tau_n = n * cos_theta * pi_n - (n + 1) * pi_{n-1}
        const tau_cur = n * cos_theta * pi_cur - (n + 1) * pi_prev;

        // 3. Update Sums
        // factor = (2n + 1) / (n(n + 1))
        const factor = (2 * n + 1) / (n * (n + 1));

        // S1 += factor * (an * pi + bn * tau)
        S1_r += factor * (an_r * pi_cur + bn_r * tau_cur);
        S1_i += factor * (an_i * pi_cur + bn_i * tau_cur);

        // S2 += factor * (an * tau + bn * pi)
        S2_r += factor * (an_r * tau_cur + bn_r * pi_cur);
        S2_i += factor * (an_i * tau_cur + bn_i * pi_cur);

        // 4. Prepare next iteration
        // pi_{n+1} = ((2n + 1) * cos * pi_n - (n + 1) * pi_{n-1}) / n
        const pi_next = ((2 * n + 1) * cos_theta * pi_cur - (n + 1) * pi_prev) / n;
        pi_prev = pi_cur;
        pi_cur = pi_next;
    }

    // Calculate Intensity: (|S1|^2 + |S2|^2) / 2
    const S1_sq = S1_r * S1_r + S1_i * S1_i;
    const S2_sq = S2_r * S2_r + S2_i * S2_i;
    const intensity = 0.5 * (S1_sq + S2_sq);

    // Wavenumber in medium k = 2pi * Re(n_med) / lambda
    const k_med = (2.0 * Math.PI * n_med[0]) / wavelength;
    const k2 = k_med * k_med;

    // Normalization: P(theta) = 4pi * I / (k^2 * C_sca)
    return (4.0 * Math.PI * intensity) / (k2 * C_sca);
}