"""
DJ Structure Engine - Professional DJ Extended and Radio Edit song structures.

This engine generates professional song structures optimized for DJ mixing and radio play.
"""

from typing import Dict, List, Optional


class DJStructureEngine:
    """
    Generates professional DJ Extended and Radio Edit song structures.
    
    Creates song arrangements optimized for:
    - DJ Extended: Long intros/outros for mixing, extended breaks
    - Radio Edit: Compact structure, immediate hook, no long intros
    """
    
    def __init__(self, bpm: int = 95):
        """
        Initialize the DJ Structure Engine.
        
        Args:
            bpm: Beats per minute for the track (default 95 for reggaeton)
        """
        self.bpm = bpm
        self.beats_per_bar = 4
        
    def generate_dj_extended_structure(self, duration_minutes: float = 6.5) -> Dict:
        """
        Generate a professional DJ Extended structure (160 bars).
        
        Optimized for DJ mixing with long intros/outros and extended mix section.
        
        Args:
            duration_minutes: Target duration in minutes (default 6.5)
            
        Returns:
            Dict with complete structure definition
        """
        structure = {
            "type": "dj_extended",
            "bpm": self.bpm,
            "target_duration_minutes": duration_minutes,
            "total_bars": 160,
            "estimated_duration": self._bars_to_minutes(160),
            "sections": [
                {
                    "name": "Intro",
                    "type": "intro",
                    "bars": 24,
                    "description": "Ambience build for DJ mixing",
                    "energy_level": 0.2,
                    "elements": ["ambience", "fx", "minimal_drums"]
                },
                {
                    "name": "Break 1",
                    "type": "break",
                    "bars": 16,
                    "description": "Minimal drums section",
                    "energy_level": 0.4,
                    "elements": ["drums", "bass", "minimal_synth"]
                },
                {
                    "name": "Build 1",
                    "type": "build",
                    "bars": 8,
                    "description": "Rising energy with riser",
                    "energy_level": 0.7,
                    "elements": ["drums", "bass", "riser", "sweep"]
                },
                {
                    "name": "Drop 1",
                    "type": "drop",
                    "bars": 16,
                    "description": "Full energy drop",
                    "energy_level": 1.0,
                    "elements": ["drums", "bass", "chords", "melody", "fx"]
                },
                {
                    "name": "Break 2",
                    "type": "break",
                    "bars": 16,
                    "description": "Melodic breakdown section",
                    "energy_level": 0.5,
                    "elements": ["minimal_drums", "bass", "chords", "melody"]
                },
                {
                    "name": "Build 2",
                    "type": "build",
                    "bars": 8,
                    "description": "Second riser build",
                    "energy_level": 0.75,
                    "elements": ["drums", "bass", "riser", "sweep", "snare_roll"]
                },
                {
                    "name": "Drop 2",
                    "type": "drop",
                    "bars": 16,
                    "description": "Variation drop",
                    "energy_level": 1.0,
                    "elements": ["drums", "bass", "chords", "melody_variation", "fx"]
                },
                {
                    "name": "Extended Mix",
                    "type": "extended",
                    "bars": 64,
                    "description": "DJ mixing section with variations",
                    "energy_level": 0.9,
                    "elements": ["drums", "bass", "chords", "melody", "vocal_chops", "fx"]
                },
                {
                    "name": "Outro",
                    "type": "outro",
                    "bars": 16,
                    "description": "Fade out for DJ mixing",
                    "energy_level": 0.3,
                    "elements": ["drums", "bass_fade", "ambience"]
                }
            ]
        }
        
        return structure
    
    def generate_radio_edit_structure(self, duration_minutes: float = 4.0) -> Dict:
        """
        Generate a professional Radio Edit structure (96 bars).
        
        Optimized for radio play with immediate hook and compact structure.
        
        Args:
            duration_minutes: Target duration in minutes (default 4.0)
            
        Returns:
            Dict with complete structure definition
        """
        structure = {
            "type": "radio_edit",
            "bpm": self.bpm,
            "target_duration_minutes": duration_minutes,
            "total_bars": 96,
            "estimated_duration": self._bars_to_minutes(96),
            "sections": [
                {
                    "name": "Intro",
                    "type": "intro",
                    "bars": 8,
                    "description": "Quick intro to hook",
                    "energy_level": 0.3,
                    "elements": ["hook_preview", "minimal_drums"]
                },
                {
                    "name": "Verse 1",
                    "type": "verse",
                    "bars": 16,
                    "description": "First verse with full groove",
                    "energy_level": 0.6,
                    "elements": ["drums", "bass", "chords", "verse_melody"]
                },
                {
                    "name": "Pre-Chorus",
                    "type": "pre_chorus",
                    "bars": 8,
                    "description": "Build to chorus",
                    "energy_level": 0.75,
                    "elements": ["drums", "bass", "building_chords", "riser"]
                },
                {
                    "name": "Chorus 1",
                    "type": "chorus",
                    "bars": 16,
                    "description": "Main hook/chorus",
                    "energy_level": 1.0,
                    "elements": ["drums", "bass", "chords", "hook_melody", "fx"]
                },
                {
                    "name": "Verse 2",
                    "type": "verse",
                    "bars": 16,
                    "description": "Second verse with variation",
                    "energy_level": 0.6,
                    "elements": ["drums", "bass", "chords", "verse_melody_variation"]
                },
                {
                    "name": "Pre-Chorus 2",
                    "type": "pre_chorus",
                    "bars": 8,
                    "description": "Build to final chorus",
                    "energy_level": 0.8,
                    "elements": ["drums", "bass", "building_chords", "riser", "sweep"]
                },
                {
                    "name": "Chorus 2",
                    "type": "chorus",
                    "bars": 16,
                    "description": "Final chorus with impact",
                    "energy_level": 1.0,
                    "elements": ["drums", "bass", "chords", "hook_melody", "impact", "fx"]
                },
                {
                    "name": "Outro",
                    "type": "outro",
                    "bars": 8,
                    "description": "Quick fade out",
                    "energy_level": 0.4,
                    "elements": ["drums", "bass_fade"]
                }
            ]
        }
        
        return structure
    
    def calculate_section_positions(self, structure: Dict) -> List[Dict]:
        """
        Calculate bar positions for each section in the structure.
        
        Args:
            structure: Structure dict from generate_*_structure methods
            
        Returns:
            List of dicts with section positions
        """
        positions = []
        current_bar = 0
        
        for section in structure["sections"]:
            section_info = {
                "name": section["name"],
                "type": section["type"],
                "start_bar": current_bar,
                "end_bar": current_bar + section["bars"],
                "duration_bars": section["bars"],
                "start_time": self._bars_to_beats(current_bar),
                "end_time": self._bars_to_beats(current_bar + section["bars"]),
                "energy_level": section["energy_level"],
                "elements": section["elements"]
            }
            positions.append(section_info)
            current_bar += section["bars"]
        
        return positions
    
    def get_elements_for_section(self, section_type: str) -> List[str]:
        """
        Get the recommended elements for a specific section type.
        
        Args:
            section_type: Type of section (intro, verse, chorus, build, drop, etc.)
            
        Returns:
            List of element names that should be active
        """
        element_map = {
            "intro": ["ambience", "fx", "minimal_drums", "fade_in"],
            "verse": ["drums", "bass", "chords", "verse_melody"],
            "pre_chorus": ["drums", "bass", "building_chords", "riser"],
            "chorus": ["drums", "bass", "chords", "hook_melody", "fx", "impact"],
            "build": ["drums", "bass", "riser", "sweep", "snare_roll"],
            "drop": ["drums", "bass", "chords", "melody", "fx", "full_energy"],
            "break": ["minimal_drums", "bass", "chords", "melody"],
            "extended": ["drums", "bass", "chords", "melody", "vocal_chops", "fx"],
            "outro": ["drums", "bass_fade", "ambience", "fade_out"]
        }
        
        return element_map.get(section_type, ["drums", "bass"])
    
    def _bars_to_minutes(self, bars: int) -> float:
        """
        Convert bars to minutes based on BPM.
        
        Args:
            bars: Number of bars
            
        Returns:
            Duration in minutes
        """
        beats = bars * self.beats_per_bar
        minutes = beats / self.bpm
        return round(minutes, 2)
    
    def _bars_to_beats(self, bars: int) -> float:
        """
        Convert bars to beats.
        
        Args:
            bars: Number of bars
            
        Returns:
            Number of beats
        """
        return bars * self.beats_per_bar
    
    def generate_custom_structure(
        self,
        section_configs: List[Dict],
        target_duration: Optional[float] = None
    ) -> Dict:
        """
        Generate a custom structure from section configurations.
        
        Args:
            section_configs: List of dicts with 'name', 'type', 'bars', 'energy_level'
            target_duration: Optional target duration in minutes
            
        Returns:
            Dict with complete custom structure
        """
        total_bars = sum(cfg.get("bars", 8) for cfg in section_configs)
        
        structure = {
            "type": "custom",
            "bpm": self.bpm,
            "target_duration_minutes": target_duration,
            "total_bars": total_bars,
            "estimated_duration": self._bars_to_minutes(total_bars),
            "sections": []
        }
        
        for cfg in section_configs:
            section = {
                "name": cfg.get("name", "Section"),
                "type": cfg.get("type", "break"),
                "bars": cfg.get("bars", 8),
                "description": cfg.get("description", ""),
                "energy_level": cfg.get("energy_level", 0.5),
                "elements": self.get_elements_for_section(cfg.get("type", "break"))
            }
            structure["sections"].append(section)
        
        return structure
    
    def get_structure_summary(self, structure: Dict) -> str:
        """
        Get a human-readable summary of a structure.
        
        Args:
            structure: Structure dict
            
        Returns:
            Formatted string summary
        """
        lines = [
            f"Structure: {structure['type']}",
            f"BPM: {structure['bpm']}",
            f"Total Bars: {structure['total_bars']}",
            f"Estimated Duration: {structure['estimated_duration']} minutes",
            "",
            "Sections:",
            "-" * 50
        ]
        
        positions = self.calculate_section_positions(structure)
        for pos in positions:
            lines.append(
                f"  {pos['name']:20} | Bars {pos['start_bar']:3}-{pos['end_bar']:<3} | "
                f"Energy: {pos['energy_level']:.1f}"
            )
        
        lines.append("-" * 50)
        return "\n".join(lines)


# Convenience functions for quick access
def create_dj_extended_structure(bpm: int = 95, duration_minutes: float = 6.5) -> Dict:
    """Quick function to create DJ Extended structure."""
    engine = DJStructureEngine(bpm)
    return engine.generate_dj_extended_structure(duration_minutes)


def create_radio_edit_structure(bpm: int = 95, duration_minutes: float = 4.0) -> Dict:
    """Quick function to create Radio Edit structure."""
    engine = DJStructureEngine(bpm)
    return engine.generate_radio_edit_structure(duration_minutes)
