#!/bin/bash

set -e

# Check if running in a pipe (e.g., curl | sh)
PIPED_EXECUTION=false
if [ ! -t 0 ]; then
    # stdin is not a terminal, likely piped execution
    PIPED_EXECUTION=true
fi

# Non-interactive mode flag
NON_INTERACTIVE=false

# Check for non-interactive mode via environment variable
if [ "$STAKPAK_NON_INTERACTIVE" = "true" ] || [ "$STAKPAK_NON_INTERACTIVE" = "1" ] || [ "$STAKPAK_YES" = "true" ] || [ "$STAKPAK_YES" = "1" ]; then
    NON_INTERACTIVE=true
fi

# Installation script version
INSTALLER_VERSION="1.0.0"

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# GitHub repository information
REPO="stakpak/agent"
BINARY_NAME="stakpak"

# Print colored output
print_info() {
    printf "${BLUE}[INFO]${NC} %s\n" "$1"
}

print_success() {
    printf "${GREEN}[SUCCESS]${NC} %s\n" "$1"
}

print_warning() {
    printf "${YELLOW}[WARNING]${NC} %s\n" "$1"
}

print_error() {
    printf "${RED}[ERROR]${NC} %s\n" "$1"
}

# Helper function to read user input, handling piped execution
read_user_input() {
    local prompt="$1"
    local default_yes="${2:-true}"
    local response=""
    
    # If non-interactive mode is enabled, use default
    if [ "$NON_INTERACTIVE" = "true" ]; then
        printf "%s [Non-interactive mode - using default]\n" "$prompt"
        if [ "$default_yes" = "true" ]; then
            return 0
        else
            return 1
        fi
    fi
    
    # Always show the prompt
    printf "%s" "$prompt"
    
    # Try to read from terminal even in piped mode
    if [ "$PIPED_EXECUTION" = "true" ]; then
        # In piped execution, try to read from controlling terminal
        if [ -r /dev/tty ]; then
            response=$(read -r input < /dev/tty && echo "$input" || echo "")
        else
            # If no terminal available, show timeout and auto-proceed
            printf " [No terminal available - auto-proceeding in 5 seconds, Ctrl+C to cancel]"
            sleep 5
            printf "\n"
            response=""
        fi
    else
        # Interactive execution - normal read
        read -r response
    fi
    
    # Process the response
    if [ "$default_yes" = "true" ]; then
        # Default is yes, only exit on explicit no
        if [ "$response" = "n" ] || [ "$response" = "N" ]; then
            return 1
        fi
        return 0
    else
        # Default is no, only proceed on explicit yes
        if [ "$response" = "y" ] || [ "$response" = "Y" ]; then
            return 0
        else
            return 1
        fi
    fi
}

# Detect OS and architecture
detect_platform() {
    OS=$(uname -s | tr '[:upper:]' '[:lower:]')
    ARCH=$(uname -m)
    
    case $OS in
        darwin)
            OS="macos"
            ;;
        linux)
            OS="linux"
            ;;
        msys*|mingw*|cygwin*)
            OS="windows"
            ;;
        *)
            print_error "Unsupported operating system: $OS"
            exit 1
            ;;
    esac
    
    case $ARCH in
        x86_64|amd64)
            ARCH="x86_64"
            ;;
        aarch64|arm64)
            ARCH="aarch64"
            ;;
        *)
            print_error "Unsupported architecture: $ARCH"
            print_info "Supported architectures: x86_64, aarch64"
            exit 1
            ;;
    esac
    
    print_info "Detected platform: $OS-$ARCH"
}

# Validate that the platform combination is supported
validate_platform_support() {
    print_info "Validating platform support..."
    
    # Define supported platform combinations based on stakpak releases
    case "$OS-$ARCH" in
        "linux-x86_64"|"linux-aarch64"|"macos-x86_64"|"macos-aarch64"|"windows-x86_64")
            print_info "Platform $OS-$ARCH is supported"
            ;;
        *)
            print_error "Platform combination $OS-$ARCH is not supported"
            print_info "Supported platforms:"
            print_info "  - linux-x86_64"
            print_info "  - linux-aarch64"
            print_info "  - macos-x86_64"
            print_info "  - macos-aarch64"
            print_info "  - windows-x86_64"
            print_info ""
            print_info "Your platform: $OS-$ARCH"
            exit 1
            ;;
         esac
}

# Check if Homebrew is available
check_homebrew() {
    if command -v brew >/dev/null 2>&1; then
        return 0
    else
        return 1
    fi
}

# Install via Homebrew
install_homebrew() {
    print_info "Installing Stakpak via Homebrew..."
    
    # Add tap if not already added
    if ! brew tap | grep -q "stakpak/stakpak"; then
        print_info "This will add the Stakpak Homebrew tap (stakpak/stakpak) to your system."
        if ! read_user_input "Continue? (Y/n) " true; then
            print_info "Installation cancelled by user."
            exit 0
        fi
        
        print_info "Adding Stakpak tap..."
        brew tap stakpak/stakpak
    fi
    
    # Install stakpak
    print_info "Installing stakpak..."
    brew install stakpak
    
    print_success "Stakpak installed successfully via Homebrew!"
}

# Get the latest release version
get_latest_release() {
    print_info "Fetching latest release information..."
    
    # Try to get the latest release from GitHub API
    if command -v curl >/dev/null 2>&1; then
        print_info "Using curl to fetch release information from: https://api.github.com/repos/$REPO/releases/latest"
        API_RESPONSE=$(curl -s "https://api.github.com/repos/$REPO/releases/latest")
        HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://api.github.com/repos/$REPO/releases/latest")
        
        print_info "HTTP Status: $HTTP_STATUS"
        
        if [ "$HTTP_STATUS" = "404" ]; then
            print_error "Repository $REPO not found or has no releases"
            print_info "API Response: $API_RESPONSE"
            exit 1
        elif [ "$HTTP_STATUS" = "403" ]; then
            print_warning "GitHub API rate limit exceeded. Trying fallback method..."
            use_fallback_release
            return
        elif [ "$HTTP_STATUS" != "200" ]; then
            print_error "GitHub API returned status $HTTP_STATUS"
            print_info "API Response: $API_RESPONSE"
            print_warning "Trying fallback method..."
            use_fallback_release
            return
        fi
        
        LATEST_RELEASE=$(echo "$API_RESPONSE" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
        
    elif command -v wget >/dev/null 2>&1; then
        print_info "Using wget to fetch release information from: https://api.github.com/repos/$REPO/releases/latest"
        API_RESPONSE=$(wget -qO- "https://api.github.com/repos/$REPO/releases/latest" 2>&1)
        WGET_EXIT_CODE=$?
        
        if [ $WGET_EXIT_CODE -ne 0 ]; then
            print_warning "wget failed with exit code $WGET_EXIT_CODE. Trying fallback method..."
            use_fallback_release
            return
        fi
        
        LATEST_RELEASE=$(echo "$API_RESPONSE" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
        
    else
        print_error "Neither curl nor wget is available. Please install one of them."
        exit 1
    fi
    
    if [ -z "$LATEST_RELEASE" ]; then
        print_warning "Failed to fetch latest release information from API. Trying fallback method..."
        use_fallback_release
        return
    fi
    
    print_info "Latest release: $LATEST_RELEASE"
}

# Fallback method to scrape release version from GitHub releases page when API fails
use_fallback_release() {
    print_info "Using fallback release detection method..."
    print_info "Scraping releases page: https://github.com/$REPO/releases"
    

    
    # Try to scrape the releases page for the latest release
    if command -v curl >/dev/null 2>&1; then
        print_info "Fetching releases page with curl..."
        RELEASES_PAGE=$(curl -s "https://github.com/$REPO/releases")
        
        if [ -z "$RELEASES_PAGE" ]; then
            print_error "Failed to fetch releases page"
            exit 1
        fi
        
        # Extract the latest release tag from the releases page
        # Look for the first occurrence of /releases/tag/vX.X.X pattern
        LATEST_RELEASE=$(echo "$RELEASES_PAGE" | grep -oE '/releases/tag/v[0-9]+\.[0-9]+\.[0-9]+[^"]*' | head -1 | sed 's|/releases/tag/||')
        
        if [ -z "$LATEST_RELEASE" ]; then
            # Try alternative pattern without 'v' prefix
            LATEST_RELEASE=$(echo "$RELEASES_PAGE" | grep -oE '/releases/tag/[0-9]+\.[0-9]+\.[0-9]+[^"]*' | head -1 | sed 's|/releases/tag/||')
        fi
        
        if [ -z "$LATEST_RELEASE" ]; then
            # Try to find any release tag pattern (more flexible)
            LATEST_RELEASE=$(echo "$RELEASES_PAGE" | grep -oE '/releases/tag/[^"]*' | head -1 | sed 's|/releases/tag/||')
        fi
        
        if [ -z "$LATEST_RELEASE" ]; then
            # Try alternative HTML structure - look for release-header pattern
            LATEST_RELEASE=$(echo "$RELEASES_PAGE" | grep -oE 'releases/tag/[^"]*' | head -1 | sed 's|releases/tag/||')
        fi
        
    elif command -v wget >/dev/null 2>&1; then
        print_info "Fetching releases page with wget..."
        RELEASES_PAGE=$(wget -qO- "https://github.com/$REPO/releases")
        
        if [ -z "$RELEASES_PAGE" ]; then
            print_error "Failed to fetch releases page"
            exit 1
        fi
        
        # Extract the latest release tag from the releases page
        LATEST_RELEASE=$(echo "$RELEASES_PAGE" | grep -oE '/releases/tag/v[0-9]+\.[0-9]+\.[0-9]+[^"]*' | head -1 | sed 's|/releases/tag/||')
        
        if [ -z "$LATEST_RELEASE" ]; then
            # Try alternative pattern without 'v' prefix
            LATEST_RELEASE=$(echo "$RELEASES_PAGE" | grep -oE '/releases/tag/[0-9]+\.[0-9]+\.[0-9]+[^"]*' | head -1 | sed 's|/releases/tag/||')
        fi
        
        if [ -z "$LATEST_RELEASE" ]; then
            # Try to find any release tag pattern (more flexible)
            LATEST_RELEASE=$(echo "$RELEASES_PAGE" | grep -oE '/releases/tag/[^"]*' | head -1 | sed 's|/releases/tag/||')
        fi
        
        if [ -z "$LATEST_RELEASE" ]; then
            # Try alternative HTML structure - look for release-header pattern
            LATEST_RELEASE=$(echo "$RELEASES_PAGE" | grep -oE 'releases/tag/[^"]*' | head -1 | sed 's|releases/tag/||')
        fi
        
    else
        print_error "Neither curl nor wget is available. Please install one of them."
        exit 1
    fi
    
    if [ -z "$LATEST_RELEASE" ]; then
        print_error "Failed to determine latest release from releases page"
        print_info "Could not find release tag pattern in the releases page"
        print_info ""
        print_info "Debug information:"
        print_info "First few lines of releases page:"
        echo "$RELEASES_PAGE" | head -10
        print_info ""
        print_info "Looking for patterns like: /releases/tag/v1.2.3 or /releases/tag/1.2.3"
        print_info "Found release tag patterns:"
        echo "$RELEASES_PAGE" | grep -oE '/releases/tag/[^"]*' | head -5
        print_info ""
        print_info "Please check the releases page manually: https://github.com/$REPO/releases"
        exit 1
    fi
    
    print_info "Found latest release from releases page: $LATEST_RELEASE"
}

# Download and install binary
install_binary() {
    print_info "Installing Stakpak via binary download..."
    
    # Construct download URL based on the actual stakpak release naming convention
    if [ "$OS" = "windows" ]; then
        BINARY_FILENAME="${BINARY_NAME}-windows-${ARCH}.zip"
    elif [ "$OS" = "macos" ]; then
        BINARY_FILENAME="${BINARY_NAME}-darwin-${ARCH}.tar.gz"
    else
        BINARY_FILENAME="${BINARY_NAME}-linux-${ARCH}.tar.gz"
    fi
    
    DOWNLOAD_URL="https://github.com/$REPO/releases/download/$LATEST_RELEASE/$BINARY_FILENAME"
    
    print_info "This will download and install the Stakpak binary from:"
    print_info "  URL: $DOWNLOAD_URL"
    print_info "  Version: $LATEST_RELEASE"
    print_info "  Platform: $OS-$ARCH"
    print_info ""
    if ! read_user_input "Continue with binary installation? (Y/n) " true; then
        print_info "Installation cancelled by user."
        exit 0
    fi
    
    # Create temporary directory
    TEMP_DIR=$(mktemp -d)
    cd "$TEMP_DIR"
    
    # Download the binary
    print_info "Downloading binary..."
    if command -v curl >/dev/null 2>&1; then
        HTTP_STATUS=$(curl -sL "$DOWNLOAD_URL" -o "$BINARY_FILENAME" -w "%{http_code}")
        if [ "$HTTP_STATUS" != "200" ]; then
            print_error "Download failed with HTTP status: $HTTP_STATUS"
            print_info "URL: $DOWNLOAD_URL"
            print_info "This might indicate:"
            print_info "1. The release version doesn't exist"
            print_info "2. The binary filename format is incorrect"
            print_info "3. Network connectivity issues"
            print_info ""
            print_info "Available releases can be found at: https://github.com/$REPO/releases"
            exit 1
        fi
    elif command -v wget >/dev/null 2>&1; then
        if ! wget -q "$DOWNLOAD_URL" -O "$BINARY_FILENAME"; then
            print_error "Download failed using wget"
            print_info "URL: $DOWNLOAD_URL"
            print_info "This might indicate:"
            print_info "1. The release version doesn't exist"
            print_info "2. The binary filename format is incorrect"
            print_info "3. Network connectivity issues"
            print_info ""
            print_info "Available releases can be found at: https://github.com/$REPO/releases"
            exit 1
        fi
    else
        print_error "Neither curl nor wget is available. Please install one of them."
        exit 1
    fi
    
    # Verify the download was successful
    if [ ! -f "$BINARY_FILENAME" ] || [ ! -s "$BINARY_FILENAME" ]; then
        print_error "Download failed or file is empty"
        print_info "Expected file: $BINARY_FILENAME"
        exit 1
    fi
    
    print_success "Binary downloaded successfully"
    
    # Extract the binary
    if [ "$OS" = "windows" ]; then
        if command -v unzip >/dev/null 2>&1; then
            unzip -q "$BINARY_FILENAME"
        else
            print_error "unzip is not available. Please install it."
            exit 1
        fi
        BINARY_FILE="${BINARY_NAME}.exe"
    else
        if command -v tar >/dev/null 2>&1; then
            tar -xzf "$BINARY_FILENAME"
        else
            print_error "tar is not available. Please install it."
            exit 1
        fi
        BINARY_FILE="$BINARY_NAME"
    fi
    
    # Find installation directory
    if [ "$OS" = "windows" ]; then
        INSTALL_DIR="$HOME/.local/bin"
    else
        # Try to find a suitable directory in PATH
        for dir in /usr/local/bin /usr/bin ~/.local/bin; do
            if [ -d "$dir" ] && [ -w "$dir" ]; then
                INSTALL_DIR="$dir"
                break
            fi
        done
        
        if [ -z "$INSTALL_DIR" ]; then
            # Create ~/.local/bin if it doesn't exist
            INSTALL_DIR="$HOME/.local/bin"
            mkdir -p "$INSTALL_DIR"
        fi
    fi
    
    # Confirm installation location
    print_info "Ready to install stakpak binary to: $INSTALL_DIR"
    if [ "$INSTALL_DIR" = "/usr/local/bin" ] || [ "$INSTALL_DIR" = "/usr/bin" ]; then
        print_warning "This is a system directory. Installation may require elevated privileges."
    fi
    if ! read_user_input "Proceed with installation? (Y/n) " true; then
        print_info "Installation cancelled by user."
        exit 0
    fi
    
    # Install the binary
    print_info "Installing to: $INSTALL_DIR"
    mkdir -p "$INSTALL_DIR"
    cp "$BINARY_FILE" "$INSTALL_DIR/"
    chmod +x "$INSTALL_DIR/$BINARY_FILE"
    
    # Clean up
    cd ..
    rm -rf "$TEMP_DIR"
    
    print_success "Stakpak installed successfully to $INSTALL_DIR!"
    
    # Check if the install directory is in PATH
    if ! echo "$PATH" | grep -q "$INSTALL_DIR"; then
        print_warning "Warning: $INSTALL_DIR is not in your PATH."
        print_info "Add the following line to your shell profile (~/.bashrc, ~/.zshrc, etc.):"
        echo "export PATH=\"$INSTALL_DIR:\$PATH\""
    fi
}

# Verify installation
verify_installation() {
    print_info "Verifying installation..."
    
    if command -v stakpak >/dev/null 2>&1; then
        VERSION=$(stakpak version 2>/dev/null || echo "unknown")
        print_success "Stakpak is installed and available in PATH"
        print_info "Version: $VERSION"
    else
        print_warning "Stakpak is installed but not available in PATH"
        print_info "You may need to restart your terminal or add the installation directory to your PATH"
    fi
}

# Test GitHub API connectivity
test_github_api() {
    print_info "Testing GitHub API connectivity..."
    
    if command -v curl >/dev/null 2>&1; then
        HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://api.github.com/repos/$REPO")
        print_info "GitHub API test - HTTP Status: $HTTP_STATUS"
        
        if [ "$HTTP_STATUS" = "404" ]; then
            print_error "Repository $REPO not found"
            return 1
        elif [ "$HTTP_STATUS" != "200" ]; then
            print_error "GitHub API returned status $HTTP_STATUS"
            return 1
        fi
        
        print_success "GitHub API connectivity test passed"
        return 0
    else
        print_error "curl not available for testing"
        return 1
    fi
}

# Main installation function
main() {
    echo "================================================"
    echo "      Stakpak Agent Installer (v$INSTALLER_VERSION)"
    echo "================================================"
    echo
    
    # Parse command line arguments
    TEST_MODE=false
    
    while [ $# -gt 0 ]; do
        case $1 in
            -h|--help)
                echo "Stakpak Agent Installer"
                echo ""
                echo "Usage: $0 [OPTIONS]"
                echo ""
                echo "Options:"
                echo "  -h, --help     Show this help message"
                echo "  -t, --test     Test mode - check connectivity and repository without installing"
                echo ""
                echo "Environment Variables:"
                echo "  STAKPAK_NON_INTERACTIVE=true    Enable non-interactive mode"
                echo "  STAKPAK_YES=true                 Enable non-interactive mode (alias)"
                echo ""
                echo "Examples:"
                echo "  $0                       # Normal installation"
                echo "  $0 --test               # Test mode"
                echo "  STAKPAK_NON_INTERACTIVE=true $0  # Non-interactive mode"
                echo "  STAKPAK_NON_INTERACTIVE=true $0 -t  # Non-interactive test mode"
                echo "  STAKPAK_NON_INTERACTIVE=true curl -sSL https://stakpak.dev/install.sh | sh   # Piped non-interactive"
                echo ""
                return 0
                ;;
            -t|--test)
                TEST_MODE=true
                shift
                ;;
            *)
                print_error "Unknown option: $1"
                print_info "Use -h or --help for usage information"
                exit 1
                ;;
        esac
    done
    
    # Handle test mode
    if [ "$TEST_MODE" = "true" ]; then
        print_info "Running in test mode..."
        if [ "$NON_INTERACTIVE" = "true" ]; then
            print_info "Non-interactive mode enabled for testing."
        fi
        
        detect_platform
        validate_platform_support
        test_github_api
        get_latest_release
        
        # Test download URL construction
        print_info "Testing download URL construction..."
        if [ "$OS" = "windows" ]; then
            BINARY_FILENAME="${BINARY_NAME}-windows-${ARCH}.zip"
        elif [ "$OS" = "macos" ]; then
            BINARY_FILENAME="${BINARY_NAME}-darwin-${ARCH}.tar.gz"
        else
            BINARY_FILENAME="${BINARY_NAME}-linux-${ARCH}.tar.gz"
        fi
        
        DOWNLOAD_URL="https://github.com/$REPO/releases/download/$LATEST_RELEASE/$BINARY_FILENAME"
        
        print_success "Test completed successfully!"
        print_info "Repository: $REPO"
        print_info "Platform: $OS-$ARCH"
        print_info "Latest release: $LATEST_RELEASE"
        print_info "Download URL: $DOWNLOAD_URL"
        print_info "Binary filename: $BINARY_FILENAME"
        
        # Test if the download URL is accessible
        print_info "Testing download URL accessibility..."
        if command -v curl >/dev/null 2>&1; then
            HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$DOWNLOAD_URL")
            if [ "$HTTP_STATUS" = "200" ]; then
                print_success "Download URL is accessible (HTTP $HTTP_STATUS)"
            else
                print_warning "Download URL returned HTTP $HTTP_STATUS"
                print_info "This might indicate the binary doesn't exist for this platform/version"
            fi
        else
            print_info "curl not available, skipping download URL test"
        fi
        
        return 0
    fi
    
    # Show non-interactive mode status
    if [ "$NON_INTERACTIVE" = "true" ]; then
        print_info "Running in non-interactive mode."
    fi
    
    # Initial consent prompt
    print_info "This installer will download and install the Stakpak agent on your system."
    print_info "The installation process will:"
    print_info "  - Download binaries from GitHub (https://github.com/stakpak/agent)"
    print_info "  - Install the stakpak binary to your system"
    print_info "  - May require elevated privileges for system directories"
    print_info ""
    if ! read_user_input "Do you want to proceed with the installation? (Y/n) " true; then
        print_info "Installation cancelled by user."
        exit 0
    fi
    
    # Detect platform
    detect_platform
    
    # Validate platform support
    validate_platform_support
    
    # Check if already installed
    if command -v stakpak >/dev/null 2>&1; then
        CURRENT_VERSION=$(stakpak version 2>/dev/null || echo "unknown")
        print_success "Stakpak is already installed: $CURRENT_VERSION"
        if ! read_user_input "Would you like to reinstall or update? (Y/n) " true; then
            print_info "Installation skipped. No action needed."
            exit 0
        fi
        print_info "Proceeding with reinstallation..."
    fi
    
    # Try Homebrew first on macOS and Linux
    if [ "$OS" = "macos" ] || [ "$OS" = "linux" ]; then
        if check_homebrew; then
            print_info "Alternative: Binary installation will be used if you choose 'n'"
            if read_user_input "Homebrew detected. Would you like to use Homebrew for installation? (Y/n) " true; then
                print_info "Using Homebrew for installation."
                install_homebrew
                verify_installation
                echo
                print_success "Installation completed!"
                print_info "Next steps:"
                print_info "1. Get an API key from https://stakpak.dev/generate-api-key"
                print_info "2. Run: stakpak"
                return
            else
                print_info "Homebrew installation declined. Falling back to binary installation."
            fi
        else
            print_info "Homebrew not found. Falling back to binary installation."
        fi
    fi
    
    # Fall back to binary installation
    get_latest_release
    install_binary
    verify_installation
    
    echo
    print_success "Installation completed!"
    print_info "Next steps:"
    print_info "1. Get an API key from https://stakpak.dev/generate-api-key"
    print_info "2. Run: stakpak"
}

# Run main function
main "$@" 