#!/usr/bin/env nu

# Collect Install Script
# Collects built plugins and prepares them for installation/distribution

# Load environment variables from env file
def load_env_vars [] {
    let env_file = "env"
    if ($env_file | path exists) {
        let content = open $env_file | lines
        | where ($it | str trim | str length) > 0
        | where not ($it | str starts-with "#")
        | each {|line|
            if ($line | str contains "=") {
                let parts = ($line | split row "=")
                if ($parts | length) >= 2 {
                    let key = ($parts | get 0 | str replace "export " "" | str trim)
                    let raw_value = ($parts | get 1 | str trim)
                    # Handle bash-style default values like ${VAR:-default}
                    let value = if ($raw_value | str starts-with "${") and ($raw_value | str contains ":-") {
                        # Extract default value from ${VAR:-default}
                        let parts = ($raw_value | str replace "${" "" | str replace "}" "" | split row ":-")
                        if ($parts | length) >= 2 {
                            $parts | get 1
                        } else {
                            $raw_value
                        }
                    } else {
                        $raw_value
                    }
                    {$key: $value}
                } else {
                    {}
                }
            } else {
                {}
            }
        }
        | reduce -f {} {|item, acc|
            if ($item | is-empty) {
                $acc
            } else {
                $acc | merge $item
            }
        }

        $content
    } else {
        {
            TARGET_PATH: "distribution",
            INSTALL_BIN_PATH: "/usr/local/bin",
            ARCHIVE_DIR_PATH: "/tmp",
            BIN_ARCHIVES_DIR_PATH: "bin_archives"
        }
    }
}

# Load build targets configuration
def load_targets_config [] {
    if ("etc/build_targets.toml" | path exists) {
        open etc/build_targets.toml
    } else {
        {targets: {}}
    }
}

# Get host platform information
def get_host_info [] {
    let arch = match (^uname -m) {
        "x86_64" => "amd64",
        "aarch64" => "arm64",
        "arm64" => "arm64",
        $arch if ($arch | str starts-with "arm") => "arm64",
        $other => $other
    }

    let platform = match (^uname -s | str downcase) {
        $os if ($os | str contains "linux") => "linux",
        $os if ($os | str contains "darwin") => "darwin",
        $os if ($os | str contains "windows") => "windows",
        $other => $other
    }

    {platform: $platform, arch: $arch, full: $"($platform)-($arch)"}
}

# Get all built plugin binaries for a specific target or all targets
def get_built_plugins [target: string = ""] {
    let config = load_targets_config
    let host_info = get_host_info

    if ($target | str length) > 0 {
        # Special handling for "host" target or detected host platform
        if ($target == "host") or ($target == $host_info.full) {
            # Get plugins for host platform (native build)
            glob "nu_plugin_*/target/release/nu_plugin_*"
            | where ($it | path type) == "file"
            | where ($it | path exists)
            | where not ($it | str ends-with ".d")
            | each {|path|
                let plugin_name = $path | path basename
                let plugin_dir = $path | path dirname | path dirname | path dirname
                {
                    name: $plugin_name,
                    path: $path,
                    source_dir: $plugin_dir,
                    target: $host_info.full,
                    size: (ls $path | get size | get 0)
                }
            }
        } else if ($target in ($config.targets | transpose name config | get name)) {
            # Get plugins for specific target
            let target_config = $config.targets | get $target
            get_plugins_for_target $target $target_config
        } else {
            print $"❌ Unknown target: ($target)"
            []
        }
    } else {
        # Get plugins for host platform - use actual detected platform
        glob "nu_plugin_*/target/release/nu_plugin_*"
        | where ($it | path type) == "file"
        | where ($it | path exists)
        | where not ($it | str ends-with ".d")
        | each {|path|
            let plugin_name = $path | path basename
            let plugin_dir = $path | path dirname | path dirname | path dirname
            {
                name: $plugin_name,
                path: $path,
                source_dir: $plugin_dir,
                target: $host_info.full,
                size: (ls $path | get 0.size)
            }
        }
    }
}

# Get plugins for a specific target
def get_plugins_for_target [target_name: string, target_config: record] {
    let rust_target = $target_config.rust_target
    let binary_ext = $target_config | get binary_extension? | default ""

    # Look for binaries in target-specific directories
    let target_pattern = $"nu_plugin_*/target/($rust_target)/release/nu_plugin_*"

    glob $target_pattern
    | where ($it | path type) == "file"
    | where ($it | path exists)
    | where not ($it | str ends-with ".d")
    | each {|path|
        let plugin_name = $path | path basename
        let plugin_dir = $path | path dirname | path dirname | path dirname | path dirname
        {
            name: $plugin_name,
            path: $path,
            source_dir: $plugin_dir,
            target: $target_name,
            size: (ls $path | get 0.size)
        }
    }
}

# Get all available built targets
def get_available_targets [] {
    let config = load_targets_config
    let host_info = get_host_info

    mut available = []

    # Check host platform first
    let host_plugins = glob "nu_plugin_*/target/release/nu_plugin_*" | where not ($it | str ends-with ".d")
    if ($host_plugins | length) > 0 {
        $available = ($available | append {
            name: $host_info.full,
            platform_name: $host_info.full,
            count: ($host_plugins | length),
            description: "Host platform binaries"
        })
    }

    # Check cross-compiled targets
    for target in ($config.targets | transpose name config) {
        let rust_target = $target.config.rust_target
        let target_plugins = glob $"nu_plugin_*/target/($rust_target)/release/nu_plugin_*" | where not ($it | str ends-with ".d")
        if ($target_plugins | length) > 0 {
            $available = ($available | append {
                name: $target.name,
                platform_name: $target.config.platform_name,
                count: ($target_plugins | length),
                description: $target.config.description
            })
        }
    }

    $available
}

# Create target directory structure
def create_target_structure [target_path: string] {
    if not ($target_path | path exists) {
        mkdir $target_path
        print $"📁 Created target directory: ($target_path)"
    }

    # Create subdirectories if needed
    let subdirs = ["scripts", "docs"]
    for subdir in $subdirs {
        let subdir_path = $"($target_path)/($subdir)"
        if not ($subdir_path | path exists) {
            mkdir $subdir_path
        }
    }
}

# Copy plugin binaries to target
def copy_plugins [plugins: list, target_path: string] {
    print $"📦 Copying ($plugins | length) plugin binaries..."

    for plugin in $plugins {
        let dest_path = $"($target_path)/($plugin.name)"
        cp $plugin.path $dest_path

        # Make executable
        chmod +x $dest_path

        print $"  ✅ ($plugin.name) (($plugin.size))"
    }
}

# Copy additional files
def copy_additional_files [target_path: string] {
    let files_to_copy = [
        {src: "LICENSE", dest: "LICENSE", required: false},
        {src: "README.md", dest: "README", required: false},
        {src: "env", dest: "env", required: false}
    ]

    for file in $files_to_copy {
        if ($file.src | path exists) {
            cp $file.src $"($target_path)/($file.dest)"
            print $"  📄 Copied ($file.src) → ($file.dest)"
        } else if $file.required {
            print $"  ⚠️  Required file not found: ($file.src)"
        }
    }
}

# Create installation script
def create_install_script [target_path: string, install_file: string] {
    let timestamp = (date now | format date "%Y-%m-%d %H:%M:%S")
    let install_script_content = "#!/usr/bin/env nu

# Auto-generated installation script for nushell plugins
# Generated at: " + $timestamp + "

def main [
    --bin-path (-b): string = \"/usr/local/bin\"  # Installation path
    --plugins (-p): list<string> = []           # Specific plugins to install
    --list (-l)                                 # List available plugins
    --dry-run (-d)                              # Show what would be done
    --register-only (-r)                        # Only register plugins, don't copy binaries
    --no-register                               # Copy binaries but don't register with nushell
    --verify (-v)                               # Verify plugin registration after installation
] {
    let available_plugins = ls | where type == file and name =~ \"nu_plugin_\" | get name

    if " + '$list' + " {
        print \"📦 Available plugins:\"
        for plugin in " + '$available_plugins' + " {
            print " + '$"  - ($plugin)"' + "
        }
        return
    }

    let plugins_to_install = if (" + '$plugins' + " | length) > 0 {
        " + '$plugins' + " | where " + '$it' + " in " + '$available_plugins' + "
    } else {
        " + '$available_plugins' + "
    }

    if (" + '$plugins_to_install' + " | length) == 0 {
        print \"❓ No plugins to install\"
        return
    }

    print " + '$"🚀 Processing ($plugins_to_install | length) plugins..."' + "

    # Step 1: Copy binaries (unless register-only mode)
    if not " + '$register_only' + " {
        print " + '$"\\n📦 Installing binaries to ($bin_path)..."' + "
        for plugin in " + '$plugins_to_install' + " {
            if " + '$dry_run' + " {
                print " + '$"Would install: ($plugin) → ($bin_path)/($plugin)"' + "
            } else {
                try {
                    cp " + '$plugin' + " " + '$"($bin_path)/($plugin)"' + "
                    chmod +x " + '$"($bin_path)/($plugin)"' + "
                    print " + '$"  ✅ Installed ($plugin)"' + "
                } catch {|err|
                    print " + '$"  ❌ Failed to install ($plugin): ($err.msg)"' + "
                }
            }
        }
    }

    # Step 2: Register plugins with nushell (unless disabled)
    if not " + '$no_register' + " {
        print \"\\n🔌 Registering plugins with nushell...\"
        for plugin in " + '$plugins_to_install' + " {
            let plugin_path = if " + '$register_only' + " {
                # Use current directory path for register-only mode
                " + '$"./($plugin)"' + "
            } else {
                # Use installation path for normal mode
                " + '$"($bin_path)/($plugin)"' + "
            }

            if " + '$dry_run' + " {
                print " + '$"Would register: plugin add ($plugin_path)"' + "
            } else {
                try {
                    nu -c " + '$"plugin add ($plugin_path)"' + "
                    print " + '$"  ✅ Registered ($plugin)"' + "
                } catch {|err|
                    print " + '$"  ⚠️  Failed to register ($plugin): ($err.msg)"' + "
                    print " + '$"     You can manually register with: plugin add ($plugin_path)"' + "
                }
            }
        }
    }

    # Step 3: Verify plugin registration (if requested and plugins were registered)
    if " + '$verify' + " and not " + '$no_register' + " and not " + '$dry_run' + " {
        print \"\\n🔍 Verifying plugin registration...\"
        for plugin in " + '$plugins_to_install' + " {
            let plugin_name = (" + '$plugin' + " | str replace \"nu_plugin_\" \"\")
            try {
                let found = (nu -c " + '$"plugin list | where name =~ ($plugin_name) | length"' + " | into int)
                if " + '$found' + " > 0 {
                    print " + '$"  ✅ Verified ($plugin)"' + "
                } else {
                    print " + '$"  ❌ Not found in plugin list: ($plugin)"' + "
                }
            } catch {|err|
                print " + '$"  ⚠️  Could not verify ($plugin): ($err.msg)"' + "
            }
        }
    }

    # Summary
    if not " + '$dry_run' + " {
        if " + '$register_only' + " {
            print \"\\n✅ Plugin registration completed!\"
            if " + '$verify' + " {
                print \"💡 Run 'plugin list' to see all registered plugins\"
            }
        } else if " + '$no_register' + " {
            print \"\\n✅ Plugin installation completed!\"
            print \"💡 To register plugins, run: nu install_nu_plugins.nu --register-only\"
        } else {
            print \"\\n✅ Plugin installation and registration completed!\"
            if " + '$verify' + " {
                print \"💡 All plugins verified. Run 'plugin list' to see details\"
            } else {
                print \"💡 Restart nushell or run 'plugin list' to see registered plugins\"
                print \"   Add --verify to automatically check registration next time\"
            }
        }
    }
}
"

    $install_script_content | save --force ($target_path | path join $install_file)
    chmod +x ($target_path | path join $install_file)
    print $"📜 Created installation script: ($install_file)"
}

# Main function
def main [
    --target-path (-t): string = ""     # Override target path
    --platform (-p): string = ""       # Specific platform to collect (e.g., linux-amd64)
    --all-platforms (-a)               # Collect all available platforms
    --force (-f)                       # Force overwrite existing files
    --list (-l)                        # List available plugins only
    --list-platforms                   # List available platforms
] {
    # Ensure we're in the repository root directory
    if not ("nu_plugin_clipboard" | path exists) {
        error make {msg: "Please run this script from the nushell-plugins repository root directory"}
    }

    print "📦 Nushell Plugin Collection & Installation Preparation"

    # Load environment variables
    let env_vars = load_env_vars
    let base_target_path = if ($target_path | str length) > 0 { $target_path } else { $env_vars.TARGET_PATH? | default "distribution" }
    let install_file = $env_vars.INSTALL_FILE? | default "install_nu_plugins.nu"

    # List platforms mode
    if $list_platforms {
        let available = get_available_targets
        if ($available | length) == 0 {
            print "❓ No built platforms found"
            print "💡 Run cross-compilation builds first"
        } else {
            print "📊 Available built platforms:"
            for target in $available {
                print $"  ✅ ($target.name) ($target.platform_name): ($target.count) plugins"
                print $"      ($target.description)"
            }
        }
        return
    }

    # Determine platforms to collect
    let available_targets = get_available_targets
    let host_info = get_host_info

    let platforms_to_collect = if $all_platforms {
        $available_targets
    } else if ($platform | str length) > 0 {
        # Handle "host" as a special case - map to actual platform
        let target_to_find = if ($platform == "host") { $host_info.full } else { $platform }
        let selected = $available_targets | where name == $target_to_find
        if ($selected | length) == 0 {
            print $"❌ Platform not found: ($platform)"
            print $"💡 Available platforms: ($available_targets | get name | str join ', ')"
            exit 1
        }
        $selected
    } else {
        # Default to host platform if available
        let host_info = get_host_info
        let host_target = $available_targets | where name == $host_info.full
        if ($host_target | length) > 0 {
            $host_target
        } else {
            # Fallback to first available platform
            $available_targets | first 1
        }
    }

    if ($platforms_to_collect | length) == 0 {
        print "❓ No platforms to collect"
        print "💡 Build plugins first with: just build or just build-cross-all"
        exit 1
    }

    print $"🎯 Platforms to collect: ($platforms_to_collect | length)"
    for platform in $platforms_to_collect {
        print $"  - ($platform.name): ($platform.count) plugins"
    }

    # Process each platform
    mut total_collected = 0
    for platform_info in $platforms_to_collect {
        let platform_name = $platform_info.name
        let plugins = get_built_plugins $platform_name

        if $list {
            if ($plugins | length) == 0 {
                print $"❓ No built plugins found for ($platform_name)"
            } else {
                print $"\n📦 ($platform_name) - ($plugins | length) built plugins:"
                for plugin in $plugins {
                    print $"  ✅ ($plugin.name) (($plugin.size)) from ($plugin.source_dir)"
                }
            }
            continue
        }

        if ($plugins | length) == 0 {
            print $"⚠️  No plugins found for platform: ($platform_name)"
            continue
        }

        # Create platform-specific directory structure
        let platform_target_path = if $all_platforms {
            $"($base_target_path)/($platform_name)"
        } else {
            $base_target_path
        }

        print $"\n📦 Collecting ($plugins | length) plugins for ($platform_name)..."
        print $"📁 Target: ($platform_target_path)"

        # Check if target exists and handle accordingly
        if ($platform_target_path | path exists) and not $force {
            print $"⚠️  Target directory '($platform_target_path)' already exists"
            let confirm = input "Continue and overwrite? [y/N]: "
            if ($confirm | str downcase) != "y" {
                print "❌ Skipping ($platform_name)"
                continue
            }
        }

        # Create target structure
        create_target_structure $platform_target_path

        # Copy plugins
        copy_plugins $plugins $platform_target_path

        # Copy additional files
        print "📄 Copying additional files..."
        copy_additional_files $platform_target_path

        # Create platform-specific installation script
        create_install_script $platform_target_path $install_file

        $total_collected = $total_collected + ($plugins | length)

        print $"✅ Collected ($plugins | length) plugins for ($platform_name)"
    }

    # List mode summary
    if $list {
        return
    }

    # Summary
    print $"\n🎉 Collection completed!"
    print $"📁 Base directory: ($base_target_path)"
    print $"📦 Total plugins collected: ($total_collected)"
    print $"🎯 Platforms: ($platforms_to_collect | get name | str join ', ')"

    print "\n💡 Next steps:"
    if $all_platforms {
        print "  1. Package all platforms: just pack-cross"
        print "  2. Test individual platforms: cd distribution/PLATFORM && nu install_nu_plugins.nu --dry-run"
    } else {
        let final_path = if $all_platforms { $"($base_target_path)/($platforms_to_collect.0.name)" } else { $base_target_path }
        print $"  1. Test installation: cd ($final_path) && nu ($install_file) --dry-run"
        print $"  2. Package for distribution: just pack"
        print $"  3. Install locally: cd ($final_path) && nu ($install_file)"
    }
}

if ($env.NUSHELL_EXECUTION_CONTEXT? | default "" | str contains "run") {
    main
}