#!/bin/bash

# Universal Nushell + Plugins Uninstaller
# POSIX compliant shell script that cleanly removes Nushell and plugins installation
#
# This script:
# - Detects installation locations (user ~/.local/bin or system /usr/local/bin)
# - Removes Nushell binary and plugin binaries
# - Cleans up configuration files (with backup option)
# - Removes PATH entries from shell configuration files
# - Unregisters plugins from Nushell
# - Provides detailed removal report

set -e  # Exit on error

# Configuration
INSTALL_DIR_USER="$HOME/.local/bin"
INSTALL_DIR_SYSTEM="/usr/local/bin"
CONFIG_DIR="$HOME/.config/nushell"
BACKUP_SUFFIX="uninstall-backup-$(date +%Y%m%d_%H%M%S)"

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

# Logging functions
log_info() {
    printf "${BLUE}ℹ️  %s${NC}\\n" "$1"
}

log_success() {
    printf "${GREEN}✅ %s${NC}\\n" "$1"
}

log_warn() {
    printf "${YELLOW}⚠️  %s${NC}\\n" "$1"
}

log_error() {
    printf "${RED}❌ %s${NC}\\n" "$1" >&2
}

log_debug() {
    if [ "$DEBUG" = "1" ]; then
        printf "${PURPLE}🐛 DEBUG: %s${NC}\\n" "$1"
    fi
}

# Usage information
usage() {
    cat << EOF
Nushell Full Distribution Uninstaller

USAGE:
    $0 [OPTIONS]

OPTIONS:
    -h, --help              Show this help message
    -y, --yes              Non-interactive mode (assume yes to prompts)
    -k, --keep-config      Keep configuration files (don't remove ~/.config/nushell)
    -b, --backup-config    Backup configuration before removal
    --system               Remove from system location (/usr/local/bin)
                           ⚠️  Requires sudo: sudo $0 --system
    --user                 Remove from user location (~/.local/bin) [default]
                           No sudo required - recommended
    --uninstall-dir PATH   Remove from custom directory (PATH must be writable)
                           Bypasses interactive prompts when supplied explicitly
                           Example: --uninstall-dir ~/.local/bin
    --dry-run              Show what would be removed without actually removing
    --debug                Enable debug output

EXAMPLES:
    # Default removal (from user location, interactive)
    $0

    # Non-interactive removal (from user location)
    $0 -y

    # Remove with config backup
    $0 --backup-config -y

    # Remove from custom directory
    $0 --uninstall-dir ~/.local/bin -y

    # Remove system installation (requires sudo)
    sudo $0 --system -y

    # Preview what would be removed
    $0 --dry-run

TROUBLESHOOTING:
    • Permission denied to /usr/local/bin?
      → Default uses ~/.local/bin (no sudo needed)
      → Or: --uninstall-dir ~/.local/bin (explicit custom path)

    • Unsure what to do?
      → Run with --dry-run first to see what would be removed
      → Default removal is safest: $0 -y

EOF
}

# Parse command line arguments
INTERACTIVE=1
KEEP_CONFIG=0
BACKUP_CONFIG=0
SYSTEM_INSTALL=0
DRY_RUN=0
CUSTOM_UNINSTALL_DIR=""

while [ $# -gt 0 ]; do
    case $1 in
        -h|--help)
            usage
            exit 0
            ;;
        -y|--yes)
            INTERACTIVE=0
            shift
            ;;
        -k|--keep-config)
            KEEP_CONFIG=1
            shift
            ;;
        -b|--backup-config)
            BACKUP_CONFIG=1
            shift
            ;;
        --system)
            SYSTEM_INSTALL=1
            shift
            ;;
        --user)
            SYSTEM_INSTALL=0
            shift
            ;;
        --uninstall-dir)
            CUSTOM_UNINSTALL_DIR="$2"
            shift 2
            ;;
        --dry-run)
            DRY_RUN=1
            shift
            ;;
        --debug)
            DEBUG=1
            shift
            ;;
        *)
            log_error "Unknown option: $1"
            usage
            exit 1
            ;;
    esac
done

# Determine installation directory
if [ -n "$CUSTOM_UNINSTALL_DIR" ]; then
    # Custom directory provided - use it directly (bypass all checks)
    INSTALL_DIR="$CUSTOM_UNINSTALL_DIR"
    log_info "Using custom uninstall directory (via --uninstall-dir): $INSTALL_DIR"
elif [ "$SYSTEM_INSTALL" = "1" ]; then
    INSTALL_DIR="$INSTALL_DIR_SYSTEM"
    log_info "Targeting system installation: $INSTALL_DIR"

    # Check if we need sudo
    if [ "$(id -u)" -ne 0 ] && [ "$DRY_RUN" = "0" ]; then
        log_warn "System installation requires administrative privileges"
        if [ "$INTERACTIVE" = "1" ]; then
            printf "Continue with sudo? [y/N]: "
            read -r response
            case "$response" in
                [yY]|[yY][eE][sS])
                    ;;
                *)
                    log_info "Uninstallation cancelled"
                    exit 0
                    ;;
            esac
        fi

        # Re-run with sudo if not already root
        if [ "$(id -u)" -ne 0 ]; then
            log_info "Re-running with sudo..."
            exec sudo "$0" "$@"
        fi
    fi
else
    INSTALL_DIR="$INSTALL_DIR_USER"
    log_info "Targeting user installation: $INSTALL_DIR"
fi

# Detection functions
detect_nushell_installation() {
    local install_dir="$1"
    local found_items=""

    log_debug "Detecting Nushell installation in $install_dir"

    # Check for nu binary
    if [ -f "$install_dir/nu" ]; then
        found_items="$found_items nu"
        log_debug "Found nu binary: $install_dir/nu"
    fi

    # Check for plugin binaries
    for plugin_binary in "$install_dir"/nu_plugin_*; do
        if [ -f "$plugin_binary" ]; then
            local plugin_name=$(basename "$plugin_binary")
            found_items="$found_items $plugin_name"
            log_debug "Found plugin binary: $plugin_binary"
        fi
    done

    echo "$found_items"
}

detect_config_installation() {
    local config_dir="$1"
    local found_items=""

    log_debug "Detecting configuration in $config_dir"

    if [ -d "$config_dir" ]; then
        # Check for main config files
        for config_file in config.nu env.nu distribution_config.toml; do
            if [ -f "$config_dir/$config_file" ]; then
                found_items="$found_items $config_file"
                log_debug "Found config file: $config_dir/$config_file"
            fi
        done

        # Check for plugin registration
        if [ -f "$config_dir/plugin.nu" ] || [ -f "$config_dir/registry.dat" ]; then
            found_items="$found_items plugin-registry"
            log_debug "Found plugin registry files"
        fi
    fi

    echo "$found_items"
}

detect_shell_profile_entries() {
    local install_dir="$1"
    local found_profiles=""

    log_debug "Detecting shell profile entries for $install_dir"

    # Check common shell profile files
    for profile in "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.profile" "$HOME/.bash_profile"; do
        if [ -f "$profile" ]; then
            if grep -q "$install_dir" "$profile" 2>/dev/null; then
                found_profiles="$found_profiles $(basename "$profile")"
                log_debug "Found PATH entry in: $profile"
            fi
        fi
    done

    echo "$found_profiles"
}

# Removal functions
remove_binaries() {
    local install_dir="$1"
    local binaries="$2"
    local removed_count=0

    log_info "Removing binaries from $install_dir..."

    for binary in $binaries; do
        local binary_path="$install_dir/$binary"
        if [ -f "$binary_path" ]; then
            log_info "Removing binary: $binary"
            if [ "$DRY_RUN" = "0" ]; then
                rm -f "$binary_path"
                if [ $? -eq 0 ]; then
                    log_success "Removed: $binary"
                    removed_count=$((removed_count + 1))
                else
                    log_error "Failed to remove: $binary"
                fi
            else
                log_info "[DRY RUN] Would remove: $binary_path"
                removed_count=$((removed_count + 1))
            fi
        fi
    done

    log_success "Removed $removed_count binaries"
}

backup_configuration() {
    local config_dir="$1"
    local backup_dir="$config_dir.$BACKUP_SUFFIX"

    if [ -d "$config_dir" ]; then
        log_info "Backing up configuration to: $backup_dir"
        if [ "$DRY_RUN" = "0" ]; then
            cp -r "$config_dir" "$backup_dir"
            if [ $? -eq 0 ]; then
                log_success "Configuration backed up successfully"
            else
                log_error "Failed to backup configuration"
                return 1
            fi
        else
            log_info "[DRY RUN] Would backup configuration to: $backup_dir"
        fi
    else
        log_info "No configuration directory to backup"
    fi
}

remove_configuration() {
    local config_dir="$1"
    local config_files="$2"

    if [ "$KEEP_CONFIG" = "1" ]; then
        log_info "Keeping configuration files as requested"
        return 0
    fi

    if [ "$BACKUP_CONFIG" = "1" ]; then
        backup_configuration "$config_dir"
    fi

    if [ -d "$config_dir" ]; then
        log_info "Removing configuration directory: $config_dir"

        # Ask for confirmation if interactive and not just removing empty dir
        if [ "$INTERACTIVE" = "1" ] && [ -n "$config_files" ]; then
            printf "Remove configuration directory $config_dir? [y/N]: "
            read -r response
            case "$response" in
                [yY]|[yY][eE][sS])
                    ;;
                *)
                    log_info "Keeping configuration directory"
                    return 0
                    ;;
            esac
        fi

        if [ "$DRY_RUN" = "0" ]; then
            rm -rf "$config_dir"
            if [ $? -eq 0 ]; then
                log_success "Configuration directory removed"
            else
                log_error "Failed to remove configuration directory"
            fi
        else
            log_info "[DRY RUN] Would remove configuration directory: $config_dir"
        fi
    else
        log_info "No configuration directory found"
    fi
}

remove_shell_profile_entries() {
    local install_dir="$1"
    local profiles="$2"

    if [ -z "$profiles" ]; then
        log_info "No shell profile entries found"
        return 0
    fi

    log_info "Removing PATH entries from shell profiles..."

    for profile_name in $profiles; do
        local profile_path="$HOME/.$profile_name"
        if [ -f "$profile_path" ]; then
            log_info "Cleaning PATH entries from: $profile_name"

            if [ "$DRY_RUN" = "0" ]; then
                # Create backup
                cp "$profile_path" "$profile_path.$BACKUP_SUFFIX"

                # Remove lines containing the install directory
                grep -v "$install_dir" "$profile_path.$BACKUP_SUFFIX" > "$profile_path"

                if [ $? -eq 0 ]; then
                    log_success "Cleaned PATH entries from: $profile_name"
                else
                    log_error "Failed to clean PATH entries from: $profile_name"
                    # Restore backup
                    mv "$profile_path.$BACKUP_SUFFIX" "$profile_path"
                fi
            else
                log_info "[DRY RUN] Would remove PATH entries from: $profile_path"
            fi
        fi
    done
}

# Unregister plugins from nushell (if nu is still available)
unregister_plugins() {
    local install_dir="$1"

    # Only try to unregister if nu is still available somewhere
    local nu_binary=""
    if command -v nu >/dev/null 2>&1; then
        nu_binary=$(command -v nu)
    elif [ -f "$install_dir/nu" ]; then
        nu_binary="$install_dir/nu"
    else
        log_info "Nushell not available for plugin unregistration"
        return 0
    fi

    log_info "Attempting to unregister plugins..."

    if [ "$DRY_RUN" = "0" ]; then
        # Try to get list of registered plugins
        local registered_plugins=""
        registered_plugins=$("$nu_binary" -c "plugin list | get name" 2>/dev/null) || {
            log_warn "Could not retrieve plugin list"
            return 0
        }

        if [ -n "$registered_plugins" ]; then
            log_info "Unregistering plugins from nushell..."
            for plugin in $registered_plugins; do
                "$nu_binary" -c "plugin rm $plugin" 2>/dev/null || {
                    log_warn "Could not unregister plugin: $plugin"
                }
            done
            log_success "Plugin unregistration completed"
        else
            log_info "No registered plugins found"
        fi
    else
        log_info "[DRY RUN] Would attempt to unregister plugins"
    fi
}

# Main uninstallation process
main() {
    log_info "🗑️  Nushell Full Distribution Uninstaller"
    log_info "========================================"

    if [ "$DRY_RUN" = "1" ]; then
        log_warn "DRY RUN MODE - No files will be modified"
    fi

    # Detect current installation
    log_info ""
    log_info "🔍 Detecting current installation..."

    local binaries=""
    local config_files=""
    local shell_profiles=""

    # Check user installation
    local user_binaries=$(detect_nushell_installation "$INSTALL_DIR_USER")
    local user_config=$(detect_config_installation "$CONFIG_DIR")
    local user_profiles=$(detect_shell_profile_entries "$INSTALL_DIR_USER")

    # Check system installation
    local system_binaries=$(detect_nushell_installation "$INSTALL_DIR_SYSTEM")
    local system_profiles=$(detect_shell_profile_entries "$INSTALL_DIR_SYSTEM")

    # Determine what we're removing based on target
    if [ "$SYSTEM_INSTALL" = "1" ]; then
        binaries="$system_binaries"
        shell_profiles="$system_profiles"
        # Config is always user-level
        config_files="$user_config"
    else
        binaries="$user_binaries"
        shell_profiles="$user_profiles"
        config_files="$user_config"
    fi

    # Show detection results
    log_info "Installation Status:"
    if [ -n "$user_binaries" ]; then
        log_info "  📁 User binaries ($INSTALL_DIR_USER): $user_binaries"
    else
        log_info "  📁 User binaries ($INSTALL_DIR_USER): none found"
    fi

    if [ -n "$system_binaries" ]; then
        log_info "  📁 System binaries ($INSTALL_DIR_SYSTEM): $system_binaries"
    else
        log_info "  📁 System binaries ($INSTALL_DIR_SYSTEM): none found"
    fi

    if [ -n "$config_files" ]; then
        log_info "  ⚙️  Configuration ($CONFIG_DIR): $config_files"
    else
        log_info "  ⚙️  Configuration ($CONFIG_DIR): none found"
    fi

    if [ -n "$shell_profiles" ]; then
        log_info "  🐚 Shell profiles: $shell_profiles"
    else
        log_info "  🐚 Shell profiles: no PATH entries found"
    fi

    # Check if anything was found
    if [ -z "$binaries" ] && [ -z "$config_files" ] && [ -z "$shell_profiles" ]; then
        log_warn "No Nushell installation detected"
        if [ "$INTERACTIVE" = "1" ]; then
            printf "Continue anyway? [y/N]: "
            read -r response
            case "$response" in
                [yY]|[yY][eE][sS])
                    ;;
                *)
                    log_info "Uninstallation cancelled"
                    exit 0
                    ;;
            esac
        else
            log_info "Nothing to remove"
            exit 0
        fi
    fi

    # Confirmation prompt
    if [ "$INTERACTIVE" = "1" ]; then
        log_info ""
        log_warn "This will remove the detected Nushell installation components."
        if [ "$KEEP_CONFIG" = "1" ]; then
            log_info "Configuration files will be kept as requested."
        elif [ "$BACKUP_CONFIG" = "1" ]; then
            log_info "Configuration files will be backed up before removal."
        fi

        printf "Proceed with uninstallation? [y/N]: "
        read -r response
        case "$response" in
            [yY]|[yY][eE][sS])
                ;;
            *)
                log_info "Uninstallation cancelled"
                exit 0
                ;;
        esac
    fi

    # Perform uninstallation
    log_info ""
    log_info "🗑️  Starting uninstallation..."

    # Unregister plugins before removing binaries
    if [ -n "$binaries" ]; then
        unregister_plugins "$INSTALL_DIR"
    fi

    # Remove binaries
    if [ -n "$binaries" ]; then
        remove_binaries "$INSTALL_DIR" "$binaries"
    fi

    # Remove configuration
    if [ -n "$config_files" ]; then
        remove_configuration "$CONFIG_DIR" "$config_files"
    fi

    # Clean shell profiles
    if [ -n "$shell_profiles" ]; then
        remove_shell_profile_entries "$INSTALL_DIR" "$shell_profiles"
    fi

    # Final summary
    log_info ""
    log_success "🎉 Uninstallation completed!"
    log_info "Summary:"
    log_info "  🗑️  Removed from: $INSTALL_DIR"
    if [ -n "$config_files" ] && [ "$KEEP_CONFIG" = "0" ]; then
        log_info "  🗑️  Configuration removed: $CONFIG_DIR"
    elif [ "$KEEP_CONFIG" = "1" ]; then
        log_info "  💾 Configuration kept: $CONFIG_DIR"
    fi
    if [ "$BACKUP_CONFIG" = "1" ]; then
        log_info "  💾 Configuration backed up with suffix: .$BACKUP_SUFFIX"
    fi

    log_info ""
    log_info "🔄 To complete removal:"
    log_info "1. Restart your terminal or run: source ~/.bashrc (or equivalent)"
    log_info "2. Verify removal: command -v nu (should return nothing)"

    if [ "$KEEP_CONFIG" = "1" ] || [ "$BACKUP_CONFIG" = "1" ]; then
        log_info ""
        log_info "📝 Note: Configuration files were preserved as requested"
    fi
}

# Run main function
main "$@"