"""User template storage.

Handles saving and loading user-created templates to the local filesystem.
"""

from __future__ import annotations

import logging
from datetime import datetime
from pathlib import Path

import yaml

from gaol.config import get_config_dir
from gaol.templates.exceptions import (
    TemplateExistsError,
    TemplateNotFoundError,
    TemplateParseError,
    TemplateStoreError,
)
from gaol.templates.models import Template, TemplateMetadata

logger = logging.getLogger(__name__)


class TemplateStore:
    """Persistent storage for user-created templates.

    Templates are stored as YAML files in ~/.config/gaol/templates/
    with the structure {category}/{name}.yaml matching the template ID.
    """

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

        Args:
            store_dir: Directory to store templates. Defaults to
                       ~/.config/gaol/templates/
        """
        if store_dir is None:
            store_dir = get_config_dir() / "templates"
        self._store_dir = store_dir
        self._store_dir.mkdir(parents=True, exist_ok=True)

    def _get_path(self, template_id: str) -> Path:
        """Get the path for a template file.

        Args:
            template_id: Template ID (e.g., 'custom/my-template')

        Returns:
            Path to the template YAML file
        """
        # Template ID is category/name
        parts = template_id.split("/", 1)
        if len(parts) == 2:
            category, name = parts
            category_dir = self._store_dir / category
            category_dir.mkdir(parents=True, exist_ok=True)
            return category_dir / f"{name}.yaml"
        else:
            return self._store_dir / f"{template_id}.yaml"

    def save(
        self,
        template: Template,
        overwrite: bool = False,
    ) -> Path:
        """Save a template to the store.

        Args:
            template: Template to save
            overwrite: Whether to overwrite existing template

        Returns:
            Path to the saved template file

        Raises:
            TemplateExistsError: If template exists and overwrite is False
            TemplateStoreError: If save fails
        """
        path = self._get_path(template.metadata.id)

        if path.exists() and not overwrite:
            raise TemplateExistsError(template.metadata.id, str(path))

        # Update timestamp
        template.metadata.updated_at = datetime.now()
        if template.metadata.created_at is None:
            template.metadata.created_at = template.metadata.updated_at

        try:
            data = template.to_dict()
            content = yaml.dump(data, default_flow_style=False, sort_keys=False)
            path.write_text(content)
            logger.debug(f"Saved template to {path}")
            return path
        except Exception as e:
            raise TemplateStoreError("save", str(e)) from e

    def get(self, template_id: str) -> Template | None:
        """Get a template from the store.

        Args:
            template_id: Template ID

        Returns:
            Template if found, None otherwise
        """
        path = self._get_path(template_id)
        if not path.exists():
            return None

        try:
            content = path.read_text()
            data = yaml.safe_load(content)
            return Template.from_dict(data)
        except Exception as e:
            logger.warning(f"Failed to load template {template_id}: {e}")
            return None

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

        Args:
            template_id: Template ID

        Returns:
            True if deleted, False if not found
        """
        path = self._get_path(template_id)
        if not path.exists():
            return False

        try:
            path.unlink()
            logger.debug(f"Deleted template {template_id}")

            # Clean up empty category directory
            category_dir = path.parent
            if category_dir != self._store_dir and not any(category_dir.iterdir()):
                category_dir.rmdir()

            return True
        except Exception as e:
            logger.error(f"Failed to delete template {template_id}: {e}")
            return False

    def list(self, category: str | None = None) -> list[Template]:
        """List all templates in the store.

        Args:
            category: Filter by category (optional)

        Returns:
            List of templates
        """
        templates = []

        if category:
            # List templates in specific category
            category_dir = self._store_dir / category
            if category_dir.exists():
                for path in category_dir.glob("*.yaml"):
                    template_id = f"{category}/{path.stem}"
                    template = self.get(template_id)
                    if template:
                        templates.append(template)
        else:
            # List all templates
            for category_dir in self._store_dir.iterdir():
                if category_dir.is_dir():
                    for path in category_dir.glob("*.yaml"):
                        template_id = f"{category_dir.name}/{path.stem}"
                        template = self.get(template_id)
                        if template:
                            templates.append(template)

            # Also check for templates in root (no category)
            for path in self._store_dir.glob("*.yaml"):
                template_id = path.stem
                template = self.get(template_id)
                if template:
                    templates.append(template)

        return templates

    def list_ids(self, category: str | None = None) -> list[str]:
        """List all template IDs in the store.

        Args:
            category: Filter by category (optional)

        Returns:
            List of template IDs
        """
        ids = []

        if category:
            category_dir = self._store_dir / category
            if category_dir.exists():
                for path in category_dir.glob("*.yaml"):
                    ids.append(f"{category}/{path.stem}")
        else:
            for category_dir in self._store_dir.iterdir():
                if category_dir.is_dir():
                    for path in category_dir.glob("*.yaml"):
                        ids.append(f"{category_dir.name}/{path.stem}")
            # Root templates
            for path in self._store_dir.glob("*.yaml"):
                ids.append(path.stem)

        return sorted(ids)

    def exists(self, template_id: str) -> bool:
        """Check if a template exists in the store.

        Args:
            template_id: Template ID

        Returns:
            True if template exists
        """
        return self._get_path(template_id).exists()

    def get_categories(self) -> list[str]:
        """Get all categories in the store.

        Returns:
            List of category names
        """
        categories = []
        for path in self._store_dir.iterdir():
            if path.is_dir() and any(path.glob("*.yaml")):
                categories.append(path.name)
        return sorted(categories)


# Module-level store instance
_template_store: TemplateStore | None = None


def get_template_store() -> TemplateStore:
    """Get the global template store instance.

    Returns:
        TemplateStore instance
    """
    global _template_store
    if _template_store is None:
        _template_store = TemplateStore()
    return _template_store
