"""Dependency manager — venv creation and pip install for Alive skills."""

from __future__ import annotations

import subprocess
import sys
import venv
from pathlib import Path

PIP_TIMEOUT = 120


class DependencyManager:
    """Manages the shared venv at ~/.alive/venv/ for skill dependencies."""

    def __init__(self, venv_dir: Path | None = None) -> None:
        from alive.config import VENV_DIR

        self._venv_dir = venv_dir or VENV_DIR

    @property
    def python(self) -> Path:
        """Path to the venv Python binary."""
        if sys.platform == "win32":
            return self._venv_dir / "Scripts" / "python.exe"
        return self._venv_dir / "bin" / "python"

    @property
    def venv_dir(self) -> Path:
        return self._venv_dir

    def ensure_venv(self) -> None:
        """Create the shared venv if it doesn't exist."""
        if not self.python.exists():
            self._venv_dir.mkdir(parents=True, exist_ok=True)
            venv.create(str(self._venv_dir), with_pip=True)

    def install(self, packages: list[str]) -> None:
        """pip install packages into the shared venv.

        Filters out standard library modules before installing.
        Raises RuntimeError if installation fails.
        """
        if not packages:
            return
        # Filter out stdlib modules (LLMs often list them as deps)
        to_install = [p for p in packages if p not in sys.stdlib_module_names]
        if not to_install:
            return
        self.ensure_venv()
        proc = subprocess.run(
            [str(self.python), "-m", "pip", "install", "--quiet", *to_install],
            capture_output=True,
            text=True,
            timeout=PIP_TIMEOUT,
        )
        if proc.returncode != 0:
            raise RuntimeError(
                f"Failed to install {to_install}:\n{proc.stderr}"
            )

    def is_installed(self, package: str) -> bool:
        """Check if a package is installed in the venv."""
        if not self.python.exists():
            return False
        proc = subprocess.run(
            [str(self.python), "-m", "pip", "show", "--quiet", package],
            capture_output=True,
            text=True,
            timeout=30,
        )
        return proc.returncode == 0


# ── Module-level singleton ──────────────────────────────────────────────────

_default_manager: DependencyManager | None = None


def get_dependency_manager() -> DependencyManager:
    """Get or create the default DependencyManager."""
    global _default_manager
    if _default_manager is None:
        _default_manager = DependencyManager()
    return _default_manager
