"""CLI entry point for justvenv."""

import os
import sys
import venv
from pathlib import Path
from enum import Enum, auto


VENV_NAME = ".venv"


class ShellType(Enum):
    """Detected shell types."""
    POWERSHELL = auto()      # Windows PowerShell or PowerShell Core
    CMD = auto()             # Windows cmd.exe
    GIT_BASH = auto()        # Git Bash (MINGW/MSYS)
    BASH = auto()            # Bash (Linux/macOS)
    ZSH = auto()             # Zsh (macOS default)
    FISH = auto()            # Fish shell
    SH = auto()              # Generic POSIX shell
    UNKNOWN = auto()


# Shell function templates (raw strings to avoid escape issues)
SHELL_FUNCTIONS = {
    ShellType.POWERSHELL: r'''function venv {
    if (!(Test-Path ".venv")) {
        python -m venv .venv
        Write-Host "Virtual environment created."
    }
    . .\.venv\Scripts\Activate.ps1
}
''',
    ShellType.CMD: r'''@echo off
if not exist ".venv" (
    python -m venv .venv
    echo Virtual environment created.
)
call .venv\Scripts\activate.bat
''',
    ShellType.BASH: '''venv() {
    if [ ! -d ".venv" ]; then
        python -m venv .venv
        echo "Virtual environment created."
    fi
    source .venv/bin/activate
}
''',
    ShellType.ZSH: '''venv() {
    if [ ! -d ".venv" ]; then
        python -m venv .venv
        echo "Virtual environment created."
    fi
    source .venv/bin/activate
}
''',
    ShellType.FISH: '''function venv
    if not test -d ".venv"
        python -m venv .venv
        echo "Virtual environment created."
    end
    source .venv/bin/activate.fish
end
''',
    ShellType.GIT_BASH: '''venv() {
    if [ ! -d ".venv" ]; then
        python -m venv .venv
        echo "Virtual environment created."
    fi
    source .venv/Scripts/activate
}
''',
}

# Setup instructions for each shell
SETUP_INSTRUCTIONS = {
    ShellType.POWERSHELL: '''
To enable 'venv' command, run this ONCE:

    venv --init >> $PROFILE; . $PROFILE

Then just type 'venv' in any project directory!
''',
    ShellType.CMD: '''
CMD doesn't support shell functions.
Save the output of 'venv --init' as venv.bat in a directory in your PATH.
''',
    ShellType.BASH: '''
To enable 'venv' command, run this ONCE:

    venv --init >> ~/.bashrc && source ~/.bashrc

Then just type 'venv' in any project directory!
''',
    ShellType.ZSH: '''
To enable 'venv' command, run this ONCE:

    venv --init >> ~/.zshrc && source ~/.zshrc

Then just type 'venv' in any project directory!
''',
    ShellType.FISH: '''
To enable 'venv' command, run this ONCE:

    venv --init > ~/.config/fish/functions/venv.fish

Then just type 'venv' in any project directory!
''',
    ShellType.GIT_BASH: '''
To enable 'venv' command, run this ONCE:

    venv --init >> ~/.bashrc && source ~/.bashrc

Then just type 'venv' in any project directory!
''',
}


def detect_shell() -> ShellType:
    """Detect the current shell environment."""
    
    if sys.platform == "win32":
        # Check for Git Bash (MINGW/MSYS)
        if os.environ.get("MSYSTEM"):
            return ShellType.GIT_BASH
        
        # Check for PowerShell via environment variable
        # PSModulePath is set by PowerShell
        if os.environ.get("PSModulePath"):
            return ShellType.POWERSHELL
        
        # Default to cmd.exe on Windows
        return ShellType.CMD
    
    else:
        # Unix-like systems (Linux, macOS, WSL)
        shell = os.environ.get("SHELL", "").lower()
        
        if "fish" in shell:
            return ShellType.FISH
        elif "zsh" in shell:
            return ShellType.ZSH
        elif "bash" in shell:
            return ShellType.BASH
        elif shell.endswith("/sh"):
            return ShellType.BASH
        else:
            return ShellType.BASH


def get_venv_path() -> Path:
    """Get the venv path in current directory."""
    return Path.cwd() / VENV_NAME


def is_venv_exists() -> bool:
    """Check if venv already exists."""
    venv_path = get_venv_path()
    
    if sys.platform == "win32":
        activate_script = venv_path / "Scripts" / "activate.bat"
    else:
        activate_script = venv_path / "bin" / "activate"
    
    return activate_script.exists()


def create_venv() -> bool:
    """Create a new venv. Returns True if successful."""
    venv_path = get_venv_path()
    
    print(f"Creating virtual environment at {venv_path}...")
    
    try:
        venv.create(venv_path, with_pip=True)
        print("Virtual environment created successfully!")
        return True
    except Exception as e:
        print(f"Error creating virtual environment: {e}", file=sys.stderr)
        return False


def print_init(shell_type: ShellType = None):
    """Print shell function for the detected or specified shell."""
    if shell_type is None:
        shell_type = detect_shell()
    
    if shell_type in SHELL_FUNCTIONS:
        print(SHELL_FUNCTIONS[shell_type])
    else:
        print(SHELL_FUNCTIONS[ShellType.BASH])


def get_profile_path() -> Path:
    """Get the shell profile path."""
    shell_type = detect_shell()
    home = Path.home()
    
    if shell_type == ShellType.POWERSHELL:
        # PowerShell profile path
        docs = home / "Documents"
        if (docs / "PowerShell").exists():
            return docs / "PowerShell" / "Microsoft.PowerShell_profile.ps1"
        return docs / "WindowsPowerShell" / "Microsoft.PowerShell_profile.ps1"
    elif shell_type == ShellType.ZSH:
        return home / ".zshrc"
    elif shell_type == ShellType.FISH:
        return home / ".config" / "fish" / "functions" / "venv.fish"
    elif shell_type == ShellType.GIT_BASH:
        return home / ".bashrc"
    else:  # BASH
        return home / ".bashrc"


def is_function_installed() -> bool:
    """Check if venv function is already installed in profile."""
    profile_path = get_profile_path()
    if not profile_path.exists():
        return False
    
    content = profile_path.read_text(encoding="utf-8", errors="ignore")
    return "function venv" in content or "venv()" in content


def install_function() -> bool:
    """Install the venv function to the shell profile."""
    shell_type = detect_shell()
    profile_path = get_profile_path()
    
    # Create parent directories if needed
    profile_path.parent.mkdir(parents=True, exist_ok=True)
    
    # Get the function for this shell
    if shell_type not in SHELL_FUNCTIONS:
        return False
    
    func = SHELL_FUNCTIONS[shell_type]
    
    # Append to profile
    with open(profile_path, "a", encoding="utf-8") as f:
        f.write("\n# Added by justvenv\n")
        f.write(func)
    
    return True


def print_setup_instructions():
    """Print setup instructions for the current shell."""
    shell_type = detect_shell()
    if shell_type in SETUP_INSTRUCTIONS:
        print(SETUP_INSTRUCTIONS[shell_type])
    else:
        print(SETUP_INSTRUCTIONS[ShellType.BASH])


def main():
    """Main entry point."""
    import argparse
    
    parser = argparse.ArgumentParser(
        prog="venv",
        description="One-liner venv creation and activation tool."
    )
    parser.add_argument(
        "--version", "-V",
        action="version",
        version=f"%(prog)s {__import__('venv_cli').__version__}"
    )
    parser.add_argument(
        "--init",
        action="store_true",
        help="Print shell function for your current shell"
    )
    parser.add_argument(
        "--init-all",
        action="store_true",
        help="Print shell functions for all supported shells"
    )
    parser.add_argument(
        "--create", "-c",
        action="store_true",
        help="Create .venv in current directory"
    )
    parser.add_argument(
        "--path", "-p",
        action="store_true",
        help="Print the venv path and exit"
    )
    
    args = parser.parse_args()
    
    # Handle --init flag
    if args.init:
        print_init()
        return 0
    
    # Handle --init-all flag
    if args.init_all:
        for shell_type, func in SHELL_FUNCTIONS.items():
            print(f"# {shell_type.name}")
            print(func)
        return 0
    
    # Handle --path flag
    if args.path:
        print(get_venv_path())
        return 0
    
    # Handle --create flag
    if args.create:
        if not is_venv_exists():
            if not create_venv():
                return 1
        else:
            print(f"Virtual environment already exists: {get_venv_path()}")
        return 0
    
    # Default: auto-install shell function
    if is_function_installed():
        print("venv function is already installed!")
        print("Just type 'venv' in any project directory.")
        print("\nIf it's not working, restart your shell or run:")
        shell_type = detect_shell()
        if shell_type == ShellType.POWERSHELL:
            print("    . $PROFILE")
        elif shell_type == ShellType.FISH:
            print("    source ~/.config/fish/functions/venv.fish")
        else:
            print("    source ~/.bashrc")
    else:
        print("Installing venv function to your shell profile...")
        if install_function():
            print("Done! Now restart your shell or run:")
            shell_type = detect_shell()
            if shell_type == ShellType.POWERSHELL:
                print("    . $PROFILE")
            elif shell_type == ShellType.FISH:
                print("    source ~/.config/fish/functions/venv.fish")
            else:
                print("    source ~/.bashrc")
            print("\nThen just type 'venv' in any project directory!")
        else:
            print("Failed to install. Please run manually:")
            print_setup_instructions()
    
    return 0


if __name__ == "__main__":
    sys.exit(main())
