"""Default feature registry builder for AI MusiMuse.

This module provides :func:`build_default_feature_registry`, which
creates and returns a fully configured
:class:`~features.registry.FeatureRegistry` with all feature
definitions currently produced by the built-in analyzers.

New analyzers should add their feature definitions here.  Each
definition's identifier must match the ``name`` field used in the
analyzer's ``Feature`` objects.
"""

from __future__ import annotations

from features.definition import (
    DataType,
    FeatureCategory,
    FeatureDefinition,
    NormalizationStrategy,
)
from features.registry import FeatureRegistry

_VERSION = "1.0.0"


def build_default_feature_registry() -> FeatureRegistry:
    """Create and return a registry with all built-in feature definitions.

    Returns:
        A fully configured :class:`FeatureRegistry` instance.
    """
    registry = FeatureRegistry()
    _register_signal_features(registry)
    _register_spectral_features(registry)
    _register_dynamic_features(registry)
    _register_rhythm_features(registry)
    _register_harmony_features(registry)
    return registry


def _register_signal_features(registry: FeatureRegistry) -> None:
    """Register all features produced by BasicSignalAnalyzer."""
    defs = [
        FeatureDefinition(
            identifier="signal.duration_seconds",
            display_name="Duration (seconds)",
            category=FeatureCategory.SIGNAL,
            description="Total duration of the audio in seconds.",
            unit="s",
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.NONE,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="signal.sample_rate",
            display_name="Sample Rate",
            category=FeatureCategory.SIGNAL,
            description="Sample rate of the audio in Hz.",
            unit="Hz",
            data_type=DataType.INT,
            normalization=NormalizationStrategy.NONE,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="signal.channels",
            display_name="Channels",
            category=FeatureCategory.SIGNAL,
            description="Number of audio channels (1 = mono, 2 = stereo).",
            unit=None,
            data_type=DataType.INT,
            normalization=NormalizationStrategy.CATEGORICAL,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="signal.peak",
            display_name="Peak Amplitude",
            category=FeatureCategory.SIGNAL,
            description="Maximum absolute amplitude of the mono signal.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="signal.rms",
            display_name="RMS Amplitude",
            category=FeatureCategory.SIGNAL,
            description="Root mean square amplitude of the mono signal.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="signal.peak_db",
            display_name="Peak dBFS",
            category=FeatureCategory.SIGNAL,
            description="Peak amplitude converted to dBFS.",
            unit="dBFS",
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="signal.rms_db",
            display_name="RMS dBFS",
            category=FeatureCategory.SIGNAL,
            description="RMS amplitude converted to dBFS.",
            unit="dBFS",
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="signal.dc_offset",
            display_name="DC Offset",
            category=FeatureCategory.SIGNAL,
            description="Mean amplitude of the signal (DC bias).",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="signal.silence_ratio",
            display_name="Silence Ratio",
            category=FeatureCategory.SIGNAL,
            description="Fraction of samples below the silence threshold.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="signal.peak_left",
            display_name="Peak Amplitude (Left)",
            category=FeatureCategory.SIGNAL,
            description="Maximum absolute amplitude of the left channel.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="signal.peak_right",
            display_name="Peak Amplitude (Right)",
            category=FeatureCategory.SIGNAL,
            description="Maximum absolute amplitude of the right channel.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="signal.rms_left",
            display_name="RMS Amplitude (Left)",
            category=FeatureCategory.SIGNAL,
            description="Root mean square amplitude of the left channel.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="signal.rms_right",
            display_name="RMS Amplitude (Right)",
            category=FeatureCategory.SIGNAL,
            description="Root mean square amplitude of the right channel.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
    ]
    for d in defs:
        registry.register(d)


def _register_spectral_features(registry: FeatureRegistry) -> None:
    """Register all features produced by SpectralAnalyzer."""
    defs = [
        FeatureDefinition(
            identifier="spectral.centroid",
            display_name="Spectral Centroid",
            category=FeatureCategory.SPECTRAL,
            description="Weighted mean frequency of the magnitude spectrum.",
            unit="Hz",
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.MINMAX,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="spectral.bandwidth",
            display_name="Spectral Bandwidth",
            category=FeatureCategory.SPECTRAL,
            description="Weighted std dev of frequencies around the centroid.",
            unit="Hz",
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.MINMAX,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="spectral.rolloff",
            display_name="Spectral Rolloff",
            category=FeatureCategory.SPECTRAL,
            description="Frequency below which 85% of spectral energy exists.",
            unit="Hz",
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.MINMAX,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="spectral.flatness",
            display_name="Spectral Flatness",
            category=FeatureCategory.SPECTRAL,
            description="Geometric / arithmetic mean of the power spectrum.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="spectral.zero_crossing_rate",
            display_name="Zero Crossing Rate",
            category=FeatureCategory.SPECTRAL,
            description="Fraction of consecutive sample pairs that cross zero.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="spectral.flux",
            display_name="Spectral Flux",
            category=FeatureCategory.SPECTRAL,
            description="Average frame-to-frame difference of magnitude spectra.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
    ]
    for d in defs:
        registry.register(d)


def _register_dynamic_features(registry: FeatureRegistry) -> None:
    """Register all features produced by DynamicAnalyzer."""
    defs = [
        FeatureDefinition(
            identifier="dynamic.crest_factor",
            display_name="Crest Factor",
            category=FeatureCategory.DYNAMIC,
            description="Ratio of peak to RMS amplitude.",
            unit="ratio",
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="dynamic.crest_factor_db",
            display_name="Crest Factor (dB)",
            category=FeatureCategory.DYNAMIC,
            description="Crest factor expressed in decibels.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="dynamic.range",
            display_name="Dynamic Range",
            category=FeatureCategory.DYNAMIC,
            description="Difference between max and min RMS envelope in dB.",
            unit="dB",
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="dynamic.headroom",
            display_name="Headroom (dB)",
            category=FeatureCategory.DYNAMIC,
            description="Difference between peak amplitude and full scale in dB.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="dynamic.clipping_ratio",
            display_name="Clipping Ratio",
            category=FeatureCategory.DYNAMIC,
            description="Fraction of samples at or above the clipping threshold.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="dynamic.average_rms_db",
            display_name="Average RMS (dBFS)",
            category=FeatureCategory.DYNAMIC,
            description="Average RMS amplitude in dBFS.",
            unit="dBFS",
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="dynamic.rms_variability",
            display_name="RMS Variability",
            category=FeatureCategory.DYNAMIC,
            description="Standard deviation of the RMS envelope in dB.",
            unit="dB",
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
    ]
    for d in defs:
        registry.register(d)


def _register_rhythm_features(registry: FeatureRegistry) -> None:
    """Register all features produced by RhythmAnalyzer."""
    defs = [
        FeatureDefinition(
            identifier="rhythm.tempo",
            display_name="Tempo (BPM)",
            category=FeatureCategory.RHYTHM,
            description="Estimated tempo in beats per minute.",
            unit="BPM",
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.LOG,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="rhythm.beat_period",
            display_name="Beat Period (seconds)",
            category=FeatureCategory.RHYTHM,
            description="Estimated beat period in seconds.",
            unit="s",
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="rhythm.density",
            display_name="Rhythm Density",
            category=FeatureCategory.RHYTHM,
            description="Number of onsets per second.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.MINMAX,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="rhythm.beat_strength",
            display_name="Beat Strength",
            category=FeatureCategory.RHYTHM,
            description="Strength of the dominant tempo from autocorrelation.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="rhythm.onset_count",
            display_name="Onset Count",
            category=FeatureCategory.RHYTHM,
            description="Total number of detected onsets.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.MINMAX,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="rhythm.onset_rate",
            display_name="Onset Rate",
            category=FeatureCategory.RHYTHM,
            description="Number of onsets per second.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.MINMAX,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="rhythm.regularity",
            display_name="Rhythm Regularity",
            category=FeatureCategory.RHYTHM,
            description="Consistency of inter-onset intervals.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
    ]
    for d in defs:
        registry.register(d)


def _register_harmony_features(registry: FeatureRegistry) -> None:
    """Register all features produced by HarmonyAnalyzer."""
    chroma_defs = [
        ("harmony.chroma_c", "Chroma C", "Energy in the C pitch class."),
        ("harmony.chroma_csharp", "Chroma C#", "Energy in the C# pitch class."),
        ("harmony.chroma_d", "Chroma D", "Energy in the D pitch class."),
        ("harmony.chroma_dsharp", "Chroma D#", "Energy in the D# pitch class."),
        ("harmony.chroma_e", "Chroma E", "Energy in the E pitch class."),
        ("harmony.chroma_f", "Chroma F", "Energy in the F pitch class."),
        ("harmony.chroma_fsharp", "Chroma F#", "Energy in the F# pitch class."),
        ("harmony.chroma_g", "Chroma G", "Energy in the G pitch class."),
        ("harmony.chroma_gsharp", "Chroma G#", "Energy in the G# pitch class."),
        ("harmony.chroma_a", "Chroma A", "Energy in the A pitch class."),
        ("harmony.chroma_asharp", "Chroma A#", "Energy in the A# pitch class."),
        ("harmony.chroma_b", "Chroma B", "Energy in the B pitch class."),
    ]
    for identifier, display_name, description in chroma_defs:
        registry.register(
            FeatureDefinition(
                identifier=identifier,
                display_name=display_name,
                category=FeatureCategory.HARMONY,
                description=description,
                unit=None,
                data_type=DataType.FLOAT,
                normalization=NormalizationStrategy.IDENTITY,
                version=_VERSION,
            )
        )

    tonnetz_defs = [
        ("harmony.tonnetz_x", "Tonnetz X", "Tonal centroid dimension X (fifths axis)."),
        (
            "harmony.tonnetz_y",
            "Tonnetz Y",
            "Tonal centroid dimension Y (minor thirds axis).",
        ),
        (
            "harmony.tonnetz_z",
            "Tonnetz Z",
            "Tonal centroid dimension Z (major thirds axis).",
        ),
        ("harmony.tonnetz_u", "Tonnetz U", "Tonal centroid dimension U."),
        ("harmony.tonnetz_v", "Tonnetz V", "Tonal centroid dimension V."),
        ("harmony.tonnetz_w", "Tonnetz W", "Tonal centroid dimension W."),
    ]
    for identifier, display_name, description in tonnetz_defs:
        registry.register(
            FeatureDefinition(
                identifier=identifier,
                display_name=display_name,
                category=FeatureCategory.HARMONY,
                description=description,
                unit=None,
                data_type=DataType.FLOAT,
                normalization=NormalizationStrategy.IDENTITY,
                version=_VERSION,
            )
        )

    extra_defs = [
        FeatureDefinition(
            identifier="harmony.key",
            display_name="Estimated Key",
            category=FeatureCategory.HARMONY,
            description="Estimated musical key from chroma distribution.",
            unit=None,
            data_type=DataType.STRING,
            normalization=NormalizationStrategy.CATEGORICAL,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="harmony.mode",
            display_name="Estimated Mode",
            category=FeatureCategory.HARMONY,
            description="Estimated musical mode (major, minor, or unknown).",
            unit=None,
            data_type=DataType.STRING,
            normalization=NormalizationStrategy.CATEGORICAL,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="harmony.tonal_stability",
            display_name="Tonal Stability",
            category=FeatureCategory.HARMONY,
            description="Stability of the tonal center (0-1).",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
        FeatureDefinition(
            identifier="harmony.pitch_class_entropy",
            display_name="Pitch Class Entropy",
            category=FeatureCategory.HARMONY,
            description="Shannon entropy of the pitch class distribution.",
            unit=None,
            data_type=DataType.FLOAT,
            normalization=NormalizationStrategy.IDENTITY,
            version=_VERSION,
        ),
    ]
    for d in extra_defs:
        registry.register(d)
