"""
Manages requirements.txt (or custom-named file) automatically.
Tracks pip install / pip uninstall events.
"""

from __future__ import annotations

import re
import subprocess
from pathlib import Path
from typing import Dict, List, Optional

from venvy.utils.console import console


def _parse_requirements(req_file: Path) -> Dict[str, str]:
    """
    Parse a requirements file into {package_name: line} dict.
    Keys are lowercased package names for comparison.
    """
    if not req_file.exists():
        return {}
    lines = req_file.read_text(encoding="utf-8").splitlines()
    packages: Dict[str, str] = {}
    for line in lines:
        stripped = line.strip()
        if not stripped or stripped.startswith("#"):
            continue
        # Extract package name (before ==, >=, etc.)
        match = re.match(r"^([A-Za-z0-9_\-\.]+)", stripped)
        if match:
            name = match.group(1).lower().replace("-", "_")
            packages[name] = stripped
    return packages


def _write_requirements(req_file: Path, packages: Dict[str, str]) -> None:
    """Write packages dict back to requirements file, sorted."""
    lines = sorted(packages.values(), key=str.lower)
    req_file.write_text("\n".join(lines) + "\n", encoding="utf-8")


def _get_installed_version(python_exe: str, package: str) -> Optional[str]:
    """Get the installed version of a package using pip show."""
    result = subprocess.run(
        [python_exe, "-m", "pip", "show", package],
        capture_output=True,
        text=True,
    )
    if result.returncode != 0:
        return None
    for line in result.stdout.splitlines():
        if line.startswith("Version:"):
            return line.split(":", 1)[1].strip()
    return None


def add_packages_to_requirements(
    packages: List[str],
    req_file: Path,
    python_exe: str,
) -> None:
    """
    Add installed packages (with pinned versions) to requirements file.
    Creates the file if it doesn't exist (after confirmation).
    """
    if not req_file.exists():
        console.print(
            f"\n[yellow]?[/yellow] Requirements file [bold]{req_file.name}[/bold] not found."
        )
        create = console.input("  Create it now? [Y/n]: ").strip().lower()
        if create in ("", "y", "yes"):
            req_file.touch()
            console.print(f"[green]✓[/green] Created [bold]{req_file}[/bold]")
        else:
            console.print("[dim]Skipped requirements update.[/dim]")
            return

    existing = _parse_requirements(req_file)
    updated = False

    for pkg in packages:
        # Strip extras like package[extra]
        pkg_clean = re.sub(r"\[.*\]", "", pkg).strip()
        pkg_clean = re.sub(r"[><=!;].*", "", pkg_clean).strip()
        if not pkg_clean:
            continue

        version = _get_installed_version(python_exe, pkg_clean)
        if version:
            key = pkg_clean.lower().replace("-", "_")
            entry = f"{pkg_clean}=={version}"
            if existing.get(key) != entry:
                existing[key] = entry
                updated = True
                console.print(
                    f"[green]✓[/green] Added [bold]{entry}[/bold] to [dim]{req_file.name}[/dim]"
                )

    if updated:
        _write_requirements(req_file, existing)


def remove_packages_from_requirements(
    packages: List[str],
    req_file: Path,
) -> None:
    """Remove uninstalled packages from the requirements file."""
    if not req_file.exists():
        return

    existing = _parse_requirements(req_file)
    updated = False

    for pkg in packages:
        pkg_clean = re.sub(r"\[.*\]", "", pkg).strip()
        pkg_clean = re.sub(r"[><=!;].*", "", pkg_clean).strip()
        if not pkg_clean:
            continue
        key = pkg_clean.lower().replace("-", "_")
        if key in existing:
            del existing[key]
            updated = True
            console.print(
                f"[green]✓[/green] Removed [bold]{pkg_clean}[/bold] from [dim]{req_file.name}[/dim]"
            )

    if updated:
        _write_requirements(req_file, existing)


def sync_requirements_to_venv(req_file: Path, python_exe: str) -> None:
    """Install all packages from requirements file into the venv."""
    if not req_file.exists():
        console.print(f"[red]✗[/red] Requirements file not found: {req_file}")
        return
    console.print(f"[cyan]→[/cyan] Installing from [bold]{req_file.name}[/bold]...")
    result = subprocess.run(
        [python_exe, "-m", "pip", "install", "-r", str(req_file)],
        text=True,
    )
    if result.returncode == 0:
        console.print("[green]✓[/green] All packages installed.")
    else:
        console.print("[red]✗[/red] Some packages failed to install.")


def list_requirements(req_file: Path) -> None:
    """Pretty-print current requirements."""
    if not req_file.exists():
        console.print(f"[yellow]No requirements file found: {req_file.name}[/yellow]")
        return
    packages = _parse_requirements(req_file)
    if not packages:
        console.print("[dim]No packages in requirements file.[/dim]")
        return
    console.print(f"\n[bold]Packages in {req_file.name}:[/bold]")
    for entry in sorted(packages.values()):
        console.print(f"  [cyan]•[/cyan] {entry}")
    console.print()
