#!/bin/bash

# Universal Installer for Nushell Plugins
# Downloads and installs the latest release of nushell plugins for your platform

set -e

# Configuration
REPO_OWNER="YOUR_ORG"  # Replace with actual GitHub org/user
REPO_NAME="nushell-plugins"
GITHUB_REPO="${REPO_OWNER}/${REPO_NAME}"
BASE_URL="https://github.com/${GITHUB_REPO}"
API_URL="https://api.github.com/repos/${GITHUB_REPO}"

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

# Default values
INSTALL_DIR="/usr/local/bin"
VERSION=""
PLATFORM=""
FORCE=false
DRY_RUN=false
QUIET=false
TEMP_DIR=""

# Functions
log() {
    if [ "$QUIET" != "true" ]; then
        echo -e "${BLUE}[INFO]${NC} $1"
    fi
}

warn() {
    echo -e "${YELLOW}[WARN]${NC} $1" >&2
}

error() {
    echo -e "${RED}[ERROR]${NC} $1" >&2
}

success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

usage() {
    cat << EOF
Universal Installer for Nushell Plugins

USAGE:
    $0 [OPTIONS]

OPTIONS:
    -d, --install-dir DIR    Installation directory (default: /usr/local/bin)
    -v, --version VERSION    Specific version to install (default: latest)
    -p, --platform PLATFORM Force specific platform (auto-detected by default)
    -f, --force             Force installation even if already installed
    --dry-run               Show what would be done without doing it
    --quiet                 Suppress non-essential output
    -h, --help              Show this help message

EXAMPLES:
    # Install latest version to default location
    $0

    # Install to custom directory
    $0 --install-dir ~/.local/bin

    # Install specific version
    $0 --version v1.2.3

    # Force specific platform
    $0 --platform linux-amd64

PLATFORMS:
    linux-amd64    Linux x86_64
    linux-arm64    Linux ARM64
    darwin-amd64   macOS Intel
    darwin-arm64   macOS Apple Silicon
    windows-amd64  Windows x86_64

REQUIREMENTS:
    - curl or wget
    - tar (for Unix-like systems)
    - nushell (nu command should be available)
    - Write permissions to installation directory

MORE INFO:
    Repository: ${BASE_URL}
    Releases:   ${BASE_URL}/releases
EOF
}

# Platform detection
detect_platform() {
    local os=""
    local arch=""

    # Detect OS
    case "$(uname -s)" in
        Linux*)  os="linux" ;;
        Darwin*) os="darwin" ;;
        CYGWIN*|MINGW*|MSYS*) os="windows" ;;
        *)
            error "Unsupported operating system: $(uname -s)"
            exit 1
            ;;
    esac

    # Detect architecture
    case "$(uname -m)" in
        x86_64|amd64) arch="amd64" ;;
        aarch64|arm64) arch="arm64" ;;
        armv7l) arch="arm32" ;;
        *)
            error "Unsupported architecture: $(uname -m)"
            exit 1
            ;;
    esac

    echo "${os}-${arch}"
}

# Check if command exists
command_exists() {
    command -v "$1" >/dev/null 2>&1
}

# Check prerequisites
check_prerequisites() {
    log "Checking prerequisites..."

    # Check for download tools
    if ! command_exists curl && ! command_exists wget; then
        error "Neither curl nor wget found. Please install one of them."
        exit 1
    fi

    # Check for tar (Unix-like systems)
    if [ "$PLATFORM" != "windows-amd64" ] && ! command_exists tar; then
        error "tar command not found. Please install tar."
        exit 1
    fi

    # Check for nushell
    if ! command_exists nu; then
        warn "nushell (nu) not found in PATH. You'll need to install nushell to use these plugins."
        warn "Visit: https://www.nushell.sh/book/installation.html"
    fi

    # Check write permissions
    if [ ! -w "$(dirname "$INSTALL_DIR")" ]; then
        error "No write permission to $(dirname "$INSTALL_DIR")"
        error "Try running with sudo or choose a different directory with --install-dir"
        exit 1
    fi
}

# Download file
download_file() {
    local url="$1"
    local output="$2"

    log "Downloading: $url"

    if command_exists curl; then
        curl -L --fail --progress-bar "$url" -o "$output"
    elif command_exists wget; then
        wget --progress=bar:force:noscroll "$url" -O "$output"
    else
        error "No download tool available"
        exit 1
    fi
}

# Get latest release info
get_latest_release() {
    local api_url="${API_URL}/releases/latest"

    log "Fetching latest release information..."

    if command_exists curl; then
        curl -s "$api_url"
    elif command_exists wget; then
        wget -qO- "$api_url"
    else
        error "No download tool available"
        exit 1
    fi
}

# Get specific release info
get_release_info() {
    local version="$1"
    local api_url="${API_URL}/releases/tags/${version}"

    log "Fetching release information for ${version}..."

    if command_exists curl; then
        curl -s "$api_url"
    elif command_exists wget; then
        wget -qO- "$api_url"
    else
        error "No download tool available"
        exit 1
    fi
}

# Parse JSON (simple parsing for our needs)
parse_json_value() {
    local json="$1"
    local key="$2"

    echo "$json" | sed -n "s/.*\"$key\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" | head -1
}

# Find download URL for platform
find_download_url() {
    local release_json="$1"
    local platform="$2"

    # Look for asset with platform name
    echo "$release_json" | grep -o '"browser_download_url":"[^"]*"' | \
        grep "$platform" | \
        head -1 | \
        sed 's/"browser_download_url":"\([^"]*\)"/\1/'
}

# Extract archive
extract_archive() {
    local archive="$1"
    local dest_dir="$2"

    log "Extracting archive to $dest_dir..."

    case "$archive" in
        *.tar.gz)
            tar -xzf "$archive" -C "$dest_dir"
            ;;
        *.zip)
            if command_exists unzip; then
                unzip -q "$archive" -d "$dest_dir"
            else
                error "unzip command not found. Please install unzip to extract .zip files."
                exit 1
            fi
            ;;
        *)
            error "Unsupported archive format: $archive"
            exit 1
            ;;
    esac
}

# Install plugins
install_plugins() {
    local extract_dir="$1"

    log "Installing plugins to $INSTALL_DIR..."

    # Find the extracted directory (might be nested)
    local plugin_dir=""
    if [ -d "$extract_dir" ]; then
        # Look for nu_plugin_* files directly or in subdirectories
        plugin_dir=$(find "$extract_dir" -name "nu_plugin_*" -type f -executable | head -1 | xargs dirname)

        if [ -z "$plugin_dir" ]; then
            # Try to find a directory with plugins
            plugin_dir=$(find "$extract_dir" -type d -name "*nushell-plugins*" | head -1)
            if [ -z "$plugin_dir" ]; then
                plugin_dir="$extract_dir"
            fi
        fi
    fi

    if [ ! -d "$plugin_dir" ]; then
        error "Could not find plugin directory in extracted archive"
        exit 1
    fi

    log "Found plugins in: $plugin_dir"

    # Create install directory if it doesn't exist
    mkdir -p "$INSTALL_DIR"

    # Copy plugin binaries
    local installed_count=0
    for plugin in "$plugin_dir"/nu_plugin_*; do
        if [ -f "$plugin" ] && [ -x "$plugin" ]; then
            local plugin_name=$(basename "$plugin")
            local dest_path="$INSTALL_DIR/$plugin_name"

            if [ "$DRY_RUN" = "true" ]; then
                log "Would install: $plugin_name -> $dest_path"
            else
                log "Installing: $plugin_name"
                cp "$plugin" "$dest_path"
                chmod +x "$dest_path"
            fi

            installed_count=$((installed_count + 1))
        fi
    done

    if [ $installed_count -eq 0 ]; then
        error "No plugin binaries found to install"
        exit 1
    fi

    success "Installed $installed_count plugins"

    # Copy installation script if available
    if [ -f "$plugin_dir/install_nu_plugins.nu" ] && [ "$DRY_RUN" != "true" ]; then
        log "Running nushell installation script..."
        if command_exists nu; then
            cd "$plugin_dir"
            nu install_nu_plugins.nu --bin-path "$INSTALL_DIR" || {
                warn "Installation script failed, but binaries were copied"
            }
        else
            warn "Nushell not available, skipping automatic plugin registration"
        fi
    fi
}

# Cleanup temporary files
cleanup() {
    if [ -n "$TEMP_DIR" ] && [ -d "$TEMP_DIR" ]; then
        log "Cleaning up temporary files..."
        rm -rf "$TEMP_DIR"
    fi
}

# Main installation function
main() {
    # Set up cleanup trap
    trap cleanup EXIT

    log "Nushell Plugins Universal Installer"
    log "Repository: $GITHUB_REPO"

    # Auto-detect platform if not specified
    if [ -z "$PLATFORM" ]; then
        PLATFORM=$(detect_platform)
        log "Detected platform: $PLATFORM"
    else
        log "Using specified platform: $PLATFORM"
    fi

    # Check prerequisites
    check_prerequisites

    # Get release information
    local release_json=""
    if [ -z "$VERSION" ]; then
        log "Getting latest release..."
        release_json=$(get_latest_release)
        VERSION=$(parse_json_value "$release_json" "tag_name")
    else
        log "Getting release $VERSION..."
        release_json=$(get_release_info "$VERSION")
    fi

    if [ -z "$release_json" ] || [ "$release_json" = "null" ]; then
        error "Failed to get release information"
        exit 1
    fi

    log "Version: $VERSION"

    # Find download URL
    local download_url=$(find_download_url "$release_json" "$PLATFORM")

    if [ -z "$download_url" ]; then
        error "No download found for platform: $PLATFORM"
        error "Available platforms can be found at: ${BASE_URL}/releases/tag/${VERSION}"
        exit 1
    fi

    log "Download URL: $download_url"

    if [ "$DRY_RUN" = "true" ]; then
        log "DRY RUN: Would download and install from $download_url"
        log "DRY RUN: Would install to $INSTALL_DIR"
        return 0
    fi

    # Create temporary directory
    TEMP_DIR=$(mktemp -d)
    local archive_name=$(basename "$download_url")
    local archive_path="$TEMP_DIR/$archive_name"

    # Download archive
    download_file "$download_url" "$archive_path"

    # Verify download
    if [ ! -f "$archive_path" ]; then
        error "Download failed: $archive_path not found"
        exit 1
    fi

    # Extract archive
    extract_archive "$archive_path" "$TEMP_DIR"

    # Install plugins
    install_plugins "$TEMP_DIR"

    success "Installation completed successfully!"

    # Show next steps
    echo ""
    echo "🎉 Nushell plugins have been installed to: $INSTALL_DIR"
    echo ""
    echo "📝 Next steps:"
    echo "   1. Make sure $INSTALL_DIR is in your PATH"
    echo "   2. In nushell, register plugins with:"

    # List installed plugins
    for plugin in "$INSTALL_DIR"/nu_plugin_*; do
        if [ -f "$plugin" ] && [ -x "$plugin" ]; then
            echo "      plugin add $plugin"
        fi
    done

    echo ""
    echo "💡 Or run this one-liner in nushell:"
    echo "   ls $INSTALL_DIR/nu_plugin_* | each { |plugin| plugin add \$plugin.name }"
    echo ""
    echo "🔗 More info: ${BASE_URL}"
}

# Parse command line arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        -d|--install-dir)
            INSTALL_DIR="$2"
            shift 2
            ;;
        -v|--version)
            VERSION="$2"
            shift 2
            ;;
        -p|--platform)
            PLATFORM="$2"
            shift 2
            ;;
        -f|--force)
            FORCE=true
            shift
            ;;
        --dry-run)
            DRY_RUN=true
            shift
            ;;
        --quiet)
            QUIET=true
            shift
            ;;
        -h|--help)
            usage
            exit 0
            ;;
        *)
            error "Unknown option: $1"
            usage
            exit 1
            ;;
    esac
done

# Run main function
main