"""Session persistence.

Sessions bind templates to specific test data and store user overrides
in a ``.impakt/`` subdirectory alongside the test data.
"""

from __future__ import annotations

import logging
from pathlib import Path
from typing import Any

from impakt.template.library import TemplateLibrary
from impakt.template.model import SessionState, TemplateSpec

logger = logging.getLogger(__name__)

IMPAKT_DIR = ".impakt"
SESSION_FILE = "session.yaml"
CACHE_DIR = "cache"


class SessionManager:
    """Manages session state for a test data directory."""

    def __init__(self, test_path: Path) -> None:
        self.test_path = Path(test_path).resolve()
        self.impakt_dir = self.test_path / IMPAKT_DIR
        self.session_file = self.impakt_dir / SESSION_FILE
        self.cache_dir = self.impakt_dir / CACHE_DIR
        self._state: SessionState | None = None

    @property
    def state(self) -> SessionState:
        """Load or create session state."""
        if self._state is None:
            if self.session_file.exists():
                self._state = SessionState.load(self.session_file)
                logger.debug("Loaded session from %s", self.session_file)
            else:
                self._state = SessionState(test_path=str(self.test_path))
        return self._state

    def save(self) -> None:
        """Persist current session state."""
        self.impakt_dir.mkdir(parents=True, exist_ok=True)
        self.state.save(self.session_file)
        logger.debug("Saved session to %s", self.session_file)

    def apply_template(self, template: TemplateSpec) -> None:
        """Bind a template to this session."""
        self.state.template_name = template.name
        self.state.template_version = template.version
        self.save()

    def set_override(self, key: str, value: Any) -> None:
        """Store a user override."""
        self.state.set_override(key, value)
        self.save()

    def cache_result(self, key: str, value: Any) -> None:
        """Cache a computation result."""
        self.state.cached_results[key] = value
        self.save()

    def get_cached(self, key: str) -> Any:
        """Retrieve a cached result, or None."""
        return self.state.cached_results.get(key)

    def promote_to_template(self, library: TemplateLibrary | None = None) -> TemplateSpec:
        """Promote session overrides back to a new or updated template.

        Creates a new template incorporating the session's overrides.
        """
        if library is None:
            library = TemplateLibrary()

        # Try to load the base template
        try:
            base = library.get(self.state.template_name)
        except FileNotFoundError:
            base = TemplateSpec(name=self.state.template_name)

        # Apply overrides (deep merge would go here)
        # For now, just update version and save
        base = TemplateSpec(
            name=base.name,
            version=base.version + 1,
            description=base.description,
            plots=base.plots,
            default_cfc=base.default_cfc,
            criteria=base.criteria,
            protocol=base.protocol,
            protocol_version=base.protocol_version,
            report_format=base.report_format,
            report_template=base.report_template,
            corridors=base.corridors,
            metadata={**base.metadata, "promoted_overrides": self.state.overrides},
        )

        library.save(base)
        logger.info("Promoted session overrides to template '%s' v%d", base.name, base.version)
        return base

    @property
    def has_session(self) -> bool:
        """Whether a session file exists."""
        return self.session_file.exists()

    def clear(self) -> None:
        """Remove session state and cache."""
        if self.session_file.exists():
            self.session_file.unlink()
        if self.cache_dir.exists():
            import shutil

            shutil.rmtree(self.cache_dir)
        self._state = None
