"""Measurement suggestion engine for signal analysis.

Provides the ``suggest_measurements`` public API and supporting helpers for
recommending the most suitable measurements based on signal characteristics.

References:
    Best practices for waveform analysis
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, cast

from oscura.inference.signal_intelligence.classification import classify_signal
from oscura.inference.signal_intelligence.detection import _count_edges
from oscura.inference.signal_intelligence.quality import assess_signal_quality

if TYPE_CHECKING:
    from oscura.core.types import WaveformTrace


def _add_statistical_suggestions(suggestions: list[dict[str, Any]]) -> None:
    """Add core statistical measurement suggestions."""
    suggestions.append(
        {
            "name": "mean",
            "category": "statistical",
            "priority": 1,
            "rationale": "Basic DC level measurement, always applicable",
            "confidence": 1.0,
        }
    )

    suggestions.append(
        {
            "name": "rms",
            "category": "statistical",
            "priority": 2,
            "rationale": "RMS voltage measurement, useful for all signal types",
            "confidence": 1.0,
        }
    )


def _add_dc_signal_suggestion(suggestions: list[dict[str, Any]]) -> None:
    """Add suggestion for DC signal noise measurement."""
    suggestions.append(
        {
            "name": "amplitude",
            "category": "amplitude",
            "priority": 3,
            "rationale": "Measure noise/variation level in DC signal",
            "confidence": 0.9,
        }
    )


def _add_amplitude_suggestion(suggestions: list[dict[str, Any]], signal_type: str) -> None:
    """Add general amplitude measurement suggestion."""
    suggestions.append(
        {
            "name": "amplitude",
            "category": "amplitude",
            "priority": 3,
            "rationale": f"Peak-to-peak amplitude for {signal_type} signal",
            "confidence": 0.95,
        }
    )


def _add_periodic_suggestions(
    suggestions: list[dict[str, Any]], classification: dict[str, Any]
) -> None:
    """Add frequency/period suggestions for periodic signals."""
    suggestions.append(
        {
            "name": "frequency",
            "category": "timing",
            "priority": 4,
            "rationale": "Periodic signal detected, frequency measurement applicable",
            "confidence": classification["confidence"],
        }
    )

    suggestions.append(
        {
            "name": "period",
            "category": "timing",
            "priority": 5,
            "rationale": "Period measurement for periodic signal",
            "confidence": classification["confidence"],
        }
    )


def _add_digital_signal_suggestions(
    suggestions: list[dict[str, Any]],
    trace: WaveformTrace,
    classification: dict[str, Any],
    quality: dict[str, Any],
    characteristics: list[str],
) -> None:
    """Add edge timing and pulse measurement suggestions for digital signals."""
    edge_count = _count_edges(trace.data, classification.get("levels"))

    if edge_count >= 2:
        snr_conf = 0.9 if quality["snr"] and quality["snr"] > 20 else 0.7

        suggestions.append(
            {
                "name": "rise_time",
                "category": "timing",
                "priority": 6,
                "rationale": f"Digital edges detected ({edge_count} edges)",
                "confidence": snr_conf,
            }
        )

        suggestions.append(
            {
                "name": "fall_time",
                "category": "timing",
                "priority": 7,
                "rationale": f"Digital edges detected ({edge_count} edges)",
                "confidence": snr_conf,
            }
        )

    if "periodic" in characteristics and edge_count >= 2:
        duty_conf = 0.85 if edge_count >= 4 else 0.75

        suggestions.append(
            {
                "name": "duty_cycle",
                "category": "timing",
                "priority": 8,
                "rationale": "Periodic pulse train detected",
                "confidence": duty_conf,
            }
        )

        suggestions.append(
            {
                "name": "pulse_width",
                "category": "timing",
                "priority": 9,
                "rationale": "Pulse measurements suitable for periodic digital signal",
                "confidence": duty_conf,
            }
        )


def _add_analog_signal_suggestions(
    suggestions: list[dict[str, Any]], quality: dict[str, Any]
) -> None:
    """Add overshoot/undershoot suggestions for analog signals."""
    if not quality["clipping"]:
        suggestions.append(
            {
                "name": "overshoot",
                "category": "amplitude",
                "priority": 10,
                "rationale": "Analog signal, overshoot measurement applicable",
                "confidence": 0.8,
            }
        )

        suggestions.append(
            {
                "name": "undershoot",
                "category": "amplitude",
                "priority": 11,
                "rationale": "Analog signal, undershoot measurement applicable",
                "confidence": 0.8,
            }
        )


def _add_spectral_suggestions(suggestions: list[dict[str, Any]], trace: WaveformTrace) -> None:
    """Add spectral analysis suggestions for clean periodic signals."""
    if len(trace.data) >= 256:
        suggestions.append(
            {
                "name": "thd",
                "category": "spectral",
                "priority": 12,
                "rationale": "Clean periodic signal suitable for harmonic analysis",
                "confidence": 0.85,
            }
        )

        suggestions.append(
            {
                "name": "snr",
                "category": "spectral",
                "priority": 13,
                "rationale": "Spectral SNR measurement for signal quality",
                "confidence": 0.8,
            }
        )


def suggest_measurements(
    trace: WaveformTrace,
    *,
    max_suggestions: int = 10,
) -> list[dict[str, Any]]:
    """Suggest appropriate measurements for a signal.

    Analyzes signal characteristics and recommends the most suitable
    measurements, ranked by relevance and reliability.

    Args:
        trace: Input waveform trace.
        max_suggestions: Maximum number of suggestions to return.

    Returns:
        List of dictionaries, each containing:
        - name: Measurement name
        - category: Measurement category (e.g., "timing", "amplitude", "spectral")
        - priority: Priority ranking (1=highest)
        - rationale: Why this measurement is recommended
        - confidence: Confidence in recommendation (0.0-1.0)

    Example:
        >>> trace = osc.load('square_wave.wfm')
        >>> suggestions = osc.suggest_measurements(trace)
        >>> for s in suggestions[:3]:
        ...     print(f"{s['name']}: {s['rationale']}")
        frequency: Periodic digital signal detected
        duty_cycle: Suitable for pulse analysis
        rise_time: Digital edges detected

    References:
        Best practices for waveform analysis
    """
    classification = classify_signal(trace)
    quality = assess_signal_quality(trace)

    signal_type = classification["type"]
    characteristics = classification["characteristics"]

    suggestions: list[dict[str, Any]] = []

    # Core statistical measurements (always applicable)
    _add_statistical_suggestions(suggestions)

    # Early return for DC signals
    if signal_type == "dc":
        _add_dc_signal_suggestion(suggestions)
        return sorted(suggestions, key=lambda x: cast("int", x["priority"]))[:max_suggestions]

    # Add suggestions based on signal characteristics
    _add_amplitude_suggestion(suggestions, signal_type)

    if "periodic" in characteristics:
        _add_periodic_suggestions(suggestions, classification)

    if signal_type in ("digital", "mixed"):
        _add_digital_signal_suggestions(
            suggestions, trace, classification, quality, characteristics
        )

    if signal_type in ("analog", "mixed"):
        _add_analog_signal_suggestions(suggestions, quality)

    if "periodic" in characteristics and "clean" in characteristics:
        _add_spectral_suggestions(suggestions, trace)

    # Sort by priority and limit
    suggestions = sorted(suggestions, key=lambda x: cast("int", x["priority"]))
    return suggestions[:max_suggestions]
