#!/usr/bin/env nu

# Distribution Plugin Installer - Install & Register from Manifest
#
# Reads a distribution manifest (JSON) and installs/registers selected plugins.
# Plugins are copied to ~/.local/bin/ and registered with Nushell.
#
# Usage:
#   install_from_manifest.nu                    # Uses DISTRIBUTION_MANIFEST.json
#   install_from_manifest.nu --manifest manifest.json
#   install_from_manifest.nu --list             # List available plugins
#   install_from_manifest.nu --all              # Install all plugins
#   install_from_manifest.nu --preset essential # Install preset
#   install_from_manifest.nu --select auth kms  # Install specific plugins
#   install_from_manifest.nu --check            # Dry-run

def main [
    --manifest: string = "DISTRIBUTION_MANIFEST.json"    # Path to manifest file
    --list                          # List available plugins only
    --all                           # Install all plugins
    --preset: string                # Use preset: essential, development, full
    --select: list<string>          # Select specific plugins
    --check (-c)                    # Dry-run, don't make changes
    --install-only                  # Only install, don't register
    --register-only                 # Only register, skip install
] {
    log_info "📦 Nushell Distribution Plugin Installer"
    log_info "=================================================================="

    # Step 1: Load manifest
    log_info $"\n📋 Step 1: Loading manifest ($manifest)..."
    let manifest_data = load_manifest $manifest
    if $manifest_data == null {
        return
    }

    let plugins = $manifest_data.plugins

    if ($plugins | length) == 0 {
        log_error "No plugins in manifest!"
        return
    }

    log_success $"Loaded ($plugins | length) available plugin\(s\)"

    # List mode?
    if $list {
        display_plugin_list $plugins
        return
    }

    # Step 2: Select plugins
    log_info "\n🎯 Step 2: Selecting plugins..."
    let selected = if ($preset | is-not-empty) {
        get_preset_plugins $plugins $preset
    } else if ($select | length) > 0 {
        filter_by_name $plugins $select
    } else if $all {
        $plugins
    } else {
        interactive_select $plugins
    }

    if ($selected | length) == 0 {
        log_warn "No plugins selected"
        return
    }

    # Step 3: Show selection
    log_info ""
    log_success $"Selected: ($selected | length) plugin\(s\)"
    for plugin in $selected {
        log_info $"  • ($plugin.name) - ($plugin.purpose)"
    }

    # Step 4: Dry-run?
    if $check {
        log_info "\n✅ DRY RUN - No changes made"
        return
    }

    # Step 5: Confirm
    print ""
    let response = try {
        input "Proceed with installation? (yes/no): "
    } catch {
        "yes"
    }

    if $response != "yes" {
        log_info "Cancelled"
        return
    }

    # Step 6: Install
    if not $register_only {
        log_info "\n📦 Step 3: Installing plugins..."
        install_plugins $selected $manifest_data.source_directory
    }

    # Step 7: Register
    if not $install_only {
        log_info "\n🔌 Step 4: Registering with Nushell..."
        register_plugins $selected
    }

    # Summary
    log_info "\n=================================================================="
    log_success "✅ Complete!"
    log_info ""
    log_info "Next steps:"
    log_info "  1. Restart Nushell: exit && nu"
    log_info "  2. Verify: nu -c 'plugin list'"
}

# Load manifest from JSON file
def load_manifest [path: string]: nothing -> record {
    if not ($path | path exists) {
        log_error $"Manifest not found: ($path)"
        return null
    }

    try {
        let content = open $path
        return $content
    } catch {|err|
        log_error $"Failed to load manifest: ($err.msg)"
        return null
    }
}

# Display plugin list
def display_plugin_list [plugins: list<record>] {
    print ""
    log_success $"Available plugins: ($plugins | length)"
    print ""

    for plugin in $plugins {
        print $"  ✓ ($plugin.name)"
        print $"    ($plugin.purpose)"
        print ""
    }
}

# Get preset plugins
def get_preset_plugins [plugins: list<record>, preset: string]: nothing -> list<record> {
    match $preset {
        "essential" => {
            $plugins | where {|p|
                $p.name in ["nu_plugin_auth", "nu_plugin_kms", "nu_plugin_orchestrator", "nu_plugin_kcl", "nu_plugin_tera"]
            }
        }
        "development" => {
            $plugins | where {|p|
                $p.name in ["nu_plugin_auth", "nu_plugin_kms", "nu_plugin_orchestrator", "nu_plugin_kcl", "nu_plugin_tera", "nu_plugin_highlight", "nu_plugin_image", "nu_plugin_clipboard"]
            }
        }
        "full" => {
            $plugins
        }
        _ => {
            log_error $"Unknown preset: ($preset)"
            log_info "Available: essential, development, full"
            []
        }
    }
}

# Filter by name
def filter_by_name [plugins: list<record>, names: list<string>]: nothing -> list<record> {
    $plugins | where {|p|
        if $p.name in $names {
            true
        } else {
            ($p.name | str replace "^nu_plugin_" "") in $names
        }
    }
}

# Interactive select
def interactive_select [plugins: list<record>]: nothing -> list<record> {
    print ""
    log_info "Available presets:"
    log_info "  1. Essential (5 core plugins)"
    log_info "  2. Development (8 plugins)"
    log_info "  3. All ($($plugins | length) plugins)"
    print ""

    let choice = try {
        input "Select (1-3): "
    } catch {
        "1"
    }

    match $choice {
        "1" => { get_preset_plugins $plugins "essential" }
        "2" => { get_preset_plugins $plugins "development" }
        "3" => { $plugins }
        _ => { [] }
    }
}

# Install plugins to ~/.local/bin/
def install_plugins [selected: list<record>, source_dir: string] {
    let install_dir = $"($env.HOME)/.local/bin"

    # Ensure directory exists
    if not ($install_dir | path exists) {
        log_info $"Creating directory: ($install_dir)"
        mkdir $install_dir
    }

    for plugin in $selected {
        log_info $"Installing: ($plugin.name)"

        try {
            let source_path = $"($source_dir)/($plugin.name)"
            let target_path = $"($install_dir)/($plugin.name)"

            if not ($source_path | path exists) {
                log_error $"  ✗ Source not found: ($source_path)"
                continue
            }

            cp $source_path $target_path
            chmod +x $target_path

            # Fix macOS code signing issues
            fix_macos_binary $target_path

            log_success $"  ✓ Installed to ($target_path)"
        } catch {|err|
            log_error $"  ✗ Failed: ($err.msg)"
        }
    }
}

# Fix macOS code signing (remove quarantine, ad-hoc sign)
def fix_macos_binary [binary_path: string] {
    let os_type = $nu.os-info.name

    if $os_type == "macos" {
        # Remove quarantine attribute
        try {
            ^xattr -d com.apple.quarantine $binary_path out+err>| null
        } catch {
            # Silently ignore if attribute doesn't exist
        }

        # Ad-hoc sign the binary
        try {
            ^codesign -s - $binary_path out+err>| null
        } catch {
            # Silently ignore if codesign fails
        }
    }
}

# Register plugins with Nushell
def register_plugins [selected: list<record>] {
    let install_dir = $"($env.HOME)/.local/bin"
    let nu_cmd = $"($install_dir)/nu"

    # Fix code signing on nu binary if it exists locally
    if ($nu_cmd | path exists) {
        fix_macos_binary $nu_cmd
    }

    for plugin in $selected {
        let basename = $plugin.name | str replace "^nu_plugin_" ""
        let plugin_path = $"($install_dir)/($plugin.name)"

        log_info $"Registering: ($plugin.name)"

        try {
            # Remove old registration if exists
            try {
                if ($nu_cmd | path exists) {
                    ^$nu_cmd -c $"plugin rm ($basename)" out+err>| null
                } else {
                    nu -c $"plugin rm ($basename)" out+err>| null
                }
            } catch {}

            # Register new - use local nu if available, otherwise system nu
            if ($nu_cmd | path exists) {
                ^$nu_cmd -c $"plugin add ($plugin_path)"
            } else {
                nu -c $"plugin add ($plugin_path)"
            }
            log_success $"  ✓ Registered"
        } catch {|err|
            log_error $"  ✗ Failed: ($err.msg)"
        }
    }
}

# Logging
def log_info [msg: string] {
    print $"ℹ️  ($msg)"
}

def log_success [msg: string] {
    print $"✅ ($msg)"
}

def log_error [msg: string] {
    print $"❌ ($msg)"
}

def log_warn [msg: string] {
    print $"⚠️  ($msg)"
}

main
