"""
T225: Blueprint Multi-Capas
Sistema de blueprints multi-capa para generaciones complejas
"""

import json
import os
from datetime import datetime
from typing import Dict, List, Any, Optional, Tuple
from dataclasses import dataclass, field
from enum import Enum


class LayerType(Enum):
    """Tipos de capas en el blueprint."""
    DRUMS = "drums"
    BASS = "bass"
    MUSIC = "music"
    FX = "fx"
    VOCAL = "vocal"
    AMBIENCE = "ambience"
    TEXTURE = "texture"
    IMPACT = "impact"


@dataclass
class LayerBlueprint:
    """Blueprint de una capa individual."""
    layer_type: LayerType
    role: str
    intensity: float  # 0.0 - 1.0
    variation_count: int
    clips: List[Dict[str, Any]]
    effects_chain: List[str]
    bus_assignment: str
    

@dataclass
class SectionBlueprint:
    """Blueprint de una sección del track."""
    kind: str  # intro, build, drop, break, outro
    start_bar: int
    end_bar: int
    layers: List[LayerBlueprint]
    transitions: Dict[str, Any]
    energy_level: int
    harmonic_content: Dict[str, Any]


class MultiLayerBlueprint:
    """
    Sistema de blueprints multi-capa para generaciones.
    
    T225: Blueprint con múltiples capas de audio y metadatos.
    """
    
    def __init__(self, genre: str, style: str, bpm: int, key: str):
        self.genre = genre
        self.style = style
        self.bpm = bpm
        self.key = key
        self.session_id = f"bp_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{genre[:3]}"
        
        self.sections: List[SectionBlueprint] = []
        self.audio_layers: List[Dict[str, Any]] = []
        self.resample_layers: List[Dict[str, Any]] = []
        self.buses: Dict[str, Any] = {}
        self.returns: Dict[str, Any] = {}
        
    def build_complete_blueprint(self, structure: str = 'standard') -> Dict[str, Any]:
        """Construye blueprint completo con todas las capas."""
        # Generar estructura de secciones
        self.sections = self._generate_sections(structure)
        
        # Generar capas de audio para cada sección
        self.audio_layers = self._generate_audio_layers()
        
        # Generar capas de resample
        self.resample_layers = self._generate_resample_layers()
        
        # Configurar buses y returns
        self.buses = self._configure_buses()
        self.returns = self._configure_returns()
        
        # Generar variantes por sección
        variants = self._generate_section_variants()
        
        return {
            'session_id': self.session_id,
            'metadata': {
                'genre': self.genre,
                'style': self.style,
                'bpm': self.bpm,
                'key': self.key,
                'structure': structure,
                'created_at': datetime.now().isoformat(),
                'version': '2.0.0'
            },
            'sections': [
                {
                    'kind': s.kind,
                    'start_bar': s.start_bar,
                    'end_bar': s.end_bar,
                    'energy_level': s.energy_level,
                    'layers': [
                        {
                            'type': l.layer_type.value,
                            'role': l.role,
                            'intensity': l.intensity,
                            'variation_count': l.variation_count,
                            'clip_count': len(l.clips)
                        }
                        for l in s.layers
                    ],
                    'transitions': s.transitions,
                    'harmonic_content': s.harmonic_content
                }
                for s in self.sections
            ],
            'audio_layers': self.audio_layers,
            'resample_layers': self.resample_layers,
            'buses': self.buses,
            'returns': self.returns,
            'section_variants': variants,
            'track_blueprint': self._generate_track_blueprint(),
            'mix_blueprint': self._generate_mix_blueprint()
        }
    
    def _generate_sections(self, structure: str) -> List[SectionBlueprint]:
        """Genera secciones según estructura."""
        structure_definitions = {
            'standard': [
                ('intro', 0, 16, 3),
                ('build', 16, 32, 6),
                ('drop', 32, 64, 9),
                ('break', 64, 80, 5),
                ('build', 80, 96, 7),
                ('drop', 96, 128, 10),
                ('outro', 128, 144, 4)
            ],
            'minimal': [
                ('intro', 0, 8, 3),
                ('build', 8, 16, 5),
                ('drop', 16, 48, 8),
                ('outro', 48, 64, 4)
            ],
            'extended': [
                ('intro', 0, 32, 3),
                ('build', 32, 48, 5),
                ('drop', 48, 80, 8),
                ('break', 80, 112, 4),
                ('build', 112, 128, 6),
                ('drop', 128, 176, 9),
                ('break', 176, 192, 5),
                ('build', 192, 208, 7),
                ('drop', 208, 256, 10),
                ('outro', 256, 288, 4)
            ],
            'club': [
                ('intro', 0, 16, 4),
                ('build', 16, 24, 6),
                ('drop', 24, 56, 9),
                ('break', 56, 72, 6),
                ('build', 72, 80, 7),
                ('drop', 80, 112, 10),
                ('outro', 112, 128, 5)
            ]
        }
        
        section_defs = structure_definitions.get(structure, structure_definitions['standard'])
        sections = []
        
        for kind, start, end, energy in section_defs:
            layers = self._generate_layers_for_section(kind, energy)
            
            section = SectionBlueprint(
                kind=kind,
                start_bar=start,
                end_bar=end,
                layers=layers,
                transitions=self._generate_transitions(kind),
                energy_level=energy,
                harmonic_content=self._generate_harmonic_content(kind)
            )
            sections.append(section)
        
        return sections
    
    def _generate_layers_for_section(self, section_kind: str, energy: int) -> List[LayerBlueprint]:
        """Genera capas para una sección específica."""
        layers = []
        
        # Capas base siempre presentes
        layers.append(LayerBlueprint(
            layer_type=LayerType.DRUMS,
            role='kick' if section_kind in ['drop', 'build'] else 'hats',
            intensity=0.8 if section_kind in ['drop', 'build'] else 0.4,
            variation_count=2,
            clips=[{'type': 'audio', 'pattern': '4x4' if section_kind == 'drop' else 'minimal'}],
            effects_chain=['EQ', 'Compression'] if section_kind == 'drop' else ['EQ'],
            bus_assignment='DRUMS_BUS'
        ))
        
        # Bass en secciones de energía
        if energy >= 5:
            layers.append(LayerBlueprint(
                layer_type=LayerType.BASS,
                role='sub' if section_kind == 'drop' else 'bassline',
                intensity=0.9 if section_kind == 'drop' else 0.6,
                variation_count=3 if section_kind == 'drop' else 1,
                clips=[{'type': 'midi', 'pattern': 'rolling' if section_kind == 'drop' else 'sparse'}],
                effects_chain=['EQ', 'Saturation'],
                bus_assignment='BASS_BUS'
            ))
        
        # Music layers
        if section_kind in ['drop', 'break']:
            layers.append(LayerBlueprint(
                layer_type=LayerType.MUSIC,
                role='lead' if section_kind == 'drop' else 'pad',
                intensity=0.7,
                variation_count=2,
                clips=[{'type': 'audio', 'pattern': 'chord_stabs' if section_kind == 'drop' else 'pad'}],
                effects_chain=['Reverb', 'Delay'],
                bus_assignment='MUSIC_BUS'
            ))
        
        # FX en transiciones
        if section_kind in ['build', 'outro']:
            layers.append(LayerBlueprint(
                layer_type=LayerType.FX,
                role='riser' if section_kind == 'build' else 'noise',
                intensity=0.6,
                variation_count=1,
                clips=[{'type': 'audio', 'pattern': 'riser'}],
                effects_chain=['Filter', 'Reverb'],
                bus_assignment='FX_BUS'
            ))
        
        # Impact en drops
        if section_kind == 'drop':
            layers.append(LayerBlueprint(
                layer_type=LayerType.IMPACT,
                role='crash',
                intensity=1.0,
                variation_count=1,
                clips=[{'type': 'one_shot', 'pattern': 'crash_drop'}],
                effects_chain=['EQ'],
                bus_assignment='DRUMS_BUS'
            ))
        
        # Ambience en intros/breaks
        if section_kind in ['intro', 'break']:
            layers.append(LayerBlueprint(
                layer_type=LayerType.AMBIENCE,
                role='texture',
                intensity=0.3,
                variation_count=1,
                clips=[{'type': 'audio', 'pattern': 'atmosphere'}],
                effects_chain=['Reverb', 'Delay'],
                bus_assignment='MUSIC_BUS'
            ))
        
        return layers
    
    def _generate_transitions(self, section_kind: str) -> Dict[str, Any]:
        """Genera configuración de transiciones."""
        transitions = {
            'in': {'type': 'cut' if section_kind == 'drop' else 'fade', 'duration_bars': 2},
            'out': {'type': 'fade', 'duration_bars': 4},
            'fx': []
        }
        
        if section_kind == 'build':
            transitions['fx'] = ['riser', 'snare_roll']
        elif section_kind == 'drop':
            transitions['fx'] = ['impact', 'crash']
        elif section_kind == 'break':
            transitions['fx'] = ['reverb_tail', 'filter_sweep']
        
        return transitions
    
    def _generate_harmonic_content(self, section_kind: str) -> Dict[str, Any]:
        """Genera contenido armónico para la sección."""
        return {
            'root_key': self.key,
            'chord_progression': self._get_chord_progression(section_kind),
            'scale': 'minor' if 'm' in self.key else 'major',
            'complexity': 'high' if section_kind == 'drop' else 'medium'
        }
    
    def _get_chord_progression(self, section_kind: str) -> List[str]:
        """Obtiene progresión de acordes según sección."""
        # Progresiones típicas de música electrónica
        progressions = {
            'intro': ['i', 'iv'],
            'build': ['i', 'v', 'vi', 'iv'],
            'drop': ['i', 'VI', 'III', 'VII'],
            'break': ['vi', 'iv', 'i', 'v'],
            'outro': ['i', 'v']
        }
        return progressions.get(section_kind, ['i', 'iv', 'v'])
    
    def _generate_audio_layers(self) -> List[Dict[str, Any]]:
        """Genera capas de audio del blueprint."""
        layers = []
        
        for section in self.sections:
            for layer in section.layers:
                if layer.layer_type in [LayerType.DRUMS, LayerType.BASS, LayerType.MUSIC]:
                    layers.append({
                        'type': layer.layer_type.value,
                        'role': layer.role,
                        'section': section.kind,
                        'start_bar': section.start_bar,
                        'end_bar': section.end_bar,
                        'intensity': layer.intensity,
                        'bus': layer.bus_assignment,
                        'effects': layer.effects_chain,
                        'sample_path': f"librerias/all_tracks/{layer.layer_type.value.title()}/{self.genre}/"
                    })
        
        return layers
    
    def _generate_resample_layers(self) -> List[Dict[str, Any]]:
        """Genera capas de resample."""
        resamples = []
        
        # Identificar secciones para resample
        for section in self.sections:
            if section.energy_level >= 7:  # Solo secciones de alta energía
                resamples.append({
                    'source_section': section.kind,
                    'start_bar': section.start_bar,
                    'end_bar': section.end_bar,
                    'processing': ['stretch', 'grain_delay'],
                    'target_bus': 'MUSIC_BUS'
                })
        
        return resamples
    
    def _configure_buses(self) -> Dict[str, Any]:
        """Configura buses RCA."""
        return {
            'DRUMS_BUS': {
                'type': 'drums',
                'effects': ['EQ', 'Compression', 'Saturator'],
                'volume': 0.85,
                'target_lufs': -8
            },
            'BASS_BUS': {
                'type': 'bass',
                'effects': ['EQ', 'Compression'],
                'volume': 0.80,
                'target_lufs': -10
            },
            'MUSIC_BUS': {
                'type': 'music',
                'effects': ['EQ', 'Reverb'],
                'volume': 0.75,
                'target_lufs': -12
            },
            'FX_BUS': {
                'type': 'fx',
                'effects': ['Reverb', 'Delay'],
                'volume': 0.70,
                'target_lufs': -14
            }
        }
    
    def _configure_returns(self) -> Dict[str, Any]:
        """Configura canales de retorno."""
        return {
            'Reverb': {
                'type': 'reverb',
                'decay': 2.5,
                'pre_delay': 20,
                'send_levels': {'DRUMS_BUS': 0.15, 'BASS_BUS': 0.05, 'MUSIC_BUS': 0.30}
            },
            'Delay': {
                'type': 'delay',
                'time_ms': 375,  # 1/8 a 128 BPM
                'feedback': 0.35,
                'send_levels': {'MUSIC_BUS': 0.20, 'FX_BUS': 0.25}
            }
        }
    
    def _generate_section_variants(self) -> Dict[str, List[Dict]]:
        """Genera variantes para cada sección."""
        variants = {}
        
        for section in self.sections:
            section_variants = []
            
            # Variante principal
            section_variants.append({
                'name': 'main',
                'variation_index': 0,
                'intensity': section.energy_level / 10,
                'active_layers': [l.layer_type.value for l in section.layers]
            })
            
            # Variante reducida (para transiciones)
            section_variants.append({
                'name': 'stripped',
                'variation_index': 1,
                'intensity': (section.energy_level / 10) * 0.6,
                'active_layers': ['drums', 'bass'] if section.energy_level > 5 else ['drums']
            })
            
            # Variante maximal (para peaks)
            if section.energy_level >= 7:
                section_variants.append({
                    'name': 'full',
                    'variation_index': 2,
                    'intensity': 1.0,
                    'active_layers': [l.layer_type.value for l in section.layers] + ['impact']
                })
            
            variants[section.kind] = section_variants
        
        return variants
    
    def _generate_track_blueprint(self) -> Dict[str, Any]:
        """Genera blueprint de tracks individuales."""
        return {
            'count': len(self.sections),
            'types': ['AUDIO'] * len(self.audio_layers) + ['MIDI'] * sum(
                1 for s in self.sections for l in s.layers if l.clips and l.clips[0].get('type') == 'midi'
            ),
            'structure': 'standard',
            'routing': {
                'drums': 'DRUMS_BUS',
                'bass': 'BASS_BUS',
                'music': 'MUSIC_BUS',
                'fx': 'FX_BUS'
            }
        }
    
    def _generate_mix_blueprint(self) -> Dict[str, Any]:
        """Genera blueprint de mezcla."""
        return {
            'gain_staging': {
                'target_lufs_master': -10,
                'headroom_db': 3.0,
                'buses': {k: v['target_lufs'] for k, v in self.buses.items()}
            },
            'automation': {
                'sections': [
                    {
                        'type': s.kind,
                        'start_bar': s.start_bar,
                        'automation_types': ['volume', 'filter'] if s.kind == 'build' else ['volume']
                    }
                    for s in self.sections
                ]
            },
            'master_chain': {
                'devices': ['EQ', 'Compressor', 'Limiter'],
                'settings': {
                    'limiter_ceiling': -1.0,
                    'compression_ratio': 2.0
                }
            }
        }


def get_generation_manifest() -> Dict[str, Any]:
    """
    Obtiene manifest de la última generación con datos reales.
    
    Incluye:
    - genre, style, bpm, key, structure
    - referencia usada o null
    - tracks blueprint
    - buses/returns creados
    - audio layers con sample paths exactos
    - resample layers
    - secciones y variantes usadas
    
    Returns:
        Manifest completo de la última generación
    """
    try:
        # Intentar cargar desde archivo
        manifest_file = os.path.join(
            os.path.dirname(__file__), 
            'logs', 'manifests', 'last_generation.json'
        )
        
        if os.path.exists(manifest_file):
            with open(manifest_file, 'r') as f:
                return json.load(f)
    except:
        pass
    
    # Generar blueprint de ejemplo
    blueprint = MultiLayerBlueprint(
        genre='techno',
        style='industrial',
        bpm=138,
        key='F#m'
    )
    
    return blueprint.build_complete_blueprint(structure='standard')


if __name__ == '__main__':
    # Test del blueprint multi-capa
    blueprint = MultiLayerBlueprint(
        genre='techno',
        style='industrial',
        bpm=138,
        key='F#m'
    )
    
    result = blueprint.build_complete_blueprint('standard')
    
    print(f"Session ID: {result['session_id']}")
    print(f"Sections: {len(result['sections'])}")
    print(f"Audio Layers: {len(result['audio_layers'])}")
    print(f"Buses: {list(result['buses'].keys())}")
    print(f"Returns: {list(result['returns'].keys())}")
