"""Profile store for imported profiles."""

from __future__ import annotations

import logging
from pathlib import Path
from typing import TYPE_CHECKING

import yaml

from gaol.config import get_config_dir
from gaol.models.profile import Profile
from gaol.sharing.exceptions import ProfileExistsError

if TYPE_CHECKING:
    from gaol.sharing.models import ImportedContentMetadata

logger = logging.getLogger(__name__)


class ProfileStore:
    """Store imported profiles locally.

    Stores profiles in ~/.config/gaol/profiles/imported/.
    Each profile is stored as a YAML file with optional metadata.

    Example:
        >>> store = ProfileStore()
        >>> store.save(profile, name="my-dev")
        >>> profile = store.get("my-dev")
        >>> store.list()
        ['my-dev', 'web-server']
    """

    STORE_SUBDIR = "profiles/imported"
    METADATA_SUFFIX = ".meta.yaml"

    def __init__(self, store_dir: Path | None = None) -> None:
        """Initialize the profile store.

        Args:
            store_dir: Custom store directory (defaults to config dir)
        """
        if store_dir is not None:
            self._store_dir = store_dir
        else:
            self._store_dir = get_config_dir() / self.STORE_SUBDIR
        self._store_dir.mkdir(parents=True, exist_ok=True)

    @property
    def store_dir(self) -> Path:
        """Get the store directory."""
        return self._store_dir

    def save(
        self,
        profile: Profile,
        name: str | None = None,
        metadata: ImportedContentMetadata | None = None,
        overwrite: bool = False,
    ) -> Path:
        """Save a profile to the store.

        Args:
            profile: Profile to save
            name: Name for the profile (uses profile.name if None)
            metadata: Optional import metadata
            overwrite: Overwrite if exists

        Returns:
            Path where profile was saved

        Raises:
            ProfileExistsError: If profile exists and overwrite=False
        """
        profile_name = name or profile.name
        profile_path = self._profile_path(profile_name)

        if profile_path.exists() and not overwrite:
            raise ProfileExistsError(profile_name, str(profile_path))

        # Save profile as YAML
        profile_data = profile.model_dump(exclude_defaults=True, exclude_none=True)
        profile_data["name"] = profile_name  # Ensure name matches

        with open(profile_path, "w") as f:
            yaml.dump(profile_data, f, default_flow_style=False, sort_keys=False)

        logger.info(f"Saved profile '{profile_name}' to {profile_path}")

        # Save metadata if provided
        if metadata is not None:
            metadata_path = self._metadata_path(profile_name)
            with open(metadata_path, "w") as f:
                yaml.dump(
                    metadata.model_dump(exclude_none=True),
                    f,
                    default_flow_style=False,
                )

        return profile_path

    def get(self, name: str) -> Profile | None:
        """Get a profile by name.

        Args:
            name: Profile name

        Returns:
            Profile or None if not found
        """
        profile_path = self._profile_path(name)

        if not profile_path.exists():
            return None

        with open(profile_path) as f:
            data = yaml.safe_load(f)

        return Profile.from_yaml(data)

    def get_metadata(self, name: str) -> dict | None:
        """Get metadata for a profile.

        Args:
            name: Profile name

        Returns:
            Metadata dict or None if not found
        """
        metadata_path = self._metadata_path(name)

        if not metadata_path.exists():
            return None

        with open(metadata_path) as f:
            return yaml.safe_load(f)

    def delete(self, name: str) -> bool:
        """Delete a profile from the store.

        Args:
            name: Profile name

        Returns:
            True if deleted, False if not found
        """
        profile_path = self._profile_path(name)
        metadata_path = self._metadata_path(name)

        if not profile_path.exists():
            return False

        profile_path.unlink()
        if metadata_path.exists():
            metadata_path.unlink()

        logger.info(f"Deleted profile '{name}'")
        return True

    def list(self) -> list[str]:
        """List all stored profile names.

        Returns:
            Sorted list of profile names
        """
        profiles = []
        for path in self._store_dir.glob("*.yaml"):
            # Skip metadata files
            if path.name.endswith(self.METADATA_SUFFIX):
                continue
            profiles.append(path.stem)
        return sorted(profiles)

    def exists(self, name: str) -> bool:
        """Check if a profile exists.

        Args:
            name: Profile name

        Returns:
            True if profile exists
        """
        return self._profile_path(name).exists()

    def _profile_path(self, name: str) -> Path:
        """Get the path for a profile file."""
        return self._store_dir / f"{name}.yaml"

    def _metadata_path(self, name: str) -> Path:
        """Get the path for a profile's metadata file."""
        return self._store_dir / f"{name}{self.METADATA_SUFFIX}"


# Module-level store instance
_store: ProfileStore | None = None


def get_profile_store() -> ProfileStore:
    """Get the global profile store instance.

    Returns:
        ProfileStore instance
    """
    global _store
    if _store is None:
        _store = ProfileStore()
    return _store
