"""Delay audio filter — time-shift AudioAnalysis by a configurable amount."""

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

import numpy as np

from wled_controller.core.audio.analysis import NUM_BANDS, AudioAnalysis
from wled_controller.core.audio.filters.base import AudioFilter, AudioFilterOptionDef
from wled_controller.core.audio.filters.registry import AudioFilterRegistry

# Assumed update rate for sizing the ring buffer
_UPDATE_RATE_HZ = 30


@AudioFilterRegistry.register
class DelayFilter(AudioFilter):
    """Buffer incoming AudioAnalysis snapshots and output the one from N ms ago.

    Uses a ring buffer (deque) sized for the configured delay at ~30 Hz
    update rate.  Until the buffer is full, outputs a silent AudioAnalysis.
    """

    filter_id = "delay"
    filter_name = "Delay"

    def __init__(self, options: Dict[str, Any]):
        super().__init__(options)
        self._delay_ms = self.options["delay_ms"]
        self._buffer_size = max(1, int(self._delay_ms / 1000.0 * _UPDATE_RATE_HZ))
        self._buffer: deque[AudioAnalysis] = deque(maxlen=self._buffer_size)

    @property
    def is_stateful(self) -> bool:
        return True

    def reset(self) -> None:
        self._buffer.clear()

    @classmethod
    def get_options_schema(cls) -> List[AudioFilterOptionDef]:
        return [
            AudioFilterOptionDef(
                key="delay_ms",
                label="Delay (ms)",
                option_type="float",
                default=100.0,
                min_value=10.0,
                max_value=2000.0,
                step=10.0,
            ),
        ]

    def process(self, analysis: AudioAnalysis) -> AudioAnalysis:
        # Take a snapshot with copied arrays to avoid reference issues
        snapshot = replace(
            analysis,
            spectrum=np.copy(analysis.spectrum),
            left_spectrum=np.copy(analysis.left_spectrum),
            right_spectrum=np.copy(analysis.right_spectrum),
        )

        if len(self._buffer) >= self._buffer_size:
            # Buffer full — return the oldest entry (the delayed one)
            delayed = self._buffer[0]
            self._buffer.append(snapshot)
            return delayed
        else:
            # Buffer not yet full — store and output silence
            self._buffer.append(snapshot)
            return replace(
                analysis,
                rms=0.0,
                peak=0.0,
                spectrum=np.zeros(NUM_BANDS, dtype=np.float32),
                beat=False,
                beat_intensity=0.0,
                left_rms=0.0,
                left_spectrum=np.zeros(NUM_BANDS, dtype=np.float32),
                right_rms=0.0,
                right_spectrum=np.zeros(NUM_BANDS, dtype=np.float32),
            )
