#!/usr/bin/env bash

set -e

# Track which installation method succeeded
UV_INSTALL_METHOD=""

# Function to install uv via package managers (most secure)
install_uv_via_package_manager() {
    echo "Attempting to install uv via system package manager..."

    if command -v brew &> /dev/null; then
        echo "Using Homebrew..."
        brew install uv && UV_INSTALL_METHOD="Homebrew" && return 0
    elif command -v apt &> /dev/null && apt list uv 2>/dev/null | grep -q uv; then
        echo "Using apt..."
        sudo apt update && sudo apt install -y uv && UV_INSTALL_METHOD="apt" && return 0
    elif command -v dnf &> /dev/null; then
        echo "Using dnf..."
        sudo dnf install -y uv 2>/dev/null && UV_INSTALL_METHOD="dnf" && return 0
    elif command -v pacman &> /dev/null; then
        echo "Using pacman..."
        sudo pacman -S --noconfirm uv 2>/dev/null && UV_INSTALL_METHOD="pacman" && return 0
    elif command -v zypper &> /dev/null; then
        echo "Using zypper..."
        sudo zypper install -y uv 2>/dev/null && UV_INSTALL_METHOD="zypper" && return 0
    elif command -v winget &> /dev/null; then
        echo "Using winget..."
        winget install --id=astral-sh.uv -e && UV_INSTALL_METHOD="winget" && return 0
    elif command -v scoop &> /dev/null; then
        echo "Using scoop..."
        scoop install uv && UV_INSTALL_METHOD="scoop" && return 0
    fi

    return 1
}

# Function to handle Ubuntu-specific installation alternatives
install_uv_ubuntu_alternatives() {
    # Check if we're on Ubuntu
    if ! command -v lsb_release &> /dev/null || [[ "$(lsb_release -si)" != "Ubuntu" ]]; then
        return 1  # Not Ubuntu, skip these options
    fi

    echo ""
    echo "Ubuntu detected. Additional trusted installation options available:"
    echo ""
    echo "1. pipx (official PyPI, installs ~9 packages)"
    echo "   Command: sudo apt install pipx && pipx install uv"
    echo ""
    echo "2. snap (community-maintained by Canonical employee)"
    echo "   Command: sudo snap install astral-uv --classic"
    echo "   Source: https://github.com/lengau/uv-snap"
    echo ""
    echo "3. Continue to official installer script download"
    echo ""

    while true; do
        read -r -p "Choose installation method (1/2/3): " choice
        case $choice in
            1)
                echo "Installing uv via pipx..."
                if sudo apt update && sudo apt install -y pipx; then
                    if pipx install uv; then
                        # Add pipx bin directory to PATH
                        export PATH="$HOME/.local/bin:$PATH"
                        UV_INSTALL_METHOD="pipx"
                        return 0
                    fi
                fi
                echo "pipx installation failed, trying next option..."
                ;;
            2)
                echo "Installing uv via snap..."
                if sudo snap install astral-uv --classic; then
                    # Snap binaries should be automatically in PATH via /snap/bin
                    UV_INSTALL_METHOD="snap"
                    return 0
                fi
                echo "snap installation failed, trying next option..."
                ;;
            3)
                return 1  # Continue to official installer download
                ;;
            *)
                echo "Invalid option. Please choose 1, 2, or 3."
                ;;
        esac
    done
}

# Function to install uv via download (with user consent)
install_uv_via_download() {
    echo ""
    echo "⚠️  SECURITY NOTICE ⚠️"
    echo "uv is not available via system package managers on this system."
    echo "To continue, we need to download and execute an installation script from:"
    echo "  https://astral.sh/uv/install.sh (Linux/macOS)"
    echo "  https://astral.sh/uv/install.ps1 (Windows)"
    echo ""
    echo "For maximum security, you can install uv manually instead:"
    echo "  1. Visit: https://docs.astral.sh/uv/getting-started/installation/"
    echo "  2. Download the binary for your platform from GitHub releases"
    echo "  3. Verify checksums and install manually"
    echo "  4. Then run: ./algo"
    echo ""

    read -p "Continue with script download? (y/N): " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        echo "Installation cancelled. Please install uv manually and retry."
        exit 1
    fi

    echo "Downloading uv installation script..."
    if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "linux-gnu" && -n "${WSL_DISTRO_NAME:-}" ]] || uname -s | grep -q "MINGW\|MSYS"; then
        # Windows (Git Bash/WSL/MINGW) - use versioned installer
        powershell -ExecutionPolicy ByPass -c "irm https://github.com/astral-sh/uv/releases/download/0.8.5/uv-installer.ps1 | iex"
        UV_INSTALL_METHOD="official installer (Windows)"
    else
        # macOS/Linux - use the versioned script for consistency
        curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.8.5/uv-installer.sh | sh
        UV_INSTALL_METHOD="official installer"
    fi
}

# Check if uv is installed, if not, install it securely
if ! command -v uv &> /dev/null; then
    echo "uv (Python package manager) not found. Installing..."

    # Try package managers first (most secure)
    if ! install_uv_via_package_manager; then
        # Try Ubuntu-specific alternatives if available
        if ! install_uv_ubuntu_alternatives; then
            # Fall back to download with user consent
            install_uv_via_download
        fi
    fi

    # Reload PATH to find uv (includes pipx, cargo, and snap paths)
    # Note: This PATH change only affects the current shell session.
    # Users may need to restart their terminal for subsequent runs.
    export PATH="$HOME/.local/bin:$HOME/.cargo/bin:/snap/bin:$PATH"

    # Verify installation worked
    if ! command -v uv &> /dev/null; then
        echo "Error: uv installation failed. Please restart your terminal and try again."
        echo "Or install manually from: https://docs.astral.sh/uv/getting-started/installation/"
        exit 1
    fi

    echo "✓ uv installed successfully via ${UV_INSTALL_METHOD}!"
fi

# Install Ansible Galaxy collections if requirements.yml exists
# This is needed for cloud providers that use collection modules (Linode, DigitalOcean, Azure, etc.)
if [ -f "requirements.yml" ]; then
    uv run ansible-galaxy collection install -r requirements.yml > /dev/null 2>&1 || true
fi

# Run the appropriate playbook
case "$1" in
  help|-h|--help)
    echo "Usage: ./algo [COMMAND] [ANSIBLE_OPTIONS]"
    echo ""
    echo "Set up a personal VPN in the cloud."
    echo ""
    echo "Commands:"
    echo "  (default)        Deploy a new VPN server"
    echo "  update-users     Add or remove users on an existing server"
    echo "  destroy          Destroy a deployed server and clean up configs"
    echo "  list-servers     List deployed servers (JSON output)"
    echo ""
    echo "Configuration:"
    echo "  Edit config.cfg to set users, DNS, and VPN options before deploying."
    echo ""
    echo "Non-interactive deployment:"
    echo "  ./algo -e 'provider=digitalocean server_name=algo region=nyc3 do_token=TOKEN'"
    echo ""
    echo "Common Ansible options (passed through):"
    echo "  -e KEY=VALUE     Set variable (bypass interactive prompts)"
    echo "  -v, -vvv         Increase output verbosity"
    echo "  --skip-tags TAG  Skip specific components"
    echo "  -t, --tags TAG   Run only specific components"
    echo ""
    echo "Docs: https://trailofbits.github.io/algo/"
    exit 0
    ;;
  update-users)
    uv run ansible-playbook users.yml "${@:2}" -t update-users ;;
  destroy)
    if [ -z "${2:-}" ] || [[ "$2" == -* ]]; then
      echo "Usage: ./algo destroy <server-ip> [ANSIBLE_OPTIONS]"
      echo ""
      echo "Destroy a deployed Algo VPN server and remove local configs."
      echo ""
      echo "Arguments:"
      echo "  server-ip        IP address of the server to destroy"
      echo ""
      echo "Examples:"
      echo "  ./algo destroy 188.166.66.185"
      echo "  ./algo destroy 52.1.2.3 -e \"region=us-east-1\""
      echo "  ./algo destroy 188.166.66.185 -e \"confirm_destroy=true\""
      exit 1
    fi
    uv run ansible-playbook destroy.yml -e "server_ip=$2" "${@:3}" ;;
  list-servers)
    uv run python3 scripts/list_servers.py "${@:2}" ;;
  *)
    uv run ansible-playbook main.yml "${@}" ;;
esac
