"""Band Extract audio filter — mask spectrum to a frequency range and recompute RMS."""

from dataclasses import replace
from typing import Any, Dict, List

from wled_controller.core.audio.analysis import AudioAnalysis
from wled_controller.core.audio.filters.base import AudioFilter, AudioFilterOptionDef
from wled_controller.core.audio.filters.registry import AudioFilterRegistry
from wled_controller.core.audio.band_filter import apply_band_filter, compute_band_mask


# Preset frequency ranges
_PRESETS = {
    "bass": (20.0, 250.0),
    "mid": (250.0, 4000.0),
    "treble": (4000.0, 20000.0),
}


@AudioFilterRegistry.register
class BandExtractFilter(AudioFilter):
    """Extract a frequency band from the spectrum.

    Supports presets (bass, mid, treble) or a custom frequency range.
    Zeros out-of-band spectrum bins and recomputes RMS from in-band data.
    """

    filter_id = "band_extract"
    filter_name = "Band Extract"

    def __init__(self, options: Dict[str, Any]):
        super().__init__(options)
        band = self.options["band"]
        if band == "custom":
            freq_low = self.options["freq_low"]
            freq_high = self.options["freq_high"]
        else:
            freq_low, freq_high = _PRESETS.get(band, (20.0, 20000.0))
        self._mask = compute_band_mask(freq_low, freq_high)

    @classmethod
    def get_options_schema(cls) -> List[AudioFilterOptionDef]:
        return [
            AudioFilterOptionDef(
                key="band",
                label="Band",
                option_type="select",
                default="bass",
                min_value=None,
                max_value=None,
                step=None,
                choices=[
                    {"value": "bass", "label": "Bass (20-250 Hz)"},
                    {"value": "mid", "label": "Mid (250-4000 Hz)"},
                    {"value": "treble", "label": "Treble (4000-20000 Hz)"},
                    {"value": "custom", "label": "Custom Range"},
                ],
            ),
            AudioFilterOptionDef(
                key="freq_low",
                label="Low Frequency (Hz)",
                option_type="float",
                default=20.0,
                min_value=20.0,
                max_value=20000.0,
                step=1.0,
            ),
            AudioFilterOptionDef(
                key="freq_high",
                label="High Frequency (Hz)",
                option_type="float",
                default=20000.0,
                min_value=20.0,
                max_value=20000.0,
                step=1.0,
            ),
        ]

    def process(self, analysis: AudioAnalysis) -> AudioAnalysis:
        filtered_spectrum, filtered_rms = apply_band_filter(
            analysis.spectrum,
            analysis.rms,
            self._mask,
        )
        filtered_left, filtered_left_rms = apply_band_filter(
            analysis.left_spectrum,
            analysis.left_rms,
            self._mask,
        )
        filtered_right, filtered_right_rms = apply_band_filter(
            analysis.right_spectrum,
            analysis.right_rms,
            self._mask,
        )
        return replace(
            analysis,
            rms=filtered_rms,
            spectrum=filtered_spectrum,
            left_rms=filtered_left_rms,
            left_spectrum=filtered_left,
            right_rms=filtered_right_rms,
            right_spectrum=filtered_right,
        )
