"""
venvy.core.pip_wrapper
~~~~~~~~~~~~~~~~~~~~~~
Generates and installs a `pip` wrapper script inside the venv.

When user runs `pip install X` inside an active venvy-managed venv,
the wrapper calls the real pip AND auto-updates requirements.txt.
The wrapper is a Python script placed BEFORE the real pip in PATH.
"""

from __future__ import annotations

import os
import platform
import stat
from pathlib import Path
from typing import Optional

IS_WINDOWS = platform.system() == "Windows"

# The wrapper script content — this replaces the real `pip` entry point
_WRAPPER_TEMPLATE = '''\
#!/usr/bin/env python
"""
venvy pip wrapper — auto-syncs requirements.txt on install/uninstall.
Generated by venvy. Do not edit manually.
"""
import sys
import os
from pathlib import Path

# Locate venvy config from VIRTUAL_ENV env var
def find_venvy_root():
    venv_path = os.environ.get("VIRTUAL_ENV")
    if not venv_path:
        return None, None
    # Walk up from venv's parent
    start = Path(venv_path).parent
    for directory in [start, *start.parents]:
        cfg = directory / ".venvy.json"
        if cfg.exists():
            import json
            try:
                data = json.loads(cfg.read_text(encoding="utf-8"))
                req_file = directory / data.get("requirements_file", "requirements.txt")
                return directory, req_file
            except Exception:
                pass
    return None, None


def main():
    args = sys.argv[1:]
    
    # Find the real pip (our script is named pip, so we need the actual pip module)
    import subprocess
    
    root, req_path = find_venvy_root()
    
    if root is None or not args or args[0].lower() not in ("install", "uninstall"):
        # Just run real pip directly
        result = subprocess.run([sys.executable, "-m", "pip"] + args, check=False)
        sys.exit(result.returncode)
    
    # Run pip and sync
    from venvy.core.pip_hook import run_pip_and_sync
    
    # The real pip executable in this venv
    venv = Path(os.environ["VIRTUAL_ENV"])
    if sys.platform == "win32":
        real_pip = venv / "Scripts" / "pip_real.exe"
        # Fall back: use pip module  
        pip_exe = venv / "Scripts" / "pip_venvy_real.exe"
    else:
        real_pip = venv / "bin" / "pip_venvy_real"
    
    # Use pip module approach (most reliable)
    pip_path = Path(sys.executable)
    
    class PipProxy:
        """Proxy that calls pip via python -m pip."""
        def __str__(self):
            return str(pip_path)
    
    import subprocess as _sp
    
    action = args[0].lower()
    
    # Run the real pip
    result = _sp.run([sys.executable, "-m", "pip"] + args, check=False)
    exit_code = result.returncode
    
    if exit_code == 0:
        from venvy.core.requirements import RequirementsManager
        from venvy.core.pip_hook import (
            _extract_package_names, _get_package_version,
            _prompt_create_requirements, _print_sync
        )
        
        pip_for_show = pip_path
        
        class _PipShowable:
            pass
        
        mgr = RequirementsManager(req_path)
        
        if action == "install":
            packages = _extract_package_names(args[1:])
            for pkg in packages:
                import subprocess
                try:
                    r = subprocess.run(
                        [sys.executable, "-m", "pip", "show", pkg],
                        capture_output=True, text=True, check=False
                    )
                    version = None
                    for line in r.stdout.splitlines():
                        if line.startswith("Version:"):
                            version = line.split(":", 1)[1].strip()
                    if version:
                        if not mgr.exists:
                            _prompt_create_requirements(req_path)
                        if mgr.exists:
                            changed = mgr.add_or_update(pkg, version)
                            if changed:
                                _print_sync(f"Added {pkg}=={version} to {req_path.name}")
                except Exception:
                    pass
        elif action == "uninstall":
            packages = _extract_package_names(args[1:])
            for pkg in packages:
                if mgr.exists:
                    removed = mgr.remove(pkg)
                    if removed:
                        _print_sync(f"Removed {pkg} from {req_path.name}")
    
    sys.exit(exit_code)


if __name__ == "__main__":
    main()
'''


def install_pip_wrapper(venv_path: Path) -> bool:
    """
    Install the venvy pip wrapper into the venv's Scripts/bin directory.
    The wrapper is named 'pip' and will be found before the real pip.
    Returns True on success.
    """
    if IS_WINDOWS:
        scripts_dir = venv_path / "Scripts"
        wrapper_path = scripts_dir / "pip.exe"
        # On Windows we create a .py launcher instead of replacing the binary
        py_wrapper = scripts_dir / "_venvy_pip_wrapper.py"
        py_wrapper.write_text(_WRAPPER_TEMPLATE, encoding="utf-8")

        # Create a batch wrapper that calls our Python script
        bat_content = f'@echo off\n"{venv_path / "Scripts" / "python.exe"}" "{py_wrapper}" %*\n'
        pip_bat = scripts_dir / "pip.bat"
        # Back up original pip if not already done
        real_pip_bat = scripts_dir / "pip_real_venvy.bat"
        if not real_pip_bat.exists() and pip_bat.exists():
            pip_bat.rename(real_pip_bat)
        pip_bat.write_text(bat_content, encoding="utf-8")
        return True
    else:
        bin_dir = venv_path / "bin"
        wrapper_path = bin_dir / "_venvy_pip_wrapper.py"
        wrapper_path.write_text(_WRAPPER_TEMPLATE, encoding="utf-8")

        pip_script = bin_dir / "pip"
        if pip_script.exists():
            real_pip = bin_dir / "pip_venvy_real"
            if not real_pip.exists():
                import shutil
                shutil.copy2(pip_script, real_pip)

        # Write new pip script
        launcher = f'#!/bin/sh\nexec "$(dirname "$0")/python" "$(dirname "$0")/_venvy_pip_wrapper.py" "$@"\n'
        pip_script.write_text(launcher, encoding="utf-8")
        pip_script.chmod(pip_script.stat().st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
        return True
