"""
Preset pack manager for loading, validating, and managing preset packs.
"""

import logging
import os
from typing import Dict, List, Optional

import tomli

from sideline.preset_packs.pack_format import PresetPack, PresetPackMetadata
from sideline.preset_packs.encoder import PresetPackEncoder
from sideline.plugins.compatibility import CompatibilityManager

logger = logging.getLogger(__name__)


class PresetPackManager:
    """Manages preset pack loading and validation."""

    def __init__(self, pack_dir: Optional[str] = None):
        """Initialize preset pack manager.

        Args:
            pack_dir: Directory to search for preset packs
        """
        self.pack_dir = pack_dir or os.path.expanduser("~/.config/sideline/packs")
        self._packs: Dict[str, PresetPack] = {}

    def load_pack(self, pack_path: str) -> Optional[PresetPack]:
        """Load a preset pack from a file.

        Args:
            pack_path: Path to the preset pack file (.tpack or .toml)

        Returns:
            Loaded PresetPack or None if failed
        """
        try:
            with open(pack_path, "rb") as f:
                # Try loading as TOML first
                if pack_path.endswith(".toml"):
                    data = tomli.load(f)
                    pack = PresetPack.from_dict(data)
                elif pack_path.endswith(".tpack"):
                    # Load ASCII art encoded pack
                    content = f.read().decode("utf-8")
                    pack = self._load_ascii_pack(content)
                else:
                    logger.error(f"Unknown file format: {pack_path}")
                    return None

            # Validate compatibility
            if not CompatibilityManager.validate_compatibility(
                pack.metadata.sideline_version
            ):
                error = CompatibilityManager.get_compatibility_error(
                    pack.metadata.sideline_version
                )
                logger.warning(f"Pack {pack.metadata.name} incompatible: {error}")
                return None

            # Store pack
            self._packs[pack.metadata.name] = pack
            logger.info(
                f"Loaded preset pack: {pack.metadata.name} v{pack.metadata.version}"
            )
            return pack

        except Exception as e:
            logger.error(f"Failed to load preset pack {pack_path}: {e}")
            return None

    def _load_ascii_pack(self, content: str) -> PresetPack:
        """Load pack from ASCII art encoded content."""
        # Extract TOML from ASCII art
        toml_data = PresetPackEncoder.decode_toml(content)

        # Parse TOML
        import tomli

        data = tomli.loads(toml_data)

        return PresetPack.from_dict(data)

    def load_directory(self, directory: Optional[str] = None) -> List[PresetPack]:
        """Load all preset packs from a directory.

        Args:
            directory: Directory to search (defaults to pack_dir)

        Returns:
            List of loaded PresetPack objects
        """
        directory = directory or self.pack_dir

        if not os.path.exists(directory):
            logger.warning(f"Preset pack directory does not exist: {directory}")
            return []

        loaded = []
        for filename in os.listdir(directory):
            if filename.endswith((".toml", ".tpack")):
                path = os.path.join(directory, filename)
                pack = self.load_pack(path)
                if pack:
                    loaded.append(pack)

        return loaded

    def save_pack(
        self, pack: PresetPack, output_path: str, format: str = "toml"
    ) -> bool:
        """Save a preset pack to a file.

        Args:
            pack: PresetPack to save
            output_path: Path to save the pack
            format: Output format ("toml" or "tpack")

        Returns:
            True if successful, False otherwise
        """
        try:
            if format == "toml":
                import tomli_w

                with open(output_path, "w") as f:
                    tomli_w.dump(pack.to_dict(), f)
            elif format == "tpack":
                # Encode as ASCII art
                toml_data = self._pack_to_toml(pack)
                ascii_art = PresetPackEncoder.encode_toml(toml_data, pack.metadata.name)

                with open(output_path, "w") as f:
                    f.write(ascii_art)
            else:
                logger.error(f"Unknown format: {format}")
                return False

            logger.info(f"Saved preset pack: {output_path}")
            return True

        except Exception as e:
            logger.error(f"Failed to save preset pack: {e}")
            return False

    def _pack_to_toml(self, pack: PresetPack) -> str:
        """Convert PresetPack to TOML string."""
        import tomli_w

        return tomli_w.dumps(pack.to_dict())

    def get_pack(self, name: str) -> Optional[PresetPack]:
        """Get a loaded preset pack by name."""
        return self._packs.get(name)

    def list_packs(self) -> List[str]:
        """List all loaded preset pack names."""
        return list(self._packs.keys())

    def register_pack_plugins(self, pack: PresetPack):
        """Register all plugins from a preset pack.

        Args:
            pack: PresetPack containing plugins
        """
        from sideline.pipeline import StageRegistry

        for plugin_entry in pack.plugins:
            try:
                # Decode plugin code
                code = PresetPackEncoder.decode_plugin_code(plugin_entry.encoded_code)

                # Execute plugin code to get the class
                local_ns = {}
                exec(code, local_ns)

                # Find the plugin class (first class defined)
                plugin_class = None
                for obj in local_ns.values():
                    if isinstance(obj, type) and hasattr(obj, "metadata"):
                        plugin_class = obj
                        break

                if plugin_class:
                    # Register the plugin
                    StageRegistry.register(plugin_entry.category, plugin_class)
                    logger.info(f"Registered plugin: {plugin_entry.name}")
                else:
                    logger.warning(f"No plugin class found in {plugin_entry.name}")

            except Exception as e:
                logger.error(f"Failed to register plugin {plugin_entry.name}: {e}")
