"""
FX Chains & Automation Pro for AbletonMCP-AI
T061-T080: DJ FX Chains, Device Racks, Macros y Automatización Avanzada
"""
import random
import time
from typing import Dict, List, Any, Optional, Tuple, Union
from dataclasses import dataclass, field
from enum import Enum


class FXType(Enum):
    """Tipos de efectos disponibles."""
    FILTER = "filter"
    DELAY = "delay"
    REVERB = "reverb"
    BEATMASHER = "beatmasher"
    TAPE_STOP = "tape_stop"
    GATER = "gater"
    FLANGER = "flanger"
    BITCRUSHER = "bitcrusher"
    VINYL = "vinyl"
    CHORUS = "chorus"
    SATURATOR = "saturator"
    PHASER = "phaser"
    PINGPONG = "pingpong"
    RESONANCE = "resonance"
    FREEZE = "freeze"
    VOCODER = "vocoder"
    AUTOPAN = "autopan"
    TRANSIENT = "transient"
    SUB_BASS = "sub_bass"


@dataclass
class MacroConfig:
    """Configuración de macro para efectos DJ."""
    name: str
    min_value: float = 0.0
    max_value: float = 1.0
    default_value: float = 0.0
    is_bipolar: bool = False


@dataclass
class FXChain:
    """Cadena de efectos con configuración."""
    name: str
    devices: List[Dict[str, Any]] = field(default_factory=list)
    macros: List[MacroConfig] = field(default_factory=list)
    is_return: bool = False


class FXAutomationEngine:
    """
    T061-T080: Engine de FX Chains & Automation Pro.
    Crea racks de efectos, macros DJ y automatización avanzada.
    """

    # Nombres de dispositivos de Ableton Live 12
    DEVICE_NAMES = {
        'AutoFilter': 'Auto Filter',
        'BeatRepeat': 'Beat Repeat',
        'HybridReverb': 'Hybrid Reverb',
        'Echo': 'Echo',
        'Flanger': 'Flanger',
        'Phaser': 'Phaser',
        'Chorus': 'Chorus',
        'Saturator': 'Saturator',
        'Limiter': 'Limiter',
        'Compressor': 'Compressor',
        'GlueCompressor': 'Glue Compressor',
        'MultibandDynamics': 'Multiband Dynamics',
        'Redux': 'Redux',
        'VinylDistortion': 'Vinyl Distortion',
        'AutoPan': 'Auto Pan',
        'Utility': 'Utility',
        'Vocoder': 'Vocoder',
        'Resonators': 'Resonators',
        'Spectrum': 'Spectrum',
        'EQ3': 'EQ Three',
        'EQ8': 'EQ Eight',
        'ChannelEQ': 'Channel EQ',
    }

    def __init__(self, seed: int = 42):
        self.rng = random.Random(seed)
        self._created_chains: List[Dict[str, Any]] = []
        self._automation_points: List[Dict[str, Any]] = []

    # =========================================================================
    # T061: Core DJ Rack Setup
    # =========================================================================

    def create_dj_rack_config(self, rack_type: str = "standard") -> FXChain:
        """
        T061: Crea configuración de rack DJ con Filter, Wash, Delay, BeatMasher.
        
        Args:
            rack_type: 'standard', 'minimal', 'extended'
        """
        devices = []
        macros = []

        if rack_type in ("standard", "extended"):
            # Filter (Auto Filter)
            devices.append({
                'type': 'AutoFilter',
                'params': {
                    'Frequency': 1000.0,
                    'Resonance': 0.5,
                    'Drive': 0.0,
                    'Morph': 0.0,  # Low-pass default
                }
            })

            # Wash (Reverb)
            devices.append({
                'type': 'HybridReverb',
                'params': {
                    'Dry/Wet': 0.3,
                    'Decay Time': 2.5,
                    'Predelay': 0.008,
                    'Room Size': 0.5,
                }
            })

            # Delay (Echo)
            devices.append({
                'type': 'Echo',
                'params': {
                    'Dry/Wet': 0.25,
                    'Feedback': 0.3,
                    'Time': 0.25,  # 1/4 note
                    'Sync': 1,  # Sync on
                }
            })

            # BeatMasher (Beat Repeat)
            devices.append({
                'type': 'BeatRepeat',
                'params': {
                    'Interval': 1,  # 1/4
                    'Grid': 0,  # 1/16
                    'Variation': 0,
                    'Chance': 1.0,
                    'Gate': 0.5,
                }
            })

        if rack_type == "extended":
            # Flanger para sweeps
            devices.append({
                'type': 'Flanger',
                'params': {
                    'Dry/Wet': 0.2,
                    'Delay Time': 10.0,
                    'Feedback': 0.3,
                    'LFO Amount': 0.5,
                }
            })

            # Vinyl para textura
            devices.append({
                'type': 'VinylDistortion',
                'params': {
                    'Tracing Drive': 0.2,
                    'Pinch': 0.3,
                    'Crackle': 0.15,
                }
            })

        # Macros del rack
        macros = [
            MacroConfig("Filter Cutoff", 0.0, 1.0, 0.5),
            MacroConfig("Wash Amount", 0.0, 1.0, 0.3),
            MacroConfig("Delay Time", 0.0, 1.0, 0.25),
            MacroConfig("BeatMasher", 0.0, 1.0, 0.0),
        ]

        if rack_type == "extended":
            macros.extend([
                MacroConfig("Flanger Sweep", 0.0, 1.0, 0.0),
                MacroConfig("Vinyl Texture", 0.0, 1.0, 0.15),
            ])

        return FXChain(
            name=f"DJ Rack - {rack_type.capitalize()}",
            devices=devices,
            macros=macros
        )

    # =========================================================================
    # T062: BeatMasher Automation
    # =========================================================================

    def create_beatmasher_automation(
        self,
        track_index: int,
        clip_index: int,
        pattern: str = "quarter_eighth",
        intensity: float = 0.5
    ) -> Dict[str, Any]:
        """
        T062: Automatización de BeatMasher con patrones 1/4, 1/8.
        
        Args:
            pattern: 'quarter', 'eighth', 'quarter_eighth', 'random'
            intensity: 0.0-1.0, probabilidad de stutter
        """
        automation_points = []
        patterns = {
            'quarter': [(0, 1), (8, 1), (16, 1), (24, 1)],
            'eighth': [(0, 0), (4, 2), (8, 0), (12, 2), (16, 0), (20, 2), (24, 0), (28, 2)],
            'quarter_eighth': [
                (0, 1), (4, 2), (8, 1), (12, 2),
                (16, 1), (20, 2), (24, 1), (28, 2)
            ],
            'build': [
                (0, 1), (2, 2), (4, 1), (6, 2),
                (8, 1), (10, 2), (12, 1), (14, 2),
                (16, 0),  # Off at drop
            ],
        }

        selected_pattern = patterns.get(pattern, patterns['quarter_eighth'])
        
        for beat, grid_value in selected_pattern:
            if self.rng.random() < intensity:
                automation_points.append({
                    'track_index': track_index,
                    'clip_index': clip_index,
                    'device_type': 'BeatRepeat',
                    'param': 'Grid',
                    'time': beat,
                    'value': grid_value,  # 0=1/16, 1=1/8, 2=1/4, 3=1/2
                    'chance': 1.0,
                })

        return {
            'pattern': pattern,
            'intensity': intensity,
            'points': automation_points,
            'device_config': {
                'type': 'BeatRepeat',
                'default_params': {
                    'Interval': 1,  # 1/4
                    'Grid': 1,  # 1/8
                    'Variation': 0,
                    'Chance': 1.0,
                    'Gate': 0.5,
                }
            }
        }

    # =========================================================================
    # T063: Tape Stop Automation
    # =========================================================================

    def create_tape_stop_automation(
        self,
        track_index: int,
        start_time: float,
        duration_beats: float = 4.0,
        pitch_range_semitones: float = -12.0
    ) -> Dict[str, Any]:
        """
        T063: Automatización de Tape Stop con pitch envelope.
        Crea una curva de pitch descendente que simula parada de cinta.
        """
        steps = int(duration_beats * 4)  # 16 pasos por beat
        points = []
        
        for i in range(steps + 1):
            t = start_time + (i / 4.0)  # Cada paso = 1/4 beat
            # Curva exponencial descendente
            progress = i / steps
            pitch = pitch_range_semitones * (progress ** 0.5)  # Raíz cuadrada para feel natural
            
            points.append({
                'time': t,
                'pitch': pitch,
                'volume': 1.0 - (progress * 0.3),  # Ligeramente bajar volumen
            })

        return {
            'effect': 'tape_stop',
            'track_index': track_index,
            'start_time': start_time,
            'duration': duration_beats,
            'pitch_range': pitch_range_semitones,
            'automation_points': points,
            'device_chain': [
                {'type': 'Utility', 'param': 'Pitch', 'points': points},
                {'type': 'AutoFilter', 'param': 'Frequency', 
                 'points': [{'time': p['time'], 'value': 20000 * (1 - progress)} for p in points]},
            ]
        }

    # =========================================================================
    # T064: Gater/Trance Gate Effect
    # =========================================================================

    def create_gater_effect(
        self,
        track_index: int,
        pattern: str = "sixteenth",
        rate: str = "1/16",
        depth: float = 0.8
    ) -> Dict[str, Any]:
        """
        T064: Efecto Gater/Trance Gate con chops de volumen en 1/16.
        
        Args:
            pattern: 'sixteenth', 'eighth', 'triplet', 'random'
            rate: '1/32', '1/16', '1/8', '1/4'
            depth: 0.0-1.0, profundidad del gating (0=silencio completo, 1=sin gating)
        """
        rate_beats = {
            '1/32': 0.125,
            '1/16': 0.25,
            '1/8': 0.5,
            '1/4': 1.0,
        }
        
        step_size = rate_beats.get(rate, 0.25)
        
        # Patrones rítmicos de gating
        patterns = {
            'sixteenth': [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0],  # X-X-X-X-
            'eighth': [1, 1, 0, 0, 1, 1, 0, 0],  # XX--XX--
            'triplet': [1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0],  # X--X--X--
            'random': None,  # Generado dinámicamente
            'build': [1, 0.8, 0.6, 0.4, 0.2, 0, 0, 0, 1, 0.8, 0.6, 0.4, 0.2, 0, 0, 0],
        }

        base_pattern = patterns.get(pattern)
        if base_pattern is None:
            # Patrón aleatorio
            base_pattern = [1 if self.rng.random() > 0.5 else 0 for _ in range(16)]

        # Aplicar profundidad al patrón
        adjusted_pattern = []
        for gate_value in base_pattern:
            if gate_value == 1:
                adjusted_pattern.append(depth)  # Abierto
            else:
                adjusted_pattern.append(max(0, 1.0 - depth))  # Cerrado

        points = []
        for i, value in enumerate(adjusted_pattern):
            time = i * step_size
            points.append({'time': time, 'value': value})

        return {
            'effect': 'gater',
            'pattern': pattern,
            'rate': rate,
            'depth': depth,
            'track_index': track_index,
            'automation_points': points,
            'device': 'Utility',  # Volumen via Utility Gain
            'param': 'Gain',
        }

    # =========================================================================
    # T065: Automated Flanger Sweeps
    # =========================================================================

    def create_flanger_sweep(
        self,
        track_index: int,
        start_bar: int,
        duration_bars: int = 4,
        rate: str = "syncopated"
    ) -> Dict[str, Any]:
        """
        T065: Flanger Sweeps con LFOs sincopados.
        
        Args:
            rate: 'slow', 'medium', 'fast', 'syncopated'
        """
        rates = {
            'slow': 0.1,      # 1 ciclo cada 10 beats
            'medium': 0.25,   # 1 ciclo cada 4 beats
            'fast': 0.5,      # 1 ciclo cada 2 beats
            'syncopated': 0.33,  # Tercina feel
        }
        
        lfo_rate = rates.get(rate, 0.25)
        total_beats = duration_bars * 4
        points = []

        # Crear sweep con sincopación
        for beat in range(0, total_beats * 4, 1):  # Cada 1/4 beat
            t = start_bar * 4 + (beat / 4.0)
            
            # LFO principal
            phase = (beat / 4.0) * lfo_rate * 2 * 3.14159
            lfo_value = (1 + (phase)) / 2  # 0-1
            
            # Sincopación adicional (offset)
            if rate == 'syncopated':
                syncopation = ((beat / 4.0) % 3) / 3.0  # Pattern ternario
                lfo_value = (lfo_value + syncopation * 0.3) % 1.0

            # Mapear a parámetros de flanger
            delay_time = 0.5 + (lfo_value * 15.0)  # 0.5-15.5 ms
            feedback = -0.5 + (lfo_value * 1.0)  # -0.5 a 0.5
            
            points.append({
                'time': t,
                'delay_time': delay_time,
                'feedback': feedback,
                'lfo_amount': 0.5 + (lfo_value * 0.5),
            })

        return {
            'effect': 'flanger_sweep',
            'rate': rate,
            'track_index': track_index,
            'start_bar': start_bar,
            'duration_bars': duration_bars,
            'automation_points': points,
            'device': 'Flanger',
            'params': ['Delay Time', 'Feedback', 'LFO Amount'],
        }

    # =========================================================================
    # T066: Send/Return DJ Strategy
    # =========================================================================

    def create_dj_send_strategy(
        self,
        return_tracks: int = 2
    ) -> Dict[str, Any]:
        """
        T066: Estrategia de Send/Return para DJ con verb/delay paralelo.
        """
        returns = []

        # Return A: Reverb (Wash)
        returns.append({
            'name': 'A-Reverb',
            'device_chain': [
                {'type': 'HybridReverb', 'params': {
                    'Dry/Wet': 1.0,  # 100% wet
                    'Decay Time': 3.0,
                    'Room Size': 0.6,
                    'Predelay': 0.012,
                }},
                {'type': 'AutoFilter', 'params': {
                    'Frequency': 8000.0,  # Low-pass suave
                    'Resonance': 0.3,
                }},
            ],
            'send_amounts': {
                'drums': 0.15,
                'bass': 0.0,  # Bass sin reverb
                'music': 0.25,
                'vocals': 0.35,
            }
        })

        # Return B: Delay (Echo)
        returns.append({
            'name': 'B-Delay',
            'device_chain': [
                {'type': 'Echo', 'params': {
                    'Dry/Wet': 1.0,
                    'Time': 0.375,  # 3/8 - dotted quarter
                    'Feedback': 0.35,
                    'Sync': 1,
                }},
                {'type': 'AutoFilter', 'params': {
                    'Frequency': 6000.0,
                    'Resonance': 0.2,
                }},
            ],
            'send_amounts': {
                'drums': 0.10,
                'bass': 0.0,
                'music': 0.20,
                'vocals': 0.30,
            }
        })

        if return_tracks >= 3:
            # Return C: Chorus/Spatial
            returns.append({
                'name': 'C-Chorus',
                'device_chain': [
                    {'type': 'Chorus', 'params': {
                        'Dry/Wet': 1.0,
                        'Delay': 25.0,
                        'Feedback': 0.4,
                        'Amount': 0.6,
                    }},
                ],
                'send_amounts': {
                    'music': 0.15,
                    'vocals': 0.20,
                }
            })

        if return_tracks >= 4:
            # Return D: Specialized FX
            returns.append({
                'name': 'D-Spatial',
                'device_chain': [
                    {'type': 'Resonators', 'params': {
                        'Decay': 0.5,
                        'II Pitch': 3,
                        'III Pitch': 7,
                        'IV Pitch': 10,
                        'V Pitch': 14,
                    }},
                    {'type': 'AutoFilter', 'params': {
                        'Frequency': 4000.0,
                    }},
                ],
                'send_amounts': {
                    'music': 0.10,
                    'vocals': 0.15,
                }
            })

        return {
            'strategy': 'parallel_send_return',
            'returns': returns,
            'master_send_config': {
                'pre_fader': True,
                'default_levels': {
                    'A-Reverb': 0.8,
                    'B-Delay': 0.7,
                    'C-Chorus': 0.6,
                    'D-Spatial': 0.5,
                }
            }
        }

    # =========================================================================
    # T067: Master Bus Filter
    # =========================================================================

    def create_master_filter_sweep(
        self,
        start_bar: int,
        duration_bars: int = 8,
        sweep_type: str = "lowpass_down"
    ) -> Dict[str, Any]:
        """
        T067: Filtro global en master bus para sweeps de energía.
        
        Args:
            sweep_type: 'lowpass_down', 'lowpass_up', 'highpass_down', 'highpass_up'
        """
        points = []
        total_beats = duration_bars * 4

        # Configuración según tipo
        configs = {
            'lowpass_down': {'start_freq': 20000, 'end_freq': 400, 'filter_type': 'low'},
            'lowpass_up': {'start_freq': 400, 'end_freq': 20000, 'filter_type': 'low'},
            'highpass_down': {'start_freq': 100, 'end_freq': 8000, 'filter_type': 'high'},
            'highpass_up': {'start_freq': 8000, 'end_freq': 100, 'filter_type': 'high'},
        }

        config = configs.get(sweep_type, configs['lowpass_down'])
        start_freq = config['start_freq']
        end_freq = config['end_freq']

        # Curva exponencial para sweep natural
        for beat_quarter in range(total_beats * 4 + 1):
            t = start_bar * 4 + (beat_quarter / 4.0)
            progress = beat_quarter / (total_beats * 4)
            
            # Curva logarítmica para sweep de frecuencia
            log_start = 10 if start_freq <= 0 else start_freq
            log_end = 10 if end_freq <= 0 else end_freq
            
            freq = log_start * ((log_end / log_start) ** progress)
            
            points.append({
                'time': t,
                'frequency': freq,
                'resonance': 0.3 + (progress * 0.4),  # Aumentar resonancia en el sweep
            })

        return {
            'effect': 'master_filter_sweep',
            'sweep_type': sweep_type,
            'track': 'master',
            'start_bar': start_bar,
            'duration_bars': duration_bars,
            'automation_points': points,
            'device': 'AutoFilter',
            'filter_type': config['filter_type'],
        }

    # =========================================================================
    # T068: Ping-Pong Delay Throws
    # =========================================================================

    def create_pingpong_throws(
        self,
        track_index: int,
        throw_positions: List[float],
        feedback: float = 0.4,
        time_dotted: bool = True
    ) -> Dict[str, Any]:
        """
        T068: Delay throws ping-pong para vocal bus.
        
        Args:
            throw_positions: Lista de posiciones en beats donde hacer el throw
            time_dotted: True = 3/8, False = 1/4
            feedback: Nivel de feedback para el eco
        """
        throws = []
        delay_time = 0.375 if time_dotted else 0.5  # 3/8 o 1/2

        for pos in throw_positions:
            # Throw: subir send momentáneamente
            throw = {
                'position': pos,
                'pre_delay': 0.5,  # 1/2 beat antes
                'duration': 2.0,   # 2 beats de throw
                'envelope': [
                    {'time': pos - 0.5, 'value': 0.0},   # Silencio antes
                    {'time': pos, 'value': 0.8},         # Pico del throw
                    {'time': pos + 0.25, 'value': 0.6},  # Decay rápido
                    {'time': pos + 1.0, 'value': 0.3},   # Sostenido
                    {'time': pos + 2.0, 'value': 0.0},   # Off
                ]
            }
            throws.append(throw)

        return {
            'effect': 'pingpong_throws',
            'track_index': track_index,
            'delay_time': delay_time,
            'feedback': feedback,
            'throws': throws,
            'device': 'Echo',
            'device_params': {
                'Time': delay_time,
                'Feedback': feedback,
                'Dry/Wet': 0.0,  # 100% send control
                'Mode': 'Ping Pong',
                'Sync': 1,
            }
        }

    # =========================================================================
    # T069: Redux/Bitcrusher Build
    # =========================================================================

    def create_redux_build(
        self,
        track_index: int,
        start_bar: int,
        end_bar: int,
        start_bits: int = 16,
        end_bits: int = 4
    ) -> Dict[str, Any]:
        """
        T069: Bitcrusher/Redux automation para builds.
        Reduce bits durante build para tensión.
        """
        points = []
        duration_beats = (end_bar - start_bar) * 4

        for beat_quarter in range(int(duration_beats * 4) + 1):
            t = start_bar * 4 + (beat_quarter / 4.0)
            progress = beat_quarter / (duration_beats * 4)
            
            # Interpolar bits
            bits = start_bits - ((start_bits - end_bits) * progress)
            
            # Downsampling rate también varía
            downsample = 1 + int(progress * 3)  # 1 -> 2 -> 3 -> 4
            
            points.append({
                'time': t,
                'bit_depth': bits,
                'downsample': downsample,
            })

        return {
            'effect': 'redux_build',
            'track_index': track_index,
            'start_bar': start_bar,
            'end_bar': end_bar,
            'automation_points': points,
            'device': 'Redux',
            'params': ['Bit Depth', 'Downsample'],
        }

    # =========================================================================
    # T070: Resonance Riding
    # =========================================================================

    def create_resonance_automation(
        self,
        track_index: int,
        section_boundaries: List[Tuple[int, int]],
        resonance_curve: str = "energy"
    ) -> Dict[str, Any]:
        """
        T070: Automatización de resonancia de filtro.
        
        Args:
            section_boundaries: [(start_bar, end_bar), ...]
            resonance_curve: 'energy', 'smooth', 'rhythmic'
        """
        points = []
        
        for start_bar, end_bar in section_boundaries:
            duration = end_bar - start_bar
            
            if resonance_curve == "energy":
                # Más resonancia en secciones intensas
                base_res = 0.3
                peak_res = 0.7
            elif resonance_curve == "smooth":
                base_res = 0.2
                peak_res = 0.4
            else:  # rhythmic
                base_res = 0.25
                peak_res = 0.6

            # Crear puntos clave
            key_points = [
                (start_bar, base_res),
                (start_bar + duration * 0.25, peak_res),
                (start_bar + duration * 0.5, base_res + 0.1),
                (start_bar + duration * 0.75, peak_res * 0.8),
                (end_bar, base_res),
            ]

            for bar, res in key_points:
                points.append({
                    'time': bar * 4,
                    'resonance': res,
                    'frequency': 1000 + (res * 5000),  # Frecuencia ligada a resonancia
                })

        return {
            'effect': 'resonance_riding',
            'track_index': track_index,
            'curve_type': resonance_curve,
            'automation_points': points,
            'device': 'AutoFilter',
            'param': 'Resonance',
        }

    # =========================================================================
    # T071: Vinyl Distortion Overlay
    # =========================================================================

    def create_vinyl_overlay(
        self,
        track_index: int,
        intensity: str = "medium",
        crackle_only: bool = False
    ) -> Dict[str, Any]:
        """
        T071: Capa de vinyl distortion con crackle y noise.
        
        Args:
            intensity: 'subtle', 'medium', 'heavy'
            crackle_only: Si True, solo crackle sin pinch
        """
        intensity_map = {
            'subtle': {'tracing': 0.1, 'pinch': 0.15, 'crackle': 0.08},
            'medium': {'tracing': 0.25, 'pinch': 0.35, 'crackle': 0.15},
            'heavy': {'tracing': 0.45, 'pinch': 0.55, 'crackle': 0.30},
        }

        params = intensity_map.get(intensity, intensity_map['medium'])
        
        if crackle_only:
            params['pinch'] = 0.0
            params['tracing'] = 0.05

        return {
            'effect': 'vinyl_overlay',
            'track_index': track_index,
            'intensity': intensity,
            'device': 'VinylDistortion',
            'params': {
                'Tracing Drive': params['tracing'],
                'Pinch': params['pinch'],
                'Crackle': params['crackle'],
                'Crackle Density': 0.5,
            },
            'automation': [
                # Crackle varía ligeramente para feel orgánico
                {'param': 'Crackle', 'variance': 0.05, 'rate': 'slow'},
            ]
        }

    # =========================================================================
    # T072: Chorus/Widening Tricks
    # =========================================================================

    def create_chorus_widening(
        self,
        track_index: int,
        target: str = "music_bus",
        width: float = 1.2
    ) -> Dict[str, Any]:
        """
        T072: Chorus para expansión del campo estéreo.
        
        Args:
            target: 'music_bus', 'vocals', 'synths', 'master'
            width: Factor de expansión (1.0 = normal, 1.5 = wide)
        """
        configs = {
            'music_bus': {
                'delay': 20.0,
                'feedback': 0.35,
                'amount': 0.5,
                'rate': 0.5,
            },
            'vocals': {
                'delay': 15.0,
                'feedback': 0.25,
                'amount': 0.4,
                'rate': 0.3,
            },
            'synths': {
                'delay': 25.0,
                'feedback': 0.45,
                'amount': 0.6,
                'rate': 0.6,
            },
            'master': {
                'delay': 12.0,
                'feedback': 0.2,
                'amount': 0.3,
                'rate': 0.4,
            },
        }

        config = configs.get(target, configs['music_bus'])

        # Utility para width estéreo
        utility_config = {
            'Stereo Width': min(2.0, max(0.0, width)),
        }

        return {
            'effect': 'chorus_widening',
            'track_index': track_index,
            'target': target,
            'width': width,
            'chain': [
                {'type': 'Chorus', 'params': {
                    'Delay': config['delay'],
                    'Feedback': config['feedback'],
                    'Amount': config['amount'],
                    'Rate': config['rate'],
                    'Dry/Wet': 0.3,
                }},
                {'type': 'Utility', 'params': utility_config},
            ]
        }

    # =========================================================================
    # T073: Sub-Bass Synthesizer
    # =========================================================================

    def create_sub_bass_synth(
        self,
        track_index: int,
        key: str = "Am",
        pattern: str = "dive",
        trigger_bars: List[int] = None
    ) -> Dict[str, Any]:
        """
        T073: Síntesis de sub-bass tipo 808 para drops.
        
        Args:
            pattern: 'dive', 'pulse', 'sustain', 'hit'
            trigger_bars: Barras donde disparar el sub-bass
        """
        if trigger_bars is None:
            trigger_bars = [8, 24]  # Drop positions default

        # Nota raíz según key
        key_roots = {
            'Am': 45, 'A': 45, 'A#m': 46, 'A#': 46,
            'Bm': 47, 'B': 47, 'Cm': 48, 'C': 48,
            'C#m': 49, 'C#': 49, 'Dm': 50, 'D': 50,
            'D#m': 51, 'D#': 51, 'Em': 52, 'E': 52,
            'Fm': 53, 'F': 53, 'F#m': 54, 'F#': 54,
            'Gm': 55, 'G': 55, 'G#m': 56, 'G#': 56,
        }
        root_note = key_roots.get(key, 45)

        patterns = {
            'dive': [
                {'pitch': root_note, 'vel': 100, 'duration': 2.0},
                {'pitch': root_note - 12, 'vel': 80, 'duration': 2.0},  # Slide down
            ],
            'pulse': [
                {'pitch': root_note, 'vel': 120, 'duration': 0.25},
                {'pitch': root_note, 'vel': 100, 'duration': 0.25},
                {'pitch': root_note, 'vel': 120, 'duration': 0.25},
                {'pitch': root_note, 'vel': 100, 'duration': 0.25},
            ],
            'sustain': [
                {'pitch': root_note, 'vel': 110, 'duration': 4.0},
            ],
            'hit': [
                {'pitch': root_note, 'vel': 127, 'duration': 0.5},
            ],
        }

        pattern_data = patterns.get(pattern, patterns['dive'])

        return {
            'effect': 'sub_bass_synth',
            'track_index': track_index,
            'key': key,
            'root_note': root_note,
            'pattern': pattern,
            'trigger_bars': trigger_bars,
            'midi_notes': pattern_data,
            'device_chain': [
                {'type': 'Saturator', 'params': {'Drive': 4.0, 'Color': 0.3}},
                {'type': 'Compressor', 'params': {'Threshold': -20.0, 'Ratio': 8.0}},
                {'type': 'Utility', 'params': {'Stereo Width': 0.0, 'Gain': 2.0}},
            ],
            'frequency_response': '20-60Hz',
        }

    # =========================================================================
    # T074: Multiband Transient Shaping
    # =========================================================================

    def create_transient_shaper(
        self,
        track_index: int,
        band_focus: str = "kick",
        attack_db: float = 3.0,
        sustain_db: float = -2.0
    ) -> Dict[str, Any]:
        """
        T074: Shaping de transientes multibanda.
        
        Args:
            band_focus: 'kick', 'snare', 'full', 'high'
            attack_db: Boost/cut en ataque (+dB)
            sustain_db: Boost/cut en sustain (-dB)
        """
        band_configs = {
            'kick': {
                'low_freq': 40,
                'mid_freq': 200,
                'high_freq': 1000,
                'bands': {
                    'low': {'attack': attack_db, 'sustain': sustain_db},
                    'mid': {'attack': attack_db * 0.5, 'sustain': sustain_db * 0.5},
                    'high': {'attack': 0, 'sustain': 0},
                }
            },
            'snare': {
                'low_freq': 100,
                'mid_freq': 500,
                'high_freq': 3000,
                'bands': {
                    'low': {'attack': 0, 'sustain': 0},
                    'mid': {'attack': attack_db, 'sustain': sustain_db},
                    'high': {'attack': attack_db * 0.7, 'sustain': sustain_db * 0.3},
                }
            },
            'full': {
                'low_freq': 120,
                'mid_freq': 1000,
                'high_freq': 6000,
                'bands': {
                    'low': {'attack': attack_db * 0.8, 'sustain': sustain_db * 0.8},
                    'mid': {'attack': attack_db, 'sustain': sustain_db},
                    'high': {'attack': attack_db * 0.5, 'sustain': sustain_db * 0.5},
                }
            },
            'high': {
                'low_freq': 500,
                'mid_freq': 2000,
                'high_freq': 8000,
                'bands': {
                    'low': {'attack': 0, 'sustain': 0},
                    'mid': {'attack': attack_db * 0.5, 'sustain': sustain_db * 0.5},
                    'high': {'attack': attack_db, 'sustain': sustain_db},
                }
            },
        }

        config = band_configs.get(band_focus, band_configs['full'])

        return {
            'effect': 'transient_shaper',
            'track_index': track_index,
            'band_focus': band_focus,
            'config': config,
            'device': 'MultibandDynamics',
            'alternative': 'Compressor',  # Fallback
            'params': {
                'Crossover Freq 1': config['low_freq'],
                'Crossover Freq 2': config['mid_freq'],
                'Crossover Freq 3': config['high_freq'],
            },
        }

    # =========================================================================
    # T075: Freeze FX
    # =========================================================================

    def create_freeze_effect(
        self,
        track_index: int,
        freeze_bar: int,
        duration_bars: int = 2,
        source: str = "reverb"
    ) -> Dict[str, Any]:
        """
        T075: Efecto Freeze (buffer freeze) para breaks.
        
        Args:
            source: 'reverb', 'delay', 'input'
        """
        freeze_time = freeze_bar * 4  # En beats
        
        if source == "reverb":
            device = 'HybridReverb'
            param = 'Freeze'
            chain = [
                {'type': 'HybridReverb', 'params': {
                    'Freeze': 0,  # Inicia off
                    'Dry/Wet': 0.5,
                    'Decay Time': 10.0,
                }},
            ]
        elif source == "delay":
            device = 'Echo'
            param = 'Freeze'
            chain = [
                {'type': 'Echo', 'params': {
                    'Freeze': 0,
                    'Feedback': 0.9,
                    'Dry/Wet': 0.4,
                }},
            ]
        else:
            device = 'Utility'
            param = 'Gain'
            chain = []

        return {
            'effect': 'freeze',
            'track_index': track_index,
            'freeze_bar': freeze_bar,
            'duration_bars': duration_bars,
            'source': source,
            'device': device,
            'param': param,
            'automation': [
                {'time': freeze_time, 'value': 0},  # Pre-freeze
                {'time': freeze_time + 0.1, 'value': 1},  # Activate
                {'time': freeze_time + (duration_bars * 4), 'value': 0},  # Release
            ],
            'chain': chain,
        }

    # =========================================================================
    # T076: Vocoder Integration
    # =========================================================================

    def create_vocoder_setup(
        self,
        vocal_track: int,
        synth_track: int,
        bands: int = 20
    ) -> Dict[str, Any]:
        """
        T076: Setup de vocoder con sidechain de sintetizador.
        
        Args:
            bands: Número de bandas (8-40)
        """
        return {
            'effect': 'vocoder',
            'vocoder_track': vocal_track,
            'carrier_track': synth_track,
            'device': 'Vocoder',
            'params': {
                'Bands': bands,
                'Range': 'Full',
                'Depth': 1.0,
                'Attack': 0.001,
                'Release': 0.05,
                'Formant': 1.0,
                'Dry/Wet': 0.7,
            },
            'routing': {
                'carrier': synth_track,  # Sintetizador como carrier
                'modulator': vocal_track,  # Vocal como modulador
            },
            'carrier_config': {
                'waveform': 'saw',
                'filter': 'lowpass',
                'cutoff': 8000,
            }
        }

    # =========================================================================
    # T077: Phaser on Hi-Hats
    # =========================================================================

    def create_phaser_hihats(
        self,
        track_index: int,
        bar_positions: List[int],
        sweep_duration: int = 8,
        stages: int = 6
    ) -> Dict[str, Any]:
        """
        T077: Phaser en hi-hats con sweeps de 8 compases.
        
        Args:
            bar_positions: Barras donde aplicar el sweep
            stages: 2, 4, 6, 8, 12
        """
        sweeps = []
        
        for start_bar in bar_positions:
            points = []
            for i in range(sweep_duration * 4 + 1):  # Cada 1/4 beat
                t = (start_bar * 4) + (i / 4.0)
                progress = i / (sweep_duration * 4)
                
                # Sweep de frecuencia
                freq = 100 + (progress * 8000)  # 100Hz -> 8kHz
                
                points.append({
                    'time': t,
                    'frequency': freq,
                    'feedback': 0.5 + (progress * 0.4),  # 0.5 -> 0.9
                })
            
            sweeps.append({
                'start_bar': start_bar,
                'points': points,
            })

        return {
            'effect': 'phaser_hihats',
            'track_index': track_index,
            'device': 'Phaser',
            'params': {
                'Stages': stages,
                'Color': 'Modern',
                'Dry/Wet': 0.3,
            },
            'sweeps': sweeps,
            'automation_param': 'Frequency',
        }

    # =========================================================================
    # T078: Saturation Drive
    # =========================================================================

    def create_saturation_drive(
        self,
        track_index: int,
        drive_db: float = 2.0,
        target: str = "master"
    ) -> Dict[str, Any]:
        """
        T078: Saturación en master bus (+2dB drive típico).
        
        Args:
            drive_db: Drive en dB (1-10)
            target: 'master', 'drums', 'bass', 'music'
        """
        # Mapeo de dB a valor de drive de Saturator
        drive_value = max(0.5, drive_db)

        configs = {
            'master': {
                'drive': drive_value,
                'color': 0.4,
                'dry_wet': 0.25,
                'type': 'Soft Sine',
            },
            'drums': {
                'drive': drive_value * 1.5,
                'color': 0.5,
                'dry_wet': 0.3,
                'type': 'Medium Curve',
            },
            'bass': {
                'drive': drive_value * 1.2,
                'color': 0.3,
                'dry_wet': 0.35,
                'type': 'Soft Sine',
            },
            'music': {
                'drive': drive_value * 0.8,
                'color': 0.5,
                'dry_wet': 0.2,
                'type': 'Warm Curve',
            },
        }

        config = configs.get(target, configs['master'])

        return {
            'effect': 'saturation_drive',
            'track_index': track_index,
            'target': target,
            'drive_db': drive_db,
            'device': 'Saturator',
            'params': {
                'Drive': config['drive'],
                'Color': config['color'],
                'Dry/Wet': config['dry_wet'],
                'Type': config['type'],
            },
            'post_gain': -1.0,  # Compensar ganancia
        }

    # =========================================================================
    # T079: Auto-Pan Rhythms
    # =========================================================================

    def create_autopan_rhythm(
        self,
        track_index: int,
        rhythm: str = "triplets",
        rate_hz: float = None
    ) -> Dict[str, Any]:
        """
        T079: Auto-pan con ritmos en 1/8 triplet.
        
        Args:
            rhythm: 'straight', 'triplets', 'dotted', 'random'
            rate_hz: Rate en Hz (None = sync)
        """
        # Rates en 1/4 notes
        rates = {
            'straight': 0.125,    # 1/32 = 1/8 triplet feel
            'triplets': 0.083,    # 1/48 = triplets
            'dotted': 0.1875,     # 1/16 dotted
            'random': None,       # Generado
        }

        rate = rates.get(rhythm, 0.083)
        
        if rhythm == 'random' or rate is None:
            rate = self.rng.uniform(0.05, 0.2)

        return {
            'effect': 'autopan_rhythm',
            'track_index': track_index,
            'rhythm': rhythm,
            'device': 'AutoPan',
            'params': {
                'Amount': 0.6,
                'Rate': rate,
                'Phase': 180,  # 180° para ping-pong
                'Waveform': 'Sine',
                'Sync': 1 if rate_hz is None else 0,
            },
            'automation': [
                # Amount varía por sección
                {'section': 'intro', 'amount': 0.3},
                {'section': 'build', 'amount': 0.5},
                {'section': 'drop', 'amount': 0.4},
                {'section': 'break', 'amount': 0.7},
            ]
        }

    # =========================================================================
    # T080: Integration Test - FX-heavy medley
    # =========================================================================

    def create_fx_medley_test(
        self,
        bpm: int = 128,
        key: str = "Am"
    ) -> Dict[str, Any]:
        """
        T080: Test medley con todas las cadenas de FX.
        Crea una configuración completa de FX para testeo.
        """
        medley = {
            'name': 'FX Medley Test',
            'bpm': bpm,
            'key': key,
            'duration_bars': 64,
            'sections': [
                {'name': 'intro', 'bars': (0, 8), 'fx': ['vinyl', 'filter']},
                {'name': 'build_a', 'bars': (8, 16), 'fx': ['beatmasher', 'redox']},
                {'name': 'drop_a', 'bars': (16, 32), 'fx': ['sub_bass', 'saturation']},
                {'name': 'break', 'bars': (32, 40), 'fx': ['freeze', 'gater']},
                {'name': 'build_b', 'bars': (40, 48), 'fx': ['tape_stop', 'flanger']},
                {'name': 'drop_b', 'bars': (48, 64), 'fx': ['phaser', 'chorus']},
            ],
            'tracks': [
                {
                    'role': 'drums',
                    'fx_chain': [
                        self.create_beatmasher_automation(0, 0, pattern='build'),
                        self.create_transient_shaper(0, 'kick', 3.0, -2.0),
                        self.create_saturation_drive(0, 2.0, 'drums'),
                    ]
                },
                {
                    'role': 'bass',
                    'fx_chain': [
                        self.create_resonance_automation(1, [(16, 32), (48, 64)]),
                        self.create_sub_bass_synth(1, key, 'dive', [16, 48]),
                    ]
                },
                {
                    'role': 'music',
                    'fx_chain': [
                        self.create_flanger_sweep(2, 40, 8, 'syncopated'),
                        self.create_chorus_widening(2, 'music_bus', 1.3),
                        self.create_phaser_hihats(2, [16, 48], 8, 6),
                    ]
                },
                {
                    'role': 'master',
                    'fx_chain': [
                        self.create_master_filter_sweep(32, 4, 'lowpass_down'),
                        self.create_saturation_drive(-1, 2.0, 'master'),  # -1 = master
                    ]
                },
                {
                    'role': 'returns',
                    'fx_chain': [
                        self.create_dj_send_strategy(4),
                    ]
                },
            ],
            'transitions': [
                {
                    'from': 'build_a',
                    'to': 'drop_a',
                    'fx': self.create_tape_stop_automation(0, 64, 2.0, -12),
                },
                {
                    'from': 'break',
                    'to': 'build_b',
                    'fx': self.create_gater_effect(2, 'build', '1/16', 0.9),
                },
            ],
        }

        return medley

    # =========================================================================
    # Utilidades de aplicación
    # =========================================================================

    def get_all_fx_configs(self) -> Dict[str, Any]:
        """Retorna todas las configuraciones de FX disponibles."""
        return {
            'T061_dj_rack_standard': self.create_dj_rack_config('standard'),
            'T061_dj_rack_extended': self.create_dj_rack_config('extended'),
            'T066_send_return_4': self.create_dj_send_strategy(4),
            'T066_send_return_2': self.create_dj_send_strategy(2),
        }

    def apply_fx_to_track(
        self,
        track_index: int,
        fx_config: Dict[str, Any],
        ableton_runtime=None
    ) -> Dict[str, Any]:
        """
        Aplica una configuración de FX a un track usando Live API.
        
        Args:
            track_index: Índice del track
            fx_config: Configuración de FX a aplicar
            ableton_runtime: Instancia del runtime de Ableton
        """
        if ableton_runtime is None:
            return {
                'status': 'error',
                'message': 'No Ableton runtime provided',
            }

        results = []
        
        # Aplicar dispositivos
        for device in fx_config.get('chain', []):
            device_type = device.get('type')
            params = device.get('params', {})
            
            try:
                # Cargar dispositivo
                result = ableton_runtime._load_device(track_index, device_type)
                results.append({
                    'device': device_type,
                    'status': 'loaded',
                    'result': result,
                })
                
                # Configurar parámetros
                device_index = result.get('device_index', -1)
                if device_index >= 0:
                    for param_name, value in params.items():
                        try:
                            ableton_runtime._set_device_parameter(
                                track_index, device_index, param_name, value
                            )
                        except Exception as e:
                            results.append({
                                'device': device_type,
                                'param': param_name,
                                'error': str(e),
                            })
            except Exception as e:
                results.append({
                    'device': device_type,
                    'status': 'error',
                    'error': str(e),
                })

        return {
            'status': 'success',
            'track_index': track_index,
            'devices_applied': len(results),
            'results': results,
        }


# Instancia global del engine
_fx_engine: Optional[FXAutomationEngine] = None


def get_fx_engine(seed: int = 42) -> FXAutomationEngine:
    """Obtiene o crea la instancia global del FX engine."""
    global _fx_engine
    if _fx_engine is None:
        _fx_engine = FXAutomationEngine(seed)
    return _fx_engine


# Alias para compatibilidad
FXAutomationPro = FXAutomationEngine


if __name__ == "__main__":
    # Test básico del engine
    engine = FXAutomationEngine(seed=42)
    
    print("=== FX Automation Pro - T061-T080 Tests ===\n")
    
    # T061
    print("T061: DJ Rack Config")
    rack = engine.create_dj_rack_config('extended')
    print(f"  Rack: {rack.name}")
    print(f"  Devices: {len(rack.devices)}")
    print(f"  Macros: {[m.name for m in rack.macros]}\n")
    
    # T062
    print("T062: BeatMasher Automation")
    bm = engine.create_beatmasher_automation(0, 0, 'quarter_eighth', 0.8)
    print(f"  Pattern: {bm['pattern']}")
    print(f"  Points: {len(bm['points'])}\n")
    
    # T063
    print("T063: Tape Stop")
    ts = engine.create_tape_stop_automation(0, 64, 4, -12)
    print(f"  Duration: {ts['duration']} beats")
    print(f"  Pitch range: {ts['pitch_range']} semitones\n")
    
    # T064
    print("T064: Gater Effect")
    gater = engine.create_gater_effect(0, 'sixteenth', '1/16', 0.8)
    print(f"  Pattern: {gater['pattern']}")
    print(f"  Rate: {gater['rate']}\n")
    
    # T065
    print("T065: Flanger Sweep")
    flanger = engine.create_flanger_sweep(0, 8, 4, 'syncopated')
    print(f"  Rate: {flanger['rate']}")
    print(f"  Points: {len(flanger['automation_points'])}\n")
    
    # T066
    print("T066: Send/Return Strategy")
    sends = engine.create_dj_send_strategy(4)
    print(f"  Returns: {len(sends['returns'])}")
    for ret in sends['returns']:
        print(f"    - {ret['name']}")
    print()
    
    # T067
    print("T067: Master Filter Sweep")
    sweep = engine.create_master_filter_sweep(16, 8, 'lowpass_down')
    print(f"  Type: {sweep['sweep_type']}")
    print(f"  Points: {len(sweep['automation_points'])}\n")
    
    # T068
    print("T068: Ping-Pong Throws")
    throws = engine.create_pingpong_throws(5, [16, 24, 32], 0.4, True)
    print(f"  Throws: {len(throws['throws'])}")
    print(f"  Delay time: {throws['delay_time']}\n")
    
    # T069
    print("T069: Redux Build")
    redux = engine.create_redux_build(0, 8, 16, 16, 4)
    print(f"  Bits: 16 -> 4")
    print(f"  Points: {len(redux['automation_points'])}\n")
    
    # T070
    print("T070: Resonance Riding")
    res = engine.create_resonance_automation(1, [(0, 16), (16, 32)], 'energy')
    print(f"  Sections: 2")
    print(f"  Points: {len(res['automation_points'])}\n")
    
    # T071
    print("T071: Vinyl Overlay")
    vinyl = engine.create_vinyl_overlay(0, 'medium')
    print(f"  Intensity: {vinyl['intensity']}")
    print(f"  Crackle: {vinyl['params']['Crackle']}\n")
    
    # T072
    print("T072: Chorus Widening")
    chorus = engine.create_chorus_widening(2, 'music_bus', 1.2)
    print(f"  Target: {chorus['target']}")
    print(f"  Width: {chorus['width']}\n")
    
    # T073
    print("T073: Sub-Bass Synth")
    sub = engine.create_sub_bass_synth(1, 'Am', 'dive', [16, 48])
    print(f"  Key: {sub['key']}")
    print(f"  Pattern: {sub['pattern']}")
    print(f"  Triggers: {sub['trigger_bars']}\n")
    
    # T074
    print("T074: Transient Shaper")
    trans = engine.create_transient_shaper(0, 'kick', 3.0, -2.0)
    print(f"  Focus: {trans['band_focus']}")
    print(f"  Bands: {len(trans['config']['bands'])}\n")
    
    # T075
    print("T075: Freeze FX")
    freeze = engine.create_freeze_effect(2, 32, 2, 'reverb')
    print(f"  Source: {freeze['source']}")
    print(f"  Bar: {freeze['freeze_bar']}\n")
    
    # T076
    print("T076: Vocoder Setup")
    vocoder = engine.create_vocoder_setup(8, 9, 20)
    print(f"  Bands: {vocoder['params']['Bands']}")
    print(f"  Vocal track: {vocoder['vocoder_track']}")
    print(f"  Synth track: {vocoder['carrier_track']}\n")
    
    # T077
    print("T077: Phaser Hi-Hats")
    phaser = engine.create_phaser_hihats(3, [16, 48], 8, 6)
    print(f"  Stages: {phaser['params']['Stages']}")
    print(f"  Sweeps: {len(phaser['sweeps'])}\n")
    
    # T078
    print("T078: Saturation Drive")
    sat = engine.create_saturation_drive(-1, 2.0, 'master')
    print(f"  Target: {sat['target']}")
    print(f"  Drive: {sat['params']['Drive']} dB\n")
    
    # T079
    print("T079: Auto-Pan Rhythm")
    pan = engine.create_autopan_rhythm(4, 'triplets')
    print(f"  Rhythm: {pan['rhythm']}")
    print(f"  Rate: {pan['params']['Rate']}\n")
    
    # T080
    print("T080: FX Medley Test")
    medley = engine.create_fx_medley_test(128, 'Am')
    print(f"  Sections: {len(medley['sections'])}")
    print(f"  Tracks: {len(medley['tracks'])}")
    print(f"  Transitions: {len(medley['transitions'])}\n")
    
    print("=== All T061-T080 tests completed successfully ===")
