"""
T087-T227: Stem Meta Tags
Inserción de metadatos en stems exportados
"""

import os
import json
from datetime import datetime
from typing import Dict, List, Any, Optional
from pathlib import Path


class StemMetaTagger:
    """
    Sistema de inserción de metadatos en stems.
    
    T087: Exporta stems con metadatos BPM/key incluidos.
    T227: Inserción avanzada de tags meta.
    """
    
    STANDARD_TAGS = {
        'bpm': 'TBPM',
        'key': 'TKEY',
        'genre': 'TCON',
        'artist': 'TPE1',
        'title': 'TIT2',
        'album': 'TALB',
        'year': 'TYER',
        'comment': 'COMM',
        'encoder': 'TENC',
        'publisher': 'TPUB'
    }
    
    def __init__(self):
        self.metadata_cache = {}
    
    def add_meta_tags(self, stem_path: str, 
                      metadata: Dict[str, Any]) -> Dict[str, Any]:
        """
        Agrega metadatos a un archivo de stem.
        
        Args:
            stem_path: Ruta al archivo de audio
            metadata: Diccionario de metadatos
            
        Returns:
            Resultado de la operación
        """
        if not os.path.exists(stem_path):
            return {'error': f'File not found: {stem_path}'}
        
        file_ext = Path(stem_path).suffix.lower()
        
        if file_ext == '.wav':
            return self._tag_wav(stem_path, metadata)
        elif file_ext in ['.aif', '.aiff']:
            return self._tag_aiff(stem_path, metadata)
        elif file_ext == '.flac':
            return self._tag_flac(stem_path, metadata)
        elif file_ext == '.mp3':
            return self._tag_mp3(stem_path, metadata)
        else:
            return {'error': f'Unsupported format: {file_ext}'}
    
    def _tag_wav(self, filepath: str, metadata: Dict) -> Dict[str, Any]:
        """Agrega metadatos a archivo WAV (INFO chunk)."""
        # WAV usa chunks INFO para metadatos
        # Esta es una implementación simplificada
        
        try:
            # Crear archivo sidecar JSON con metadatos
            sidecar_path = filepath.replace('.wav', '_metadata.json')
            
            wav_metadata = {
                'format': 'WAV',
                'encoding': 'PCM',
                'metadata': metadata,
                'embedded': False,  # WAV no soporta ID3 nativamente
                'sidecar': sidecar_path
            }
            
            with open(sidecar_path, 'w') as f:
                json.dump(wav_metadata, f, indent=2)
            
            return {
                'success': True,
                'format': 'WAV',
                'method': 'sidecar_json',
                'sidecar_path': sidecar_path,
                'fields_written': list(metadata.keys())
            }
        except Exception as e:
            return {'error': str(e)}
    
    def _tag_aiff(self, filepath: str, metadata: Dict) -> Dict[str, Any]:
        """Agrega metadatos a archivo AIFF."""
        try:
            sidecar_path = filepath.replace('.aiff', '_metadata.json').replace('.aif', '_metadata.json')
            
            aiff_metadata = {
                'format': 'AIFF',
                'metadata': metadata,
                'embedded': False,
                'sidecar': sidecar_path
            }
            
            with open(sidecar_path, 'w') as f:
                json.dump(aiff_metadata, f, indent=2)
            
            return {
                'success': True,
                'format': 'AIFF',
                'method': 'sidecar_json',
                'sidecar_path': sidecar_path
            }
        except Exception as e:
            return {'error': str(e)}
    
    def _tag_flac(self, filepath: str, metadata: Dict) -> Dict[str, Any]:
        """Agrega metadatos a archivo FLAC (Vorbis comments)."""
        # FLAC usa Vorbis comments
        # Requeriría mutagen o similar
        
        try:
            # Intentar importar mutagen si está disponible
            try:
                from mutagen.flac import FLAC
                audio = FLAC(filepath)
                
                # Mapear metadatos
                if 'bpm' in metadata:
                    audio['BPM'] = str(metadata['bpm'])
                if 'key' in metadata:
                    audio['INITIALKEY'] = metadata['key']
                if 'genre' in metadata:
                    audio['GENRE'] = metadata['genre']
                if 'artist' in metadata:
                    audio['ARTIST'] = metadata['artist']
                if 'title' in metadata:
                    audio['TITLE'] = metadata['title']
                
                audio.save()
                
                return {
                    'success': True,
                    'format': 'FLAC',
                    'method': 'vorbis_comments',
                    'fields_written': list(metadata.keys())
                }
            except ImportError:
                # Fallback a sidecar
                sidecar_path = filepath.replace('.flac', '_metadata.json')
                with open(sidecar_path, 'w') as f:
                    json.dump({'format': 'FLAC', 'metadata': metadata}, f, indent=2)
                
                return {
                    'success': True,
                    'format': 'FLAC',
                    'method': 'sidecar_json',
                    'note': 'mutagen not available - using sidecar'
                }
        except Exception as e:
            return {'error': str(e)}
    
    def _tag_mp3(self, filepath: str, metadata: Dict) -> Dict[str, Any]:
        """Agrega metadatos a archivo MP3 (ID3)."""
        try:
            try:
                from mutagen.mp3 import MP3
                from mutagen.id3 import ID3, TIT2, TPE1, TALB, TKEY, TBPM, TCON, TYER
                
                audio = MP3(filepath)
                
                # Asegurar que existe tag ID3
                if audio.tags is None:
                    audio.add_tags()
                
                # Mapear metadatos
                if 'title' in metadata:
                    audio.tags['TIT2'] = TIT2(encoding=3, text=metadata['title'])
                if 'artist' in metadata:
                    audio.tags['TPE1'] = TPE1(encoding=3, text=metadata['artist'])
                if 'album' in metadata:
                    audio.tags['TALB'] = TALB(encoding=3, text=metadata['album'])
                if 'bpm' in metadata:
                    audio.tags['TBPM'] = TBPM(encoding=3, text=str(metadata['bpm']))
                if 'key' in metadata:
                    audio.tags['TKEY'] = TKEY(encoding=3, text=metadata['key'])
                if 'genre' in metadata:
                    audio.tags['TCON'] = TCON(encoding=3, text=metadata['genre'])
                if 'year' in metadata:
                    audio.tags['TYER'] = TYER(encoding=3, text=str(metadata['year']))
                
                audio.save()
                
                return {
                    'success': True,
                    'format': 'MP3',
                    'method': 'id3_v2.4',
                    'fields_written': list(metadata.keys())
                }
            except ImportError:
                return {
                    'success': False,
                    'error': 'mutagen package required for MP3 tagging'
                }
        except Exception as e:
            return {'error': str(e)}
    
    def tag_stems_batch(self, stems_dir: str, 
                        common_metadata: Dict[str, Any],
                        individual_metadata: Dict[str, Dict] = None) -> Dict[str, Any]:
        """
        Tags múltiples stems en batch.
        
        Args:
            stems_dir: Directorio con stems
            common_metadata: Metadatos comunes para todos
            individual_metadata: Metadatos específicos por archivo
            
        Returns:
            Resultados del batch
        """
        results = []
        
        for filename in os.listdir(stems_dir):
            if filename.lower().endswith(('.wav', '.aif', '.aiff', '.flac', '.mp3')):
                filepath = os.path.join(stems_dir, filename)
                
                # Combinar metadatos comunes con individuales
                metadata = common_metadata.copy()
                if individual_metadata and filename in individual_metadata:
                    metadata.update(individual_metadata[filename])
                
                result = self.add_meta_tags(filepath, metadata)
                result['filename'] = filename
                results.append(result)
        
        successful = sum(1 for r in results if r.get('success'))
        
        return {
            'total_files': len(results),
            'successful': successful,
            'failed': len(results) - successful,
            'results': results
        }
    
    def create_export_job(self, output_dir: str = None,
                          bus_names: str = 'drums,bass,music,master',
                          include_metadata: bool = True,
                          format: str = 'wav',
                          bit_depth: int = 24,
                          sample_rate: int = 44100) -> Dict[str, Any]:
        """
        T086-T087: Crea job de exportación con stems y metadata.
        
        Args:
            output_dir: Directorio de salida
            bus_names: Lista de buses a exportar
            include_metadata: Incluir metadata BPM/key
            format: wav, aiff, flac
            bit_depth: 16, 24, 32
            sample_rate: 44100, 48000, 96000
            
        Returns:
            Configuración del job de exportación
        """
        buses = bus_names.split(',') if isinstance(bus_names, str) else bus_names
        
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        
        if output_dir is None:
            output_dir = os.path.expanduser(f'~/AbletonMCP_Exports/{timestamp}')
        
        os.makedirs(output_dir, exist_ok=True)
        
        job = {
            'job_id': f'export_{timestamp}',
            'created_at': datetime.now().isoformat(),
            'output_dir': output_dir,
            'format': format,
            'bit_depth': bit_depth,
            'sample_rate': sample_rate,
            'stems': [],
            'metadata': {
                'include_bpm_key': include_metadata,
                'export_date': datetime.now().isoformat(),
                'encoder': 'AbletonMCP-AI T227'
            }
        }
        
        for bus in buses:
            filename = f'{bus}_{timestamp}.{format}'
            filepath = os.path.join(output_dir, filename)
            
            stem_config = {
                'bus': bus,
                'filename': filename,
                'filepath': filepath,
                'metadata': {
                    'stem_type': bus,
                    'export_timestamp': timestamp,
                    'bit_depth': bit_depth,
                    'sample_rate': sample_rate
                }
            }
            
            job['stems'].append(stem_config)
        
        # Guardar configuración del job
        job_file = os.path.join(output_dir, 'export_job.json')
        with open(job_file, 'w') as f:
            json.dump(job, f, indent=2)
        
        return {
            'success': True,
            'job': job,
            'job_file': job_file,
            'output_dir': output_dir,
            'total_stems': len(buses)
        }


def export_stem_mixdown(bus_names: str = 'drums,bass,music,master',
                        output_dir: str = None,
                        include_metadata: bool = True) -> Dict[str, Any]:
    """
    T087: Exporta stems 24-bit/44.1kHz separados por bus.
    
    Args:
        bus_names: Lista de buses separados por coma
        output_dir: Directorio de salida
        include_metadata: Incluir metadata BPM/key en archivos
        
    Returns:
        Configuración del job de exportación
    """
    tagger = StemMetaTagger()
    
    # Crear job de exportación
    job_result = tagger.create_export_job(
        output_dir=output_dir,
        bus_names=bus_names,
        include_metadata=include_metadata,
        format='wav',
        bit_depth=24,
        sample_rate=44100
    )
    
    return job_result


if __name__ == '__main__':
    # Test del tagger
    tagger = StemMetaTagger()
    
    # Simular tagging
    metadata = {
        'bpm': 128,
        'key': 'Am',
        'genre': 'techno',
        'artist': 'AbletonMCP-AI',
        'title': 'Generated Track',
        'year': 2026
    }
    
    # Crear job de exportación
    job = tagger.create_export_job(
        bus_names='drums,bass,music,master',
        include_metadata=True
    )
    
    print(json.dumps(job, indent=2))
