"""
venvy.commands.requirements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Manual requirements management commands:
  venvy add <package>       — install + add to requirements
  venvy remove <package>    — uninstall + remove from requirements
  venvy sync                — install all packages from requirements.txt
  venvy freeze              — update requirements.txt from current venv
"""

from __future__ import annotations

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

import typer
from rich.console import Console

from venvy.core.config import VenvyConfig
from venvy.core.requirements import RequirementsManager
from venvy.core.venv import VenvManager

console = Console()


def _resolve_context() -> tuple[Optional[VenvManager], Optional[RequirementsManager], Path]:
    """Resolve venv and requirements manager from current context."""
    cwd = Path.cwd()
    config = VenvyConfig.find(cwd)
    root = VenvyConfig.find_root(cwd) or cwd

    if config:
        venv_mgr = VenvManager(project_root=root, venv_name=config.venv_name)
        req_path = root / config.requirements_file
    else:
        # Try to detect any active/local venv
        from venvy.core.venv import VenvManager as VM, IS_WINDOWS
        import os
        active = os.environ.get("VIRTUAL_ENV")
        if active:
            venv_mgr = VM(project_root=Path(active).parent, venv_name=Path(active).name)
        else:
            found = VM.find_venv_in_project(cwd)
            venv_mgr = VM(project_root=cwd, venv_name=found.name) if found else None
        req_path = cwd / "requirements.txt"

    req_mgr = RequirementsManager(req_path)
    return venv_mgr, req_mgr, root


def cmd_add(packages: List[str], no_req: bool = False) -> None:
    """Install packages and add them to requirements.txt."""
    venv_mgr, req_mgr, root = _resolve_context()

    pip = str(venv_mgr.pip_executable) if venv_mgr and venv_mgr.exists else "pip"

    for package in packages:
        console.print(f"[cyan]Installing {package}...[/cyan]")
        result = subprocess.run(
            [pip, "install", package],
            check=False,
        )
        if result.returncode != 0:
            console.print(f"[red]✗ Failed to install {package}[/red]")
            continue

        if not no_req:
            # Get installed version
            version = _get_version(pip, package)
            if version:
                if not req_mgr.exists:
                    req_mgr.create_empty()
                changed = req_mgr.add_or_update(package, version)
                if changed:
                    console.print(
                        f"[green]✓[/green] {package}=={version} → {req_mgr.filepath.name}"
                    )
                else:
                    console.print(f"[green]✓[/green] Installed {package}=={version}")


def cmd_remove(packages: List[str], no_req: bool = False) -> None:
    """Uninstall packages and remove them from requirements.txt."""
    venv_mgr, req_mgr, root = _resolve_context()

    pip = str(venv_mgr.pip_executable) if venv_mgr and venv_mgr.exists else "pip"

    for package in packages:
        console.print(f"[cyan]Uninstalling {package}...[/cyan]")
        result = subprocess.run(
            [pip, "uninstall", "-y", package],
            check=False,
        )
        if result.returncode != 0:
            console.print(f"[yellow]⚠ pip uninstall failed for {package}[/yellow]")

        if not no_req and req_mgr.exists:
            removed = req_mgr.remove(package)
            if removed:
                console.print(f"[green]✓[/green] Removed {package} from {req_mgr.filepath.name}")
            else:
                console.print(f"[dim]{package} not found in {req_mgr.filepath.name}[/dim]")


def cmd_sync() -> None:
    """Install all packages from requirements.txt into the venv."""
    venv_mgr, req_mgr, root = _resolve_context()

    if not req_mgr.exists:
        console.print(f"[red]No {req_mgr.filepath.name} found.[/red]")
        raise typer.Exit(1)

    pip = str(venv_mgr.pip_executable) if venv_mgr and venv_mgr.exists else "pip"

    console.print(f"[cyan]Installing from {req_mgr.filepath.name}...[/cyan]")
    result = subprocess.run(
        [pip, "install", "-r", str(req_mgr.filepath)],
        check=False,
    )
    if result.returncode == 0:
        console.print("[green]✓ All packages installed.[/green]")
    else:
        console.print("[red]✗ Some packages failed to install.[/red]")
        raise typer.Exit(1)


def cmd_freeze() -> None:
    """Update requirements.txt to match currently installed packages."""
    venv_mgr, req_mgr, root = _resolve_context()

    if not venv_mgr or not venv_mgr.exists:
        console.print("[red]No virtual environment found.[/red]")
        raise typer.Exit(1)

    installed = venv_mgr.get_installed_packages()
    # Filter out pip, setuptools, wheel (meta packages)
    meta = {"pip", "setuptools", "wheel", "pkg-resources"}
    packages = {k: v for k, v in installed.items() if k not in meta}

    count = req_mgr.sync_from_installed(packages)
    console.print(
        f"[green]✓[/green] Wrote {count} packages to {req_mgr.filepath.name}"
    )


def _get_version(pip: str, package: str) -> Optional[str]:
    try:
        result = subprocess.run(
            [pip, "show", package],
            capture_output=True, text=True, check=False
        )
        for line in result.stdout.splitlines():
            if line.startswith("Version:"):
                return line.split(":", 1)[1].strip()
    except Exception:
        pass
    return None
