"""Unified spectral measurement function.

Provides a single entry point for computing multiple spectral quality
metrics following IEEE 1241-2010.

Example:
    >>> from oscura.analyzers.waveform.spectral.measure import measure
    >>> results = measure(trace)
    >>> if results['thd']['applicable']:
    ...     print(f"THD: {results['thd']['display']}")

References:
    IEEE 1241-2010: ADC Terminology and Test Methods
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

import numpy as np

from oscura.analyzers.waveform.spectral.fft import fft
from oscura.analyzers.waveform.spectral.quality_metrics import enob, sfdr, sinad, snr, thd
from oscura.core.measurement_result import make_inapplicable, make_measurement

if TYPE_CHECKING:
    from oscura.core.types import WaveformTrace


def measure(
    trace: WaveformTrace,
    *,
    parameters: list[str] | None = None,
    include_units: bool = True,
) -> dict[str, Any]:
    """Compute multiple spectral measurements with consistent format.

    Unified function for computing spectral quality metrics following IEEE 1241-2010.
    Returns MeasurementResult format with applicability tracking.

    Args:
        trace: Input waveform trace.
        parameters: List of measurement names to compute. If None, compute all.
            Valid names: thd, snr, sinad, enob, sfdr, dominant_freq
        include_units: If True, return MeasurementResult format. If False, return flat values.

    Returns:
        Dictionary mapping measurement names to MeasurementResults (if include_units=True)
        or raw values (if include_units=False).

    Raises:
        InsufficientDataError: If trace is too short for analysis.
        AnalysisError: If computation fails.

    Example:
        >>> from oscura.analyzers.waveform.spectral.measure import measure
        >>> results = measure(trace)
        >>> if results['thd']['applicable']:
        ...     print(f"THD: {results['thd']['display']}")

        >>> # Get specific measurements only
        >>> results = measure(trace, parameters=["thd", "snr"])

        >>> # Get flat values (legacy compatibility)
        >>> results = measure(trace, include_units=False)
        >>> thd_value = results["thd"]  # float or np.nan

    References:
        IEEE 1241-2010: ADC Terminology and Test Methods
    """
    # Define all available spectral measurements
    all_measurements = {
        "thd": thd,
        "snr": snr,
        "sinad": sinad,
        "enob": enob,
        "sfdr": sfdr,
    }

    # Select requested measurements or all
    if parameters is None:
        selected = all_measurements
    else:
        selected = {k: v for k, v in all_measurements.items() if k in parameters}

    results: dict[str, Any] = {}

    for name, func in selected.items():
        try:
            measurement_result = func(trace)  # type: ignore[operator]

            if include_units:
                # Return full MeasurementResult
                results[name] = measurement_result
            else:
                # Legacy mode: extract raw value (NaN if inapplicable)
                if measurement_result["applicable"]:
                    results[name] = measurement_result["value"]
                else:
                    results[name] = np.nan

        except Exception:
            # On error, create inapplicable result
            if include_units:
                results[name] = make_inapplicable("", "Measurement failed")
            else:
                results[name] = np.nan

    # Add dominant frequency if requested or if computing all
    if parameters is None or "dominant_freq" in parameters:
        try:
            fft_result = fft(trace, return_phase=False)
            freq, magnitude = fft_result[0], fft_result[1]
            dominant_idx = int(np.argmax(np.abs(magnitude[1:]))) + 1  # Skip DC
            dominant_freq_value = float(freq[dominant_idx])

            if include_units:
                results["dominant_freq"] = make_measurement(dominant_freq_value, "Hz")
            else:
                results["dominant_freq"] = dominant_freq_value
        except Exception:
            if include_units:
                results["dominant_freq"] = make_inapplicable("Hz", "FFT failed")
            else:
                results["dominant_freq"] = np.nan

    return results


__all__ = [
    "measure",
]
