"""Package management utilities for per-app environments."""

import subprocess
import sys
from pathlib import Path
from typing import Optional

from scry_run.console import status, success, error, warning


def get_venv_python(app_dir: Path) -> Path:
    """Get path to Python executable in venv, cross-platform.

    Args:
        app_dir: Path to the app directory

    Returns:
        Path to the Python executable in the app's venv
    """
    if sys.platform == "win32":
        return app_dir / ".venv" / "Scripts" / "python.exe"
    return app_dir / ".venv" / "bin" / "python"


def get_scry_run_source_path() -> Optional[Path]:
    """Get the source path if scry-run is installed in development mode.

    Returns:
        Path to source directory if dev install, None if PyPI install
    """
    import scry_run
    package_path = Path(scry_run.__file__).parent
    # Go up to the project root (src/scry_run -> src -> project_root)
    project_root = package_path.parent.parent
    
    # Check if we're in development mode (can access pyproject.toml and src/)
    if (project_root / "pyproject.toml").exists() and (project_root / "src" / "scry_run").exists():
        return project_root

    return None


def is_scry_run_installed(app_dir: Path) -> bool:
    """Check if scry-run is installed in the app's venv.

    Args:
        app_dir: Path to the app directory

    Returns:
        True if scry-run is available in the app's venv
    """
    python_path = get_venv_python(app_dir)
    if not python_path.exists():
        return False

    result = subprocess.run(
        [str(python_path), "-c", "import scry_run"],
        capture_output=True,
    )
    return result.returncode == 0


def ensure_scry_run_installed(app_dir: Path) -> None:
    """Ensure scry-run is installed in the app's virtual environment.

    In development mode (source install), installs from local path with -e.
    In production mode (PyPI install), installs from PyPI.

    Args:
        app_dir: Path to the app directory
    """
    ensure_venv(app_dir)

    if is_scry_run_installed(app_dir):
        return

    source_path = get_scry_run_source_path()
    python_path = get_venv_python(app_dir)

    if source_path:
        # Development mode - editable install from source
        status(f"Installing scry-run from source ({source_path.name})...")
        cmd = ["uv", "pip", "install", "--python", str(python_path), "-e", str(source_path)]
    else:
        # Production mode - install from PyPI
        status("Installing scry-run from PyPI...")
        cmd = ["uv", "pip", "install", "--python", str(python_path), "scry-run"]

    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        error(f"Failed to install scry-run: {result.stderr}")
        raise RuntimeError(f"Failed to install scry-run: {result.stderr}")

    success("Installed scry-run")


def ensure_venv(app_dir: Path) -> None:
    """Ensure a virtual environment exists for the app.

    Args:
        app_dir: Path to the app directory
    """
    venv_path = app_dir / ".venv"
    if venv_path.exists():
        return

    status(f"Creating virtual environment in {app_dir.name}...")
    result = subprocess.run(
        ["uv", "venv"],
        cwd=app_dir,
        capture_output=True,
        text=True,
    )
    if result.returncode != 0:
        error(f"Failed to create venv: {result.stderr}")
        raise RuntimeError(f"uv venv failed: {result.stderr}")


def install_packages(app_dir: Path, packages: list[str]) -> None:
    """Install packages into the app's virtual environment.

    Args:
        app_dir: Path to the app directory
        packages: List of package specs (e.g., ["pygame", "requests>=2.0"])
    """
    if not packages:
        return

    # Ensure venv exists
    ensure_venv(app_dir)

    status(f"Installing packages: {', '.join(packages)}")
    python_path = get_venv_python(app_dir)
    result = subprocess.run(
        ["uv", "pip", "install", "--python", str(python_path)] + packages,
        capture_output=True,
        text=True,
    )
    if result.returncode != 0:
        error(f"Failed to install packages: {result.stderr}")
        raise RuntimeError(f"uv pip install failed: {result.stderr}")

    success(f"Installed {len(packages)} package(s)")


def get_installed_packages(app_dir: Path) -> list[str]:
    """Get list of installed packages in the app's environment.

    Args:
        app_dir: Path to the app directory

    Returns:
        List of "package==version" strings
    """
    venv_path = app_dir / ".venv"
    if not venv_path.exists():
        return []

    python_path = get_venv_python(app_dir)
    result = subprocess.run(
        ["uv", "pip", "list", "--format=freeze", "--python", str(python_path)],
        capture_output=True,
        text=True,
    )
    if result.returncode != 0:
        warning(f"Failed to list packages in {app_dir.name}")
        return []

    packages = []
    for line in result.stdout.strip().split("\n"):
        line = line.strip()
        if line and not line.startswith("#"):
            packages.append(line)

    return packages
