from __future__ import annotations

from typing import cast
from typing_extensions import TypeAlias

import numpy as np
import numpy.typing as npt

# Canonical floating array type (Python 3.8 compatible)
ArrayF: TypeAlias = npt.NDArray[np.float32]


def gauss(x: ArrayF, mu: float, sigma: float) -> ArrayF:
    """Gaussian bump used in ECG morphology."""
    y = np.exp(-0.5 * ((x - mu) / sigma) ** 2).astype(np.float32)
    return cast(ArrayF, y)


def ecg_mult(
    x: ArrayF,
    *,
    p_mu: float = 0.18,
    q_mu: float = 0.38,
    r_mu: float = 0.40,
    s_mu: float = 0.42,
    t_mu: float = 0.70,
    p_sig: float = 0.030,
    q_sig: float = 0.010,
    r_sig: float = 0.008,
    s_sig: float = 0.012,
    t_sig: float = 0.055,
    p_amp: float = 0.10,
    q_amp: float = -0.12,
    r_amp: float = 1.00,
    s_amp: float = -0.25,
    t_amp: float = 0.35,
    baseline: float = 1.0,
    gain: float = 0.20,
    min_mult: float = 0.05,
) -> ArrayF:
    """
    Canonical ECG-shaped multiplier: P–QRS–T complex.
    Returns a strictly positive multiplier curve.
    """
    P = p_amp * gauss(x, p_mu, p_sig)
    Q = q_amp * gauss(x, q_mu, q_sig)
    R = r_amp * gauss(x, r_mu, r_sig)
    S = s_amp * gauss(x, s_mu, s_sig)
    T = t_amp * gauss(x, t_mu, t_sig)

    mult = baseline + gain * (P + Q + R + S + T)
    mult = np.maximum(mult, min_mult).astype(np.float32)
    return cast(ArrayF, mult)
