#!/usr/bin/env nu
# Install - Install binaries from source or bundle
#
# Usage:
#   nu scripts/provisioning/install.nu --source ./bin --prefix ~/.local
#   nu scripts/provisioning/install.nu --source ./bin
#

use common/platform.nu *
use common/validate.nu *

def show-help [] {
    let help_text = "
syntaxis Install - Install binaries to system

USAGE:
  nu scripts/provisioning/install.nu [OPTIONS]

OPTIONS:
  --source <DIR>        Source directory containing binaries (required)
  --prefix <PATH>       Installation prefix
                        Default: /usr/local
  --force               Overwrite existing binaries
  --backup              Backup existing binaries before overwriting
  --help                Show this help message

EXAMPLES:
  # Install binaries to default location
  nu scripts/provisioning/install.nu --source ./bin

  # Install to custom prefix
  nu scripts/provisioning/install.nu --source ./bin --prefix ~/.local

  # Install with backup
  nu scripts/provisioning/install.nu --source ./bin --backup
"
    print $help_text
}

def detect-binaries [source_dir: path] {
    if (not (($source_dir | path exists))) {
        let msg = "Source directory not found: " + ($source_dir | into string)
error make {msg: $msg}
    }

    let files = (glob ($source_dir | path join "*"))
    let binaries = (
        $files
        | where {|f| (($f | path type) == "file")}
        | each {|f| {path: $f, name: ($f | path basename)}}
    )

    if (($binaries | length) == 0) {
        let msg = "No binaries found in: " + ($source_dir | into string)
error make {msg: $msg}
    }

    $binaries
}

def ensure-bin-directory [bin_dir: path] {
    if (not (($bin_dir | path exists))) {
        print ("📁 Creating directory: " + ($bin_dir | into string))
        ^mkdir -p $bin_dir
    }

    let perm_check = (validate-permissions $bin_dir --write true)
    if (not ($perm_check.valid)) {
        let msg = "Cannot write to directory: " + ($bin_dir | into string)
error make {msg: $msg}
    }
}

def backup-existing [bin_dir: path, binary_name: string] {
    let binary_path = ($bin_dir | path join $binary_name)
    if (($binary_path | path exists)) {
        let timestamp = (date now | format date "%Y%m%d-%H%M%S")
        let backup_path = ($bin_dir | path join ($binary_name + ".backup-" + $timestamp))
        ^cp $binary_path $backup_path
        print ("  📦 Backed up to: " + ($backup_path | path basename))
    }
}

def install-binary [source_path: path, bin_dir: path, binary_name: string, force: bool, backup: bool] {
    let dest_path = ($bin_dir | path join $binary_name)

    if (($dest_path | path exists)) {
        if $backup {
            backup-existing $bin_dir $binary_name
        } else if (not $force) {
            print ("  ⚠️  " + $binary_name + " already exists (use --force to overwrite)")
            return false
        }
    }

    print ("  📋 Installing: " + $binary_name)
    ^cp $source_path $dest_path
    ^chmod +x $dest_path
    print ("    ✓ Installed to: " + ($dest_path | into string))
    true
}

def create-manifest [bin_dir: path, installed_binaries: list] {
    let manifest_dir = ($env.HOME | path join ".syntaxis")
    ^mkdir -p $manifest_dir

    let manifest = {
        installation: {
            installed_at: (date now | format date "%Y-%m-%dT%H:%M:%SZ")
            prefix: ($bin_dir | into string)
            binaries: $installed_binaries
        }
    }

    let manifest_file = ($manifest_dir | path join "manifest.toml")
    let content = $manifest | to toml
    $content | ^tee $manifest_file
    print ("✅ Manifest saved: " + ($manifest_file | into string))
}

def show-installation-summary [bin_dir: path, installed_binaries: list] {
    print ""
    print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    print "✅ Installation Summary"
    print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    print ("Installed to: " + ($bin_dir | into string))
    print ("Binaries:     " + (($installed_binaries | length) | into string))
    $installed_binaries | each { |bin|
        print ("  ✓ " + $bin)
    }
    print ""
    print "Next steps:"
    print "  1. Add to PATH: export PATH=\"" + ($bin_dir | into string) + ":$PATH\""
    print "  2. Verify: " + (($installed_binaries.0) | into string) + " --help"
    print ""
}

# Main entry point
def main [--source: path = "", --prefix: path = "", --force = false, --backup = false, --help = false] {
    if $help {
        show-help
        return
    }

    if ($source == "") {
        error make {msg: "Source directory must be specified with --source"}
    }

    # Determine installation prefix
    let install_prefix = if ($prefix == "") {
        default-prefix (current-target)
    } else {
        $prefix
    }

    let bin_dir = ($install_prefix | path join "bin")

    print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    print "📦 syntaxis Install"
    print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    print ("Source:      " + ($source | into string))
    print ("Destination: " + ($bin_dir | into string))
    print ("Force:       " + ($force | into string))
    print ("Backup:      " + ($backup | into string))
    print ""

    # Ensure destination directory is writable
    ensure-bin-directory $bin_dir

    # Detect binaries in source
    print "🔍 Detecting binaries..."
    let binaries = (detect-binaries $source)
    print ("  Found " + (($binaries | length) | into string) + " binaries")
    print ""

    # Install each binary
    print "📥 Installing binaries..."
    let installed_binaries = (
        $binaries
        | each { |bin|
            let success = (install-binary $bin.path $bin_dir $bin.name $force $backup)
            if $success {
                $bin.name
            } else {
                null
            }
        }
        | where { |item| (not ($item == null)) }
    )

    if (($installed_binaries | length) > 0) {
        create-manifest $bin_dir $installed_binaries
        show-installation-summary $bin_dir $installed_binaries
    } else {
        print "❌ No binaries were installed"
    }
}

