"""
venvy + / venvy -  — zero-setup venv activation.

The approach:
  venvy +  → spawns a new interactive shell with the venv activated.
             The user is now inside an activated environment.
             Their prompt shows (venv_name) as usual.

  venvy -  → just runs `exit` in the current shell (or tells the user to).
             If we're in a venvy-spawned shell, `exit` returns to the parent.

No shell integration or eval required. Works on Windows CMD, PowerShell,
bash, and zsh out of the box.
"""

from __future__ import annotations

import os
import subprocess
import sys
from pathlib import Path

from venvy.core.venv_manager import find_venv, get_venv_python
from venvy.utils.console import console
from venvy.utils.platform_utils import IS_WINDOWS, get_active_venv


def activate_command() -> None:
    """
    Spawn a new interactive shell with the venv activated.
    No eval, no shell-init, no setup. Works everywhere.
    """
    venv_path = find_venv()

    if not venv_path:
        console.print(
            "[red]✗[/red] No virtual environment found in this directory.\n"
            "  Run [bold]venvy create venv[/bold] to create one."
        )
        raise SystemExit(1)

    # Already inside a venvy shell for this venv?
    active = get_active_venv()
    if active and Path(active).resolve() == venv_path.resolve():
        console.print(
            f"[green]✓[/green] Already active: [bold]{venv_path.name}[/bold]\n"
            f"  Type [bold]exit[/bold] to deactivate."
        )
        return

    console.print(
        f"[green]✓[/green] Activating [bold]{venv_path.name}[/bold] "
        f"— spawning shell. Type [bold]exit[/bold] to deactivate.\n"
    )

    # Build new env with venv activated
    env = os.environ.copy()
    if IS_WINDOWS:
        scripts_dir = str(venv_path / "Scripts")
        env["PATH"] = scripts_dir + os.pathsep + env.get("PATH", "")
        env["VIRTUAL_ENV"] = str(venv_path)
        env.pop("PYTHONHOME", None)
        # Use PROMPT to show venv name — works in CMD
        env["PROMPT"] = f"({venv_path.name}) $P$G"
    else:
        bin_dir = str(venv_path / "bin")
        env["PATH"] = bin_dir + os.pathsep + env.get("PATH", "")
        env["VIRTUAL_ENV"] = str(venv_path)
        env.pop("PYTHONHOME", None)
        # PS1 shows venv name in bash/zsh
        base_ps1 = env.get("PS1", r"\u@\h:\w\$ ")
        env["PS1"] = f"({venv_path.name}) {base_ps1}"

    # Choose shell
    shell_cmd = _pick_shell()

    try:
        # Replace current process image with the shell (exec-style on Unix)
        # On Windows subprocess is used instead since os.execvpe is less reliable
        if IS_WINDOWS:
            result = subprocess.run(shell_cmd, env=env)
            raise SystemExit(result.returncode)
        else:
            os.execvpe(shell_cmd[0], shell_cmd, env)  # never returns
    except FileNotFoundError:
        console.print(f"[red]✗[/red] Shell not found: {shell_cmd[0]}")
        raise SystemExit(1)


def deactivate_command() -> None:
    """
    If in a venvy-spawned shell, `exit` returns to the parent shell.
    We just run exit for the user, or tell them to type it.
    """
    active = get_active_venv()
    if not active:
        console.print("[yellow]⚠[/yellow]  No virtual environment is currently active.")
        return

    venv_name = Path(active).name
    console.print(
        f"[cyan]→[/cyan] Deactivating [bold]{venv_name}[/bold]...\n"
        f"  (Exiting venvy shell — returning to parent shell)"
    )
    # Exit the shell spawned by `venvy +`
    # On Windows, this is a CMD/PowerShell process — `exit` closes it.
    # On Unix, we spawned a bash/zsh — `exit` returns to parent.
    raise SystemExit(0)


def shell_init_command() -> None:
    """
    Shell integration is now OPTIONAL — venvy + works without it.
    This command still exists for users who want pip auto-tracking in
    their native shell without using `venvy pip install`.
    """
    if IS_WINDOWS:
        _print_windows_init()
    else:
        _print_unix_init()


def find_venv_command() -> None:
    """Internal: print venv path for shell functions."""
    venv_path = find_venv()
    if venv_path:
        print(str(venv_path))


def _pick_shell() -> list:
    """Determine the best interactive shell to spawn."""
    if IS_WINDOWS:
        # Try PowerShell first, fall back to CMD
        if _cmd_exists("pwsh"):
            return ["pwsh", "-NoLogo", "-NoExit"]
        if _cmd_exists("powershell"):
            return ["powershell", "-NoLogo", "-NoExit"]
        # CMD — set PROMPT via env, just run cmd.exe
        return ["cmd.exe"]
    else:
        # Prefer user's current shell, fall back to bash
        shell = os.environ.get("SHELL", "/bin/bash")
        return [shell]


def _cmd_exists(name: str) -> bool:
    """Check if a command exists on PATH."""
    import shutil
    return shutil.which(name) is not None


def _print_unix_init() -> None:
    script = r'''
# ── venvy shell integration (optional) ───────────────────────────────
# venvy + already works without this. Add this ONLY if you want plain
# `pip install` to auto-update requirements.txt in your native shell.
#
# Add to ~/.bashrc or ~/.zshrc:
#   eval "$(venvy shell-init)"

function pip() {
  local action="$1"
  if [ "$action" = "install" ] || [ "$action" = "uninstall" ]; then
    command venvy pip "$@"
  else
    command pip "$@"
  fi
}
# ─────────────────────────────────────────────────────────────────────
'''
    print(script)
    console.print(
        "[dim]venvy + works without any setup.[/dim]\n"
        "[dim]shell-init is only needed for native pip auto-tracking.[/dim]\n\n"
        "[dim]Add to ~/.bashrc or ~/.zshrc:[/dim]\n"
        '  [bold cyan]eval "$(venvy shell-init)"[/bold cyan]'
    )


def _print_windows_init() -> None:
    script = r'''
# ── venvy PowerShell integration (optional) ──────────────────────────
# venvy + already works without this. Add this ONLY if you want plain
# `pip install` to auto-update requirements.txt in your native shell.
#
# Add to your $PROFILE:
#   venvy shell-init | Invoke-Expression

function pip {
  param([Parameter(ValueFromRemainingArguments=$true)]$args)
  if ($args[0] -eq 'install' -or $args[0] -eq 'uninstall') {
    venvy pip @args
  } else {
    pip.exe @args
  }
}
# ─────────────────────────────────────────────────────────────────────
'''
    print(script)
    console.print(
        "[dim]venvy + works without any setup.[/dim]\n"
        "[dim]shell-init is only needed for native pip auto-tracking.[/dim]"
    )
