"""
Section Automation Engine - Applies REAL automation to sections.

This engine provides filter sweeps, volume ramps, sidechain setup,
and reverb sends for different song sections.
"""

from typing import Dict, List, Optional, Any, Callable
import math


class SectionAutomation:
    """Applies automation effects to song sections."""
    
    def __init__(self, live_bridge):
        """
        Initialize with LiveBridge for direct Ableton control.
        
        Args:
            live_bridge: LiveBridge instance for Ableton API calls
        """
        self.live_bridge = live_bridge
        self._curve_functions = {
            "linear": self._linear_curve,
            "exponential": self._exponential_curve,
            "logarithmic": self._logarithmic_curve,
            "s_curve": self._s_curve,
            "step": self._step_curve
        }
    
    def _linear_curve(self, t: float) -> float:
        """Linear interpolation."""
        return t
    
    def _exponential_curve(self, t: float) -> float:
        """Exponential curve for filter sweeps (faster at start)."""
        return t * t
    
    def _logarithmic_curve(self, t: float) -> float:
        """Logarithmic curve (slower at start)."""
        return math.sqrt(t)
    
    def _s_curve(self, t: float) -> float:
        """S-curve (ease in-out)."""
        return 3 * t * t - 2 * t * t * t
    
    def _step_curve(self, t: float) -> float:
        """Step function (immediate change)."""
        return 1.0 if t >= 0.5 else 0.0
    
    def _generate_automation_points(
        self,
        start_value: float,
        end_value: float,
        start_bar: float,
        end_bar: float,
        curve: str = "linear",
        steps: int = 8
    ) -> List[List[float]]:
        """
        Generate automation points with curve interpolation.
        
        Args:
            start_value: Starting parameter value
            end_value: Ending parameter value
            start_bar: Starting bar position
            end_bar: Ending bar position
            curve: Curve type (linear, exponential, logarithmic, s_curve, step)
            steps: Number of automation points
            
        Returns:
            List of [time, value] pairs
        """
        curve_func = self._curve_functions.get(curve, self._linear_curve)
        points = []
        
        duration = end_bar - start_bar
        
        for i in range(steps + 1):
            t = i / steps
            curved_t = curve_func(t)
            
            time = start_bar + (duration * t)
            value = start_value + (end_value - start_value) * curved_t
            
            points.append([time, value])
        
        return points
    
    def apply_filter_sweep(
        self,
        track_index: int,
        start_bar: float,
        end_bar: float,
        start_freq: float,
        end_freq: float,
        curve: str = "exponential"
    ) -> Dict:
        """
        Apply filter frequency sweep automation.
        
        Args:
            track_index: Target track index
            start_bar: Starting bar position
            end_bar: Ending bar position
            start_freq: Starting frequency in Hz (e.g., 200)
            end_freq: Ending frequency in Hz (e.g., 20000)
            curve: Curve type for the sweep
            
        Returns:
            Dict with status and automation details
        """
        try:
            # Generate exponential frequency points for smoother sweep
            if curve == "exponential":
                # Convert to log scale for exponential sweep
                import math
                log_start = math.log10(start_freq)
                log_end = math.log10(end_freq)
                
                points = []
                steps = 16
                for i in range(steps + 1):
                    t = i / steps
                    log_freq = log_start + (log_end - log_start) * (t * t)
                    freq = 10 ** log_freq
                    time = start_bar + (end_bar - start_bar) * t
                    points.append([time, freq])
            else:
                points = self._generate_automation_points(
                    start_freq, end_freq, start_bar, end_bar, curve, steps=16
                )
            
            # Apply automation via LiveBridge
            result = self.live_bridge.add_parameter_automation(
                track_index=track_index,
                parameter_name="Frequency",
                device_name="Auto Filter",
                clip_index=0,
                points=points
            )
            
            return {
                "status": "success",
                "track_index": track_index,
                "automation_type": "filter_sweep",
                "start_bar": start_bar,
                "end_bar": end_bar,
                "start_freq": start_freq,
                "end_freq": end_freq,
                "curve": curve,
                "points_count": len(points),
                "live_result": result
            }
            
        except Exception as e:
            return {
                "status": "error",
                "track_index": track_index,
                "automation_type": "filter_sweep",
                "error": str(e)
            }
    
    def apply_volume_ramp(
        self,
        track_index: int,
        start_bar: float,
        end_bar: float,
        start_vol: float,
        end_vol: float,
        curve: str = "linear"
    ) -> Dict:
        """
        Apply volume ramp automation.
        
        Args:
            track_index: Target track index
            start_bar: Starting bar position
            end_bar: Ending bar position
            start_vol: Starting volume (0.0 - 1.0, or dB value)
            end_vol: Ending volume (0.0 - 1.0, or dB value)
            curve: Curve type for the ramp
            
        Returns:
            Dict with status and automation details
        """
        try:
            points = self._generate_automation_points(
                start_vol, end_vol, start_bar, end_bar, curve, steps=8
            )
            
            # Apply automation via LiveBridge
            result = self.live_bridge.add_parameter_automation(
                track_index=track_index,
                parameter_name="volume",
                points=points
            )
            
            return {
                "status": "success",
                "track_index": track_index,
                "automation_type": "volume_ramp",
                "start_bar": start_bar,
                "end_bar": end_bar,
                "start_vol": start_vol,
                "end_vol": end_vol,
                "curve": curve,
                "points_count": len(points),
                "live_result": result
            }
            
        except Exception as e:
            return {
                "status": "error",
                "track_index": track_index,
                "automation_type": "volume_ramp",
                "error": str(e)
            }
    
    def apply_sidechain_setup(
        self,
        source_track: int,
        target_track: int,
        amount: float = 0.7
    ) -> Dict:
        """
        Setup sidechain compression from source to target track.
        
        Args:
            source_track: Track index providing the sidechain trigger (e.g., kick)
            target_track: Track index receiving sidechain compression (e.g., bass)
            amount: Sidechain amount (0.0 - 1.0)
            
        Returns:
            Dict with status and setup details
        """
        try:
            result = self.live_bridge.setup_sidechain(
                source_track=source_track,
                target_track=target_track,
                amount=amount
            )
            
            return {
                "status": "success",
                "source_track": source_track,
                "target_track": target_track,
                "amount": amount,
                "live_result": result
            }
            
        except Exception as e:
            return {
                "status": "error",
                "source_track": source_track,
                "target_track": target_track,
                "error": str(e)
            }
    
    def apply_reverb_send(
        self,
        track_index: int,
        send_index: int,
        start_bar: float,
        end_bar: float,
        start_wet: float,
        end_wet: float
    ) -> Dict:
        """
        Apply reverb send amount automation.
        
        Args:
            track_index: Target track index
            send_index: Return track index for reverb
            start_bar: Starting bar position
            end_bar: Ending bar position
            start_wet: Starting send amount (0.0 - 1.0)
            end_wet: Ending send amount (0.0 - 1.0)
            
        Returns:
            Dict with status and automation details
        """
        try:
            points = self._generate_automation_points(
                start_wet, end_wet, start_bar, end_bar, "s_curve", steps=6
            )
            
            # Apply automation via LiveBridge
            result = self.live_bridge.add_parameter_automation(
                track_index=track_index,
                parameter_name="send",
                send_index=send_index,
                points=points
            )
            
            return {
                "status": "success",
                "track_index": track_index,
                "send_index": send_index,
                "automation_type": "reverb_send",
                "start_bar": start_bar,
                "end_bar": end_bar,
                "start_wet": start_wet,
                "end_wet": end_wet,
                "points_count": len(points),
                "live_result": result
            }
            
        except Exception as e:
            return {
                "status": "error",
                "track_index": track_index,
                "automation_type": "reverb_send",
                "error": str(e)
            }
    
    def apply_section_package(
        self,
        section_type: str,
        track_indices: Dict[str, int],
        start_bar: float,
        end_bar: float
    ) -> Dict:
        """
        Apply all relevant automations for a song section.
        
        Args:
            section_type: Type of section (intro, build, chorus, outro, etc.)
            track_indices: Dict mapping track roles to indices
                e.g., {"bass": 1, "master": -1, "drums": 0, "chords": 2}
            start_bar: Section start position
            end_bar: Section end position
            
        Returns:
            Dict with all applied automations
        """
        results = {
            "status": "success",
            "section_type": section_type,
            "start_bar": start_bar,
            "end_bar": end_bar,
            "automations": []
        }
        
        section_type = section_type.lower()
        
        if section_type == "intro":
            # Intro: Filter sweep up on bass, volume ramp up
            if "bass" in track_indices:
                # Filter sweep from 200Hz to 800Hz
                result = self.apply_filter_sweep(
                    track_index=track_indices["bass"],
                    start_bar=start_bar,
                    end_bar=end_bar,
                    start_freq=200,
                    end_freq=800,
                    curve="exponential"
                )
                results["automations"].append(result)
            
            # Volume ramp up on master
            if "master" in track_indices:
                result = self.apply_volume_ramp(
                    track_index=track_indices["master"],
                    start_bar=start_bar,
                    end_bar=end_bar,
                    start_vol=0.3,
                    end_vol=0.85,
                    curve="logarithmic"
                )
                results["automations"].append(result)
        
        elif section_type in ["build", "buildup"]:
            # Build: Filter sweep up on master, reverb increase
            if "master" in track_indices:
                result = self.apply_filter_sweep(
                    track_index=track_indices["master"],
                    start_bar=start_bar,
                    end_bar=end_bar,
                    start_freq=1000,
                    end_freq=18000,
                    curve="exponential"
                )
                results["automations"].append(result)
            
            # Reverb send increase on melodic elements
            if "chords" in track_indices and "reverb_return" in track_indices:
                result = self.apply_reverb_send(
                    track_index=track_indices["chords"],
                    send_index=track_indices["reverb_return"],
                    start_bar=start_bar,
                    end_bar=end_bar,
                    start_wet=0.1,
                    end_wet=0.5
                )
                results["automations"].append(result)
            
            # Subtle volume ramp up for tension
            if "drums" in track_indices:
                result = self.apply_volume_ramp(
                    track_index=track_indices["drums"],
                    start_bar=start_bar,
                    end_bar=end_bar - (end_bar - start_bar) * 0.25,  # End before drop
                    start_vol=0.8,
                    end_vol=1.0,
                    curve="linear"
                )
                results["automations"].append(result)
        
        elif section_type in ["chorus", "drop", "hook"]:
            # Chorus: Filter open, volume boost
            if "master" in track_indices:
                # Ensure filter is fully open
                result = self.apply_filter_sweep(
                    track_index=track_indices["master"],
                    start_bar=start_bar,
                    end_bar=start_bar + 0.5,  # Quick open
                    start_freq=5000,
                    end_freq=20000,
                    curve="linear"
                )
                results["automations"].append(result)
            
            # Volume boost for impact
            if "bass" in track_indices:
                result = self.apply_volume_ramp(
                    track_index=track_indices["bass"],
                    start_bar=start_bar,
                    end_bar=start_bar + 0.25,  # Immediate boost
                    start_vol=0.7,
                    end_vol=0.95,
                    curve="linear"
                )
                results["automations"].append(result)
            
            # Set reverb to moderate for space
            if "chords" in track_indices and "reverb_return" in track_indices:
                result = self.apply_reverb_send(
                    track_index=track_indices["chords"],
                    send_index=track_indices["reverb_return"],
                    start_bar=start_bar,
                    end_bar=start_bar + 0.5,
                    start_wet=0.3,
                    end_wet=0.25
                )
                results["automations"].append(result)
        
        elif section_type in ["outro", "fade"]:
            # Outro: Filter sweep down, volume fade
            if "master" in track_indices:
                result = self.apply_filter_sweep(
                    track_index=track_indices["master"],
                    start_bar=start_bar,
                    end_bar=end_bar,
                    start_freq=20000,
                    end_freq=500,
                    curve="logarithmic"
                )
                results["automations"].append(result)
            
            # Volume fade out
            result = self.apply_volume_ramp(
                track_index=track_indices.get("master", 0),
                start_bar=start_bar + (end_bar - start_bar) * 0.25,
                end_bar=end_bar,
                start_vol=0.85,
                end_vol=0.0,
                curve="logarithmic"
            )
            results["automations"].append(result)
            
            # Reduce reverb
            if "reverb_return" in track_indices:
                result = self.apply_reverb_send(
                    track_index=track_indices.get("chords", 0),
                    send_index=track_indices["reverb_return"],
                    start_bar=start_bar,
                    end_bar=end_bar,
                    start_wet=0.3,
                    end_wet=0.0
                )
                results["automations"].append(result)
        
        elif section_type == "verse":
            # Verse: Subtle automation for dynamics
            if "bass" in track_indices:
                # Gentle filter modulation
                result = self.apply_filter_sweep(
                    track_index=track_indices["bass"],
                    start_bar=start_bar,
                    end_bar=end_bar,
                    start_freq=400,
                    end_freq=600,
                    curve="s_curve"
                )
                results["automations"].append(result)
            
            # Consistent volume
            if "master" in track_indices:
                result = self.apply_volume_ramp(
                    track_index=track_indices["master"],
                    start_bar=start_bar,
                    end_bar=end_bar,
                    start_vol=0.8,
                    end_vol=0.8,
                    curve="linear"
                )
                results["automations"].append(result)
        
        elif section_type == "bridge":
            # Bridge: Different energy level - filter variation
            if "master" in track_indices:
                result = self.apply_filter_sweep(
                    track_index=track_indices["master"],
                    start_bar=start_bar,
                    end_bar=end_bar,
                    start_freq=3000,
                    end_freq=8000,
                    curve="s_curve"
                )
                results["automations"].append(result)
            
            # Lower volume for contrast
            result = self.apply_volume_ramp(
                track_index=track_indices.get("master", 0),
                start_bar=start_bar,
                end_bar=start_bar + 2,
                start_vol=0.85,
                end_vol=0.7,
                curve="linear"
            )
            results["automations"].append(result)
        
        # Count successful automations
        success_count = sum(1 for a in results["automations"] if a.get("status") == "success")
        results["automation_count"] = len(results["automations"])
        results["success_count"] = success_count
        
        return results
    
    def apply_transition(
        self,
        from_section: str,
        to_section: str,
        transition_bar: float,
        track_indices: Dict[str, int],
        duration_bars: float = 2.0
    ) -> Dict:
        """
        Apply automation for smooth transition between sections.
        
        Args:
            from_section: Current section type
            to_section: Next section type
            transition_bar: Bar where transition occurs
            track_indices: Dict mapping track roles to indices
            duration_bars: Duration of the transition
            
        Returns:
            Dict with transition automation details
        """
        results = {
            "status": "success",
            "from_section": from_section,
            "to_section": to_section,
            "transition_bar": transition_bar,
            "automations": []
        }
        
        # Build to Chorus transition
        if from_section in ["build", "buildup"] and to_section in ["chorus", "drop"]:
            # Reverb swell before drop
            if "reverb_return" in track_indices:
                result = self.apply_reverb_send(
                    track_index=track_indices.get("chords", track_indices.get("master", 0)),
                    send_index=track_indices["reverb_return"],
                    start_bar=transition_bar - duration_bars,
                    end_bar=transition_bar,
                    start_wet=0.2,
                    end_wet=0.6
                )
                results["automations"].append(result)
            
            # Filter open on drop
            if "master" in track_indices:
                result = self.apply_filter_sweep(
                    track_index=track_indices["master"],
                    start_bar=transition_bar - 0.5,
                    end_bar=transition_bar + 0.5,
                    start_freq=5000,
                    end_freq=20000,
                    curve="exponential"
                )
                results["automations"].append(result)
        
        # Chorus to Build transition
        elif from_section in ["chorus", "drop"] and to_section in ["build", "buildup"]:
            # Volume dip for breath
            if "master" in track_indices:
                result = self.apply_volume_ramp(
                    track_index=track_indices["master"],
                    start_bar=transition_bar,
                    end_bar=transition_bar + 1,
                    start_vol=0.9,
                    end_vol=0.7,
                    curve="linear"
                )
                results["automations"].append(result)
        
        # Any to Outro
        elif to_section in ["outro", "fade"]:
            # Start filter sweep down
            if "master" in track_indices:
                result = self.apply_filter_sweep(
                    track_index=track_indices["master"],
                    start_bar=transition_bar,
                    end_bar=transition_bar + duration_bars,
                    start_freq=20000,
                    end_freq=2000,
                    curve="logarithmic"
                )
                results["automations"].append(result)
        
        results["automation_count"] = len(results["automations"])
        return results
