"""
Preset System - Sistema de Presets y Templates para AbletonMCP_AI (T061-T065)

Gestión completa de presets para reggaeton: predefinidos, personalizados,
importación/exportación, y aplicación a proyectos.
"""
import json
import logging
import os
from dataclasses import dataclass, field, asdict
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional, Union

logger = logging.getLogger("PresetSystem")

PRESETS_DIR = Path(r"C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\AbletonMCP_AI\presets")


# =============================================================================
# DATACLASSES
# =============================================================================

@dataclass
class TrackPreset:
    """Configuración de preset para una pista individual."""
    name: str
    track_type: str  # "midi" o "audio"
    role: str
    sample_criteria: Dict[str, Any] = field(default_factory=dict)
    device_chain: List[Dict[str, Any]] = field(default_factory=list)
    volume: float = 0.8
    pan: float = 0.0
    mute: bool = False
    solo: bool = False
    color: int = 0
    
    def to_dict(self) -> Dict[str, Any]: return asdict(self)
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "TrackPreset": return cls(**data)


@dataclass
class MixingConfig:
    """Configuración de mezcla para un preset."""
    eq_low_gain: float = 0.0
    eq_mid_gain: float = 0.0
    eq_high_gain: float = 0.0
    compressor_threshold: float = -6.0
    compressor_ratio: float = 3.0
    compressor_makeup: float = 3.0
    send_reverb: float = 0.3
    send_delay: float = 0.2
    master_volume: float = 0.85
    
    def to_dict(self) -> Dict[str, Any]: return asdict(self)
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "MixingConfig": return cls(**data)


@dataclass
class SampleSelectionCriteria:
    """Criterios de selección de samples para un preset."""
    preferred_packs: List[str] = field(default_factory=list)
    excluded_packs: List[str] = field(default_factory=list)
    min_bpm: float = 0.0
    max_bpm: float = 0.0
    preferred_key: str = ""
    use_similarity_selection: bool = False
    similarity_reference: str = ""
    priority_roles: List[str] = field(default_factory=lambda: ["kick", "snare", "bass", "hat_closed"])
    
    def to_dict(self) -> Dict[str, Any]: return asdict(self)
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "SampleSelectionCriteria": return cls(**data)


@dataclass
class Preset:
    """Preset completo de configuración de canción."""
    name: str
    description: str
    version: str = "1.0"
    created_at: str = field(default_factory=lambda: datetime.now().isoformat())
    updated_at: str = field(default_factory=lambda: datetime.now().isoformat())
    bpm: float = 95.0
    key: str = "Am"
    style: str = "dembow"
    structure: str = "standard"
    tracks_config: List[TrackPreset] = field(default_factory=list)
    mixing_config: MixingConfig = field(default_factory=MixingConfig)
    sample_selection: SampleSelectionCriteria = field(default_factory=SampleSelectionCriteria)
    tags: List[str] = field(default_factory=list)
    author: str = ""
    is_builtin: bool = False
    
    def to_dict(self) -> Dict[str, Any]:
        return {
            "name": self.name, "description": self.description, "version": self.version,
            "created_at": self.created_at, "updated_at": self.updated_at,
            "bpm": self.bpm, "key": self.key, "style": self.style, "structure": self.structure,
            "tracks_config": [t.to_dict() for t in self.tracks_config],
            "mixing_config": self.mixing_config.to_dict(),
            "sample_selection": self.sample_selection.to_dict(),
            "tags": self.tags, "author": self.author, "is_builtin": self.is_builtin,
        }
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "Preset":
        tracks = [TrackPreset.from_dict(t) for t in data.get("tracks_config", [])]
        mixing = MixingConfig.from_dict(data.get("mixing_config", {}))
        samples = SampleSelectionCriteria.from_dict(data.get("sample_selection", {}))
        return cls(
            name=data["name"], description=data.get("description", ""), version=data.get("version", "1.0"),
            created_at=data.get("created_at", datetime.now().isoformat()),
            updated_at=data.get("updated_at", datetime.now().isoformat()),
            bpm=data.get("bpm", 95.0), key=data.get("key", "Am"), style=data.get("style", "dembow"),
            structure=data.get("structure", "standard"), tracks_config=tracks, mixing_config=mixing,
            sample_selection=samples, tags=data.get("tags", []), author=data.get("author", ""),
            is_builtin=data.get("is_builtin", False),
        )


# =============================================================================
# PRESETS PREDEFINIDOS
# =============================================================================

def create_builtin_presets() -> Dict[str, Preset]:
    """Crea el diccionario de presets predefinidos del sistema."""
    
    # 1. Reggaeton Clásico 95 BPM
    reggaeton_classic = Preset(
        name="reggaeton_classic_95bpm",
        description="Reggaeton clásico con dembow puro. Ideal para pistas de club.",
        bpm=95.0, key="Am", style="dembow", structure="standard",
        tags=["classic", "club", "dembow", "standard"], is_builtin=True,
        tracks_config=[
            TrackPreset(name="Kick", track_type="midi", role="kick", volume=0.9, sample_criteria={"role": "kick", "pack_preference": "classic"}),
            TrackPreset(name="Snare", track_type="midi", role="snare", volume=0.75, sample_criteria={"role": "snare"}),
            TrackPreset(name="Hi-Hats", track_type="midi", role="hat_closed", volume=0.65, sample_criteria={"role": "hat_closed"}),
            TrackPreset(name="Bass", track_type="midi", role="bass", volume=0.85, sample_criteria={"role": "bass", "pack_preference": "classic"}),
            TrackPreset(name="Synth Lead", track_type="midi", role="synth_lead", volume=0.7, sample_criteria={"role": "synth"}),
        ],
        mixing_config=MixingConfig(eq_low_gain=2.0, compressor_threshold=-4.0, compressor_ratio=2.5, send_reverb=0.25, master_volume=0.88),
    )
    
    # 2. Perreo Intenso 100 BPM
    perreo_intenso = Preset(
        name="perreo_intenso_100bpm",
        description="Perreo intenso con kick heavy y bajo prominente. Alto impacto.",
        bpm=100.0, key="Em", style="perreo", structure="standard",
        tags=["perreo", "heavy", "club", "energetic"], is_builtin=True,
        tracks_config=[
            TrackPreset(name="Kick Heavy", track_type="midi", role="kick", volume=0.95, sample_criteria={"role": "kick", "character": "heavy"}),
            TrackPreset(name="Snare", track_type="midi", role="snare", volume=0.8),
            TrackPreset(name="Clap", track_type="midi", role="clap", volume=0.7),
            TrackPreset(name="Hi-Hats", track_type="midi", role="hat_closed", volume=0.7),
            TrackPreset(name="Bass Deep", track_type="midi", role="bass", volume=0.9, sample_criteria={"role": "bass", "character": "deep"}),
            TrackPreset(name="Lead", track_type="midi", role="synth_lead", volume=0.75),
        ],
        mixing_config=MixingConfig(eq_low_gain=4.0, compressor_threshold=-6.0, compressor_ratio=3.5, send_reverb=0.2, master_volume=0.9),
    )
    
    # 3. Reggaeton Romántico 90 BPM
    reggaeton_romantico = Preset(
        name="reggaeton_romantico_90bpm",
        description="Reggaeton romántico con reverb abundante y mezcla balanceada.",
        bpm=90.0, key="Gm", style="romantico", structure="extended",
        tags=["romantico", "smooth", "reverb", "extended"], is_builtin=True,
        tracks_config=[
            TrackPreset(name="Kick Soft", track_type="midi", role="kick", volume=0.75, sample_criteria={"role": "kick", "character": "soft"}),
            TrackPreset(name="Snare", track_type="midi", role="snare", volume=0.65),
            TrackPreset(name="Hi-Hats", track_type="midi", role="hat_closed", volume=0.55),
            TrackPreset(name="Bass Smooth", track_type="midi", role="bass", volume=0.7, sample_criteria={"role": "bass", "character": "smooth"}),
            TrackPreset(name="Pad", track_type="midi", role="synth_pad", volume=0.6),
            TrackPreset(name="Lead Melodic", track_type="midi", role="synth_lead", volume=0.65),
        ],
        mixing_config=MixingConfig(eq_low_gain=0.0, compressor_threshold=-8.0, compressor_ratio=2.0, send_reverb=0.5, send_delay=0.35, master_volume=0.82),
    )
    
    # 4. Moombahton 108 BPM
    moombahton = Preset(
        name="moombahton_108bpm",
        description="Moombahton con variación de dembow y estructura minimal.",
        bpm=108.0, key="Dm", style="moombahton", structure="minimal",
        tags=["moombahton", "dembow", "minimal", "electronic"], is_builtin=True,
        tracks_config=[
            TrackPreset(name="Kick Moombah", track_type="midi", role="kick", volume=0.9, sample_criteria={"role": "kick", "style": "moombahton"}),
            TrackPreset(name="Snare", track_type="midi", role="snare", volume=0.75),
            TrackPreset(name="Tom", track_type="midi", role="perc", volume=0.6, sample_criteria={"role": "perc"}),
            TrackPreset(name="Hi-Hats", track_type="midi", role="hat_closed", volume=0.65),
            TrackPreset(name="Bass", track_type="midi", role="bass", volume=0.8),
            TrackPreset(name="Stabs", track_type="midi", role="synth_lead", volume=0.7, sample_criteria={"role": "synth", "character": "stab"}),
        ],
        mixing_config=MixingConfig(eq_low_gain=3.0, compressor_threshold=-5.0, compressor_ratio=3.0, send_reverb=0.3, master_volume=0.87),
    )
    
    # 5. Trapeton 140 BPM
    trapeton = Preset(
        name="trapeton_140bpm",
        description="Trapeton con 808s pesados y hi-hat rolls. Fusión trap-reggaeton.",
        bpm=140.0, key="Cm", style="trapeton", structure="standard",
        tags=["trapeton", "trap", "808", "hihat_rolls", "hard"], is_builtin=True,
        tracks_config=[
            TrackPreset(name="808 Kick", track_type="midi", role="kick", volume=0.95, sample_criteria={"role": "kick", "character": "808"}),
            TrackPreset(name="Snare", track_type="midi", role="snare", volume=0.8, sample_criteria={"role": "snare", "character": "trap"}),
            TrackPreset(name="Hi-Hats", track_type="midi", role="hat_closed", volume=0.75, sample_criteria={"role": "hat_closed", "style": "trap"}),
            TrackPreset(name="Hi-Hat Rolls", track_type="midi", role="hat_open", volume=0.65, sample_criteria={"role": "hat_open", "style": "trap_rolls"}),
            TrackPreset(name="808 Bass", track_type="midi", role="bass", volume=0.9, sample_criteria={"role": "bass", "character": "808"}),
            TrackPreset(name="Lead Hard", track_type="midi", role="synth_lead", volume=0.75, sample_criteria={"role": "synth", "character": "aggressive"}),
        ],
        mixing_config=MixingConfig(eq_low_gain=5.0, eq_high_gain=2.0, compressor_threshold=-8.0, compressor_ratio=4.0, compressor_makeup=4.0, send_reverb=0.15, send_delay=0.25, master_volume=0.92),
    )
    
    return {
        reggaeton_classic.name: reggaeton_classic,
        perreo_intenso.name: perreo_intenso,
        reggaeton_romantico.name: reggaeton_romantico,
        moombahton.name: moombahton,
        trapeton.name: trapeton,
    }


# =============================================================================
# PRESET MANAGER
# =============================================================================

class PresetManager:
    """Gestor de presets para AbletonMCP_AI."""
    
    def __init__(self, presets_dir: Optional[str] = None):
        self._presets_dir = Path(presets_dir) if presets_dir else PRESETS_DIR
        self._builtin_presets: Dict[str, Preset] = create_builtin_presets()
        self._custom_presets: Dict[str, Preset] = {}
        self._ensure_presets_dir()
        self._load_custom_presets()
    
    def _ensure_presets_dir(self):
        if not self._presets_dir.exists():
            try:
                self._presets_dir.mkdir(parents=True, exist_ok=True)
                logger.info("Created presets directory: %s", self._presets_dir)
            except Exception as e:
                logger.error("Failed to create presets directory: %s", e)
    
    def _get_preset_path(self, preset_name: str) -> Path:
        safe_name = preset_name.replace(" ", "_").lower()
        return self._presets_dir / f"{safe_name}.json"
    
    def _load_custom_presets(self):
        if not self._presets_dir.exists():
            return
        for preset_file in self._presets_dir.glob("*.json"):
            try:
                with open(preset_file, "r", encoding="utf-8") as f:
                    data = json.load(f)
                preset = Preset.from_dict(data)
                if not preset.is_builtin:
                    self._custom_presets[preset.name] = preset
            except Exception as e:
                logger.warning("Failed to load preset %s: %s", preset_file, e)
        logger.info("Loaded %d custom presets", len(self._custom_presets))
    
    def load_preset(self, preset_name: str) -> Optional[Preset]:
        """Carga un preset por nombre. Busca primero en builtins, luego custom."""
        if preset_name in self._builtin_presets:
            logger.info("Loaded builtin preset: %s", preset_name)
            return self._builtin_presets[preset_name]
        if preset_name in self._custom_presets:
            logger.info("Loaded custom preset: %s", preset_name)
            return self._custom_presets[preset_name]
        preset_name_lower = preset_name.lower()
        for name, preset in {**self._builtin_presets, **self._custom_presets}.items():
            if name.lower() == preset_name_lower:
                return preset
        logger.warning("Preset not found: %s", preset_name)
        return None
    
    def save_as_preset(self, config: Dict[str, Any], preset_name: str) -> bool:
        """Guarda una configuración como preset personalizado."""
        try:
            preset = self._config_to_preset(config, preset_name)
            preset.is_builtin = False
            preset.updated_at = datetime.now().isoformat()
            preset_path = self._get_preset_path(preset_name)
            with open(preset_path, "w", encoding="utf-8") as f:
                json.dump(preset.to_dict(), f, indent=2, ensure_ascii=False)
            self._custom_presets[preset_name] = preset
            logger.info("Saved preset: %s", preset_name)
            return True
        except Exception as e:
            logger.error("Failed to save preset %s: %s", preset_name, e)
            return False
    
    def _config_to_preset(self, config: Dict[str, Any], name: str) -> Preset:
        """Convierte un diccionario de configuración a un Preset."""
        tracks_config = []
        for track_data in config.get("tracks", []):
            tracks_config.append(TrackPreset(
                name=track_data.get("name", "Track"), track_type=track_data.get("track_type", "midi"),
                role=track_data.get("instrument_role", "synth"), volume=track_data.get("volume", 0.8),
                pan=track_data.get("pan", 0.0), device_chain=track_data.get("device_chain", []),
            ))
        mixing_data = config.get("mixing_config", {})
        mixing_config = MixingConfig(
            eq_low_gain=mixing_data.get("eq_low_gain", 0.0), eq_mid_gain=mixing_data.get("eq_mid_gain", 0.0),
            eq_high_gain=mixing_data.get("eq_high_gain", 0.0), compressor_threshold=mixing_data.get("compressor_threshold", -6.0),
            compressor_ratio=mixing_data.get("compressor_ratio", 3.0), send_reverb=mixing_data.get("send_reverb", 0.3),
            send_delay=mixing_data.get("send_delay", 0.2), master_volume=mixing_data.get("master_volume", 0.85),
        )
        return Preset(
            name=name, description=config.get("description", f"Custom preset: {name}"),
            bpm=config.get("bpm", 95.0), key=config.get("key", "Am"), style=config.get("style", "dembow"),
            structure=config.get("structure", "standard"), tracks_config=tracks_config,
            mixing_config=mixing_config, tags=config.get("tags", ["custom"]),
        )
    
    def list_presets(self, include_builtin: bool = True, filter_tags: Optional[List[str]] = None) -> List[Dict[str, Any]]:
        """Lista todos los presets disponibles."""
        all_presets: Dict[str, Preset] = {}
        if include_builtin:
            all_presets.update(self._builtin_presets)
        all_presets.update(self._custom_presets)
        if filter_tags:
            all_presets = {n: p for n, p in all_presets.items() if any(t in p.tags for t in filter_tags)}
        result = [
            {"name": n, "description": p.description, "bpm": p.bpm, "key": p.key, "style": p.style,
             "structure": p.structure, "tags": p.tags, "is_builtin": p.is_builtin, "track_count": len(p.tracks_config)}
            for n, p in all_presets.items()
        ]
        result.sort(key=lambda x: (not x["is_builtin"], x["name"]))
        return result
    
    def create_custom_preset(self, current_config: Dict[str, Any], name: str, description: str = "", tags: Optional[List[str]] = None) -> Optional[Preset]:
        """Crea un nuevo preset personalizado desde una configuración."""
        try:
            preset = self._config_to_preset(current_config, name)
            preset.description = description or f"Custom preset: {name}"
            preset.tags = tags or ["custom"]
            preset.is_builtin = False
            preset.author = current_config.get("author", "")
            if self.save_as_preset(current_config, name):
                return preset
            return None
        except Exception as e:
            logger.error("Failed to create custom preset: %s", e)
            return None
    
    def delete_preset(self, preset_name: str) -> bool:
        """Elimina un preset personalizado. No se pueden eliminar builtins."""
        if preset_name in self._builtin_presets:
            logger.warning("Cannot delete builtin preset: %s", preset_name)
            return False
        if preset_name not in self._custom_presets:
            logger.warning("Preset not found for deletion: %s", preset_name)
            return False
        try:
            preset_path = self._get_preset_path(preset_name)
            if preset_path.exists():
                preset_path.unlink()
            del self._custom_presets[preset_name]
            logger.info("Deleted preset: %s", preset_name)
            return True
        except Exception as e:
            logger.error("Failed to delete preset %s: %s", preset_name, e)
            return False
    
    def export_preset(self, preset_name: str, export_path: str) -> bool:
        """Exporta un preset a un archivo externo."""
        preset = self.load_preset(preset_name)
        if not preset:
            logger.warning("Cannot export non-existent preset: %s", preset_name)
            return False
        try:
            export_path = Path(export_path)
            if not export_path.suffix == ".json":
                export_path = export_path.with_suffix(".json")
            with open(export_path, "w", encoding="utf-8") as f:
                json.dump(preset.to_dict(), f, indent=2, ensure_ascii=False)
            logger.info("Exported preset %s to %s", preset_name, export_path)
            return True
        except Exception as e:
            logger.error("Failed to export preset %s: %s", preset_name, e)
            return False
    
    def import_preset(self, import_path: str, preset_name: Optional[str] = None) -> Optional[Preset]:
        """Importa un preset desde un archivo externo."""
        try:
            import_path = Path(import_path)
            if not import_path.exists():
                logger.error("Import file not found: %s", import_path)
                return None
            with open(import_path, "r", encoding="utf-8") as f:
                data = json.load(f)
            preset = Preset.from_dict(data)
            preset.is_builtin = False
            if preset_name:
                preset.name = preset_name
            preset_path = self._get_preset_path(preset.name)
            with open(preset_path, "w", encoding="utf-8") as f:
                json.dump(preset.to_dict(), f, indent=2, ensure_ascii=False)
            self._custom_presets[preset.name] = preset
            logger.info("Imported preset: %s", preset.name)
            return preset
        except Exception as e:
            logger.error("Failed to import preset from %s: %s", import_path, e)
            return None
    
    def get_preset_details(self, preset_name: str) -> Optional[Dict[str, Any]]:
        """Obtiene detalles completos de un preset."""
        preset = self.load_preset(preset_name)
        if not preset:
            return None
        return {
            "name": preset.name, "description": preset.description, "version": preset.version,
            "created_at": preset.created_at, "updated_at": preset.updated_at,
            "bpm": preset.bpm, "key": preset.key, "style": preset.style, "structure": preset.structure,
            "tracks": [{"name": t.name, "type": t.track_type, "role": t.role, "volume": t.volume, "pan": t.pan} for t in preset.tracks_config],
            "mixing": preset.mixing_config.to_dict(),
            "sample_selection": preset.sample_selection.to_dict(),
            "tags": preset.tags, "author": preset.author, "is_builtin": preset.is_builtin,
        }
    
    def duplicate_preset(self, source_name: str, new_name: str) -> bool:
        """Duplica un preset existente con un nuevo nombre."""
        source = self.load_preset(source_name)
        if not source:
            return False
        try:
            new_preset = Preset.from_dict(source.to_dict())
            new_preset.name = new_name
            new_preset.is_builtin = False
            new_preset.description = f"Copy of {source_name}: {source.description}"
            new_preset.created_at = datetime.now().isoformat()
            new_preset.updated_at = datetime.now().isoformat()
            preset_path = self._get_preset_path(new_name)
            with open(preset_path, "w", encoding="utf-8") as f:
                json.dump(new_preset.to_dict(), f, indent=2, ensure_ascii=False)
            self._custom_presets[new_name] = new_preset
            logger.info("Duplicated preset %s to %s", source_name, new_name)
            return True
        except Exception as e:
            logger.error("Failed to duplicate preset: %s", e)
            return False


# =============================================================================
# FUNCIONES DE CONVENIENCIA
# =============================================================================

_manager: Optional[PresetManager] = None


def get_preset_manager() -> PresetManager:
    """Retorna la instancia singleton del PresetManager."""
    global _manager
    if _manager is None:
        _manager = PresetManager()
    return _manager


def apply_preset_to_project(preset_name: str) -> Dict[str, Any]:
    """Aplica un preset completo al proyecto actual."""
    manager = get_preset_manager()
    preset = manager.load_preset(preset_name)
    if not preset:
        return {"success": False, "error": f"Preset not found: {preset_name}"}
    config = {
        "bpm": preset.bpm, "key": preset.key, "style": preset.style, "structure": preset.structure,
        "tracks": [{"name": t.name, "track_type": t.track_type, "instrument_role": t.role,
                     "volume": t.volume, "pan": t.pan, "device_chain": t.device_chain} for t in preset.tracks_config],
        "mixing_config": preset.mixing_config.to_dict(),
        "sample_criteria": preset.sample_selection.to_dict(),
    }
    return {
        "success": True, "preset_name": preset_name, "config": config,
        "message": f"Preset '{preset_name}' loaded and ready to apply",
    }


def get_default_preset() -> str:
    """Retorna el nombre del preset por defecto."""
    return "reggaeton_classic_95bpm"


def list_available_presets(style_filter: Optional[str] = None) -> List[Dict[str, Any]]:
    """Lista todos los presets disponibles, opcionalmente filtrados por estilo."""
    manager = get_preset_manager()
    presets = manager.list_presets()
    if style_filter:
        presets = [p for p in presets if p.get("style") == style_filter]
    return presets


def quick_apply_preset(preset_name: Optional[str] = None) -> Dict[str, Any]:
    """Aplica rápidamente un preset (o el default si no se especifica)."""
    if preset_name is None:
        preset_name = get_default_preset()
    return apply_preset_to_project(preset_name)


# =============================================================================
# HANDLERS MCP
# =============================================================================

def _cmd_load_preset(params: Dict[str, Any]) -> Dict[str, Any]:
    """Handler MCP: Carga un preset por nombre."""
    preset_name = params.get("preset_name", "")
    if not preset_name:
        return {"success": False, "error": "Missing preset_name parameter"}
    manager = get_preset_manager()
    preset = manager.load_preset(preset_name)
    if not preset:
        return {"success": False, "error": f"Preset not found: {preset_name}"}
    return {"success": True, "preset": preset.to_dict()}


def _cmd_save_as_preset(params: Dict[str, Any]) -> Dict[str, Any]:
    """Handler MCP: Guarda configuración actual como preset."""
    config, preset_name = params.get("config", {}), params.get("preset_name", "")
    if not preset_name:
        return {"success": False, "error": "Missing preset_name parameter"}
    success = get_preset_manager().save_as_preset(config, preset_name)
    return {"success": success, "preset_name": preset_name, "message": f"Preset '{preset_name}' saved" if success else "Failed to save"}


def _cmd_list_presets(params: Dict[str, Any]) -> Dict[str, Any]:
    """Handler MCP: Lista todos los presets disponibles."""
    manager = get_preset_manager()
    presets = manager.list_presets(include_builtin=params.get("include_builtin", True), filter_tags=params.get("filter_tags"))
    return {"success": True, "count": len(presets), "presets": presets}


def _cmd_create_custom_preset(params: Dict[str, Any]) -> Dict[str, Any]:
    """Handler MCP: Crea un preset personalizado."""
    current_config, name = params.get("current_config", {}), params.get("name", "")
    if not name:
        return {"success": False, "error": "Missing name parameter"}
    preset = get_preset_manager().create_custom_preset(current_config, name, params.get("description", ""), params.get("tags"))
    return {"success": preset is not None, "preset_name": name, "preset": preset.to_dict() if preset else None}


def _cmd_delete_preset(params: Dict[str, Any]) -> Dict[str, Any]:
    """Handler MCP: Elimina un preset personalizado."""
    preset_name = params.get("preset_name", "")
    if not preset_name:
        return {"success": False, "error": "Missing preset_name parameter"}
    success = get_preset_manager().delete_preset(preset_name)
    return {"success": success, "message": f"Preset '{preset_name}' deleted" if success else f"Failed to delete '{preset_name}'"}


def _cmd_export_preset(params: Dict[str, Any]) -> Dict[str, Any]:
    """Handler MCP: Exporta un preset a archivo."""
    preset_name, export_path = params.get("preset_name", ""), params.get("export_path", "")
    if not preset_name or not export_path:
        return {"success": False, "error": "Missing preset_name or export_path"}
    success = get_preset_manager().export_preset(preset_name, export_path)
    return {"success": success, "message": f"Exported to {export_path}" if success else "Export failed"}


def _cmd_import_preset(params: Dict[str, Any]) -> Dict[str, Any]:
    """Handler MCP: Importa un preset desde archivo."""
    import_path = params.get("import_path", "")
    if not import_path:
        return {"success": False, "error": "Missing import_path parameter"}
    preset = get_preset_manager().import_preset(import_path, params.get("preset_name"))
    return {"success": preset is not None, "preset_name": preset.name if preset else None, "preset": preset.to_dict() if preset else None}


def _cmd_get_preset_details(params: Dict[str, Any]) -> Dict[str, Any]:
    """Handler MCP: Obtiene detalles completos de un preset."""
    preset_name = params.get("preset_name", "")
    if not preset_name:
        return {"success": False, "error": "Missing preset_name parameter"}
    details = get_preset_manager().get_preset_details(preset_name)
    return {"success": details is not None, "preset": details, "error": f"Preset not found: {preset_name}" if not details else None}


def _cmd_duplicate_preset(params: Dict[str, Any]) -> Dict[str, Any]:
    """Handler MCP: Duplica un preset existente."""
    source_name, new_name = params.get("source_name", ""), params.get("new_name", "")
    if not source_name or not new_name:
        return {"success": False, "error": "Missing source_name or new_name"}
    success = get_preset_manager().duplicate_preset(source_name, new_name)
    return {"success": success, "message": f"Duplicated: {source_name} -> {new_name}" if success else "Duplication failed"}


# Mapa de handlers disponibles para el MCP server
MCP_HANDLERS = {
    "load_preset": _cmd_load_preset,
    "save_as_preset": _cmd_save_as_preset,
    "list_presets": _cmd_list_presets,
    "create_custom_preset": _cmd_create_custom_preset,
    "delete_preset": _cmd_delete_preset,
    "export_preset": _cmd_export_preset,
    "import_preset": _cmd_import_preset,
    "get_preset_details": _cmd_get_preset_details,
    "duplicate_preset": _cmd_duplicate_preset,
    "apply_preset": lambda p: apply_preset_to_project(p.get("preset_name", "")),
}


# =============================================================================
# MAIN / TEST
# =============================================================================

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    print("=" * 70)
    print("PRESET SYSTEM - AbletonMCP_AI")
    print("=" * 70)
    print("\n1. Inicializando PresetManager...")
    manager = get_preset_manager()
    print(f"   OK - Directorio: {manager._presets_dir}")
    print("\n2. Presets predefinidos:")
    for name, preset in manager._builtin_presets.items():
        print(f"   - {name}: {preset.description[:45]}...")
    print("\n3. Listando todos los presets...")
    all_presets = manager.list_presets()
    print(f"   Total: {len(all_presets)} presets")
    for p in all_presets[:5]:
        print(f"   - {p['name']} ({p['style']}, {p['bpm']} BPM, {p['track_count']} tracks)")
    print("\n4. Cargando 'reggaeton_classic_95bpm'...")
    classic = manager.load_preset("reggaeton_classic_95bpm")
    if classic:
        print(f"   BPM: {classic.bpm}, Key: {classic.key}, Tracks: {len(classic.tracks_config)}")
    print("\n5. Detalles de 'perreo_intenso_100bpm'...")
    details = manager.get_preset_details("perreo_intenso_100bpm")
    if details:
        print(f"   EQ Low: {details['mixing']['eq_low_gain']} dB, Comp: {details['mixing']['compressor_threshold']} dB")
    print("\n6. Aplicando preset default...")
    result = quick_apply_preset()
    print(f"   Success: {result['success']}, Preset: {result.get('preset_name')}")
    print("\n" + "=" * 70)
    print("Tests completados!")
    print("=" * 70)
