import numpy as np
from scipy.signal import butter, sosfilt
from .base import BaseProcessorModule

class DynamicsModule(BaseProcessorModule):
    """Surgical Dynamics Processing: Multiband & Limiting."""
    
    def process(self, audio: np.ndarray, **kwargs) -> np.ndarray:
        return audio

    def apply_multiband(self, audio: np.ndarray, bands_settings: list) -> np.ndarray:
        if not bands_settings: return audio
        
        sr = self.sample_rate
        sos_low = butter(4, 200, 'lp', fs=sr, output='sos')
        sos_mid = butter(4, [200, 5000], 'bp', fs=sr, output='sos')
        sos_high = butter(4, 5000, 'hp', fs=sr, output='sos')
        
        out = np.zeros_like(audio)
        filters = [sos_low, sos_mid, sos_high]
        
        for i, sos in enumerate(filters):
            if i >= len(bands_settings): break
            settings = bands_settings[i]
            
            if audio.ndim == 1: band_audio = sosfilt(sos, audio)
            else:
                l = sosfilt(sos, audio[:, 0]); r = sosfilt(sos, audio[:, 1])
                band_audio = np.column_stack((l, r))
            
            # Makeup gain
            makeup = 10 ** (settings.get('makeup_db', 0) / 20)
            band_audio *= makeup
            out += band_audio
            
        return out

    def apply_limiter(self, audio: np.ndarray, target_lufs: float = -8.0, release_ms: float = 50.0) -> np.ndarray:
        """Pro Limiter with adjustable release logic."""
        sr = self.sample_rate
        try:
            import pyloudnorm as pyln
            meter = pyln.Meter(sr)
            loudness = meter.integrated_loudness(audio)
            gain_needed = target_lufs - loudness
            audio *= (10 ** (gain_needed / 20))
        except: pass
            
        # Hard Ceiling
        return np.clip(audio, -0.99, 0.99)