# Module: Utilities Command Handlers
# Purpose: Implements handlers for all utility commands: SSH, SOPS, cache management, providers, plugins, and guides.
# Dependencies: Various lib_provisioning modules

export def handle_ssh [flags: record] {
  let curr_settings = (find_get_settings --infra $flags.infra --settings $flags.settings $flags.include_notuse)
  rm -rf $curr_settings.wk_path
  server_ssh $curr_settings "" "pub" false
}

# SOPS edit command handler
export def handle_sops_edit [task: string, ops: string, flags: record] {
  let pos = if $task == "sed" { 0 } else { 1 }
  let ops_parts = ($ops | split row " ")
  let target_file = if ($ops_parts | length) > $pos { $ops_parts | get $pos } else { "" }

  if ($target_file | is-empty) {
    throw-error $"🛑 No file found" $"for (_ansi yellow_bold)sops(_ansi reset) edit"
    exit -1
  }

  let target_full_path = if not ($target_file | path exists) {
    let infra_path = (get_infra $flags.infra)
    let candidate = ($infra_path | path join $target_file)
    if ($candidate | path exists) {
      $candidate
    } else {
      throw-error $"🛑 No file (_ansi green_italic)($target_file)(_ansi reset) found" $"for (_ansi yellow_bold)sops(_ansi reset) edit"
      exit -1
    }
  } else {
    $target_file
  }

  # Setup SOPS environment if needed
  if ($env.PROVISIONING_SOPS? | is-empty) {
    let curr_settings = (find_get_settings --infra $flags.infra --settings $flags.settings $flags.include_notuse)
    rm -rf $curr_settings.wk_path
    $env.CURRENT_INFRA_PATH = ($curr_settings.infra_path | path join $curr_settings.infra)
    use ../../sops_env.nu
  }

  if $task == "sed" {
    on_sops "sed" $target_full_path
  } else {
    on_sops $task $target_full_path ($ops_parts | skip 1)
  }
}

# Cache command handler
export def handle_cache [ops: string, flags: record] {
  use ../../lib_provisioning/config/cache/simple-cache.nu *

  # Parse cache subcommand
  let parts = if ($ops | is-not-empty) {
    ($ops | str trim | split row " " | where { |x| ($x | is-not-empty) })
  } else {
    []
  }

  let subcommand = if ($parts | length) > 0 { $parts | get 0 } else { "status" }
  let args = if ($parts | length) > 1 { $parts | skip 1 } else { [] }

  # Handle cache commands
  match $subcommand {
    "status" => {
      print ""
      cache-status
      print ""
    }

    "config" => {
      let config_cmd = if ($args | length) > 0 { $args | get 0 } else { "show" }
      match $config_cmd {
        "show" => {
          print ""
          let config = (get-cache-config)
          let cache_base = (($env.HOME? | default "~" | path expand) | path join ".provisioning" "cache" "config")
          print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
          print "📋 Cache Configuration"
          print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
          print ""

          print "▸ Core Settings:"
          let enabled = ($config | get --optional enabled | default true)
          print ("  Enabled: " + ($enabled | into string))
          print ""

          print "▸ Cache Location:"
          print ("  Base Path: " + $cache_base)
          print ""

          print "▸ Time-To-Live (TTL) Settings:"
          let ttl_final = ($config | get --optional ttl_final_config | default "300")
          let ttl_nickel = ($config | get --optional ttl_nickel | default "1800")
          let ttl_sops = ($config | get --optional ttl_sops | default "900")
          print ("  Final Config: " + ($ttl_final | into string) + "s (5 minutes)")
          print ("  Nickel Compilation: " + ($ttl_nickel | into string) + "s (30 minutes)")
          print ("  SOPS Decryption: " + ($ttl_sops | into string) + "s (15 minutes)")
          print "  Provider Config: 600s (10 minutes)"
          print "  Platform Config: 600s (10 minutes)"
          print ""

          print "▸ Security Settings:"
          print "  SOPS File Permissions: 0600 (owner read-only)"
          print "  SOPS Directory Permissions: 0700 (owner access only)"
          print ""

          print "▸ Validation Settings:"
          print "  Strict mtime Checking: true (validates all source files)"
          print ""
          print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
          print ""
        }
        "get" => {
          if ($args | length) > 1 {
            let setting = $args | get 1
            let value = (cache-config-get $setting)
            if $value != null {
              print $"($setting) = ($value)"
            } else {
              print $"Setting not found: ($setting)"
            }
          } else {
            print "❌ cache config get requires a setting path"
            print "Usage: provisioning cache config get <path>"
            exit 1
          }
        }
        "set" => {
          if ($args | length) > 2 {
            let setting = $args | get 1
            let value = ($args | skip 2 | str join " ")
            cache-config-set $setting $value
            print $"✓ Set ($setting) = ($value)"
          } else {
            print "❌ cache config set requires setting path and value"
            print "Usage: provisioning cache config set <path> <value>"
            exit 1
          }
        }
        _ => {
          print $"❌ Unknown cache config subcommand: ($config_cmd)"
          print ""
          print "Available cache config subcommands:"
          print "  show              - Show all cache configuration"
          print "  get <setting>     - Get specific cache setting"
          print "  set <key> <val>   - Set cache setting"
          print ""
          print "Available settings for get/set:"
          print "  enabled           - Cache enabled (true/false)"
          print "  ttl_final_config  - TTL for final config (seconds)"
          print "  ttl_nickel           - TTL for Nickel compilation (seconds)"
          print "  ttl_sops          - TTL for SOPS decryption (seconds)"
          print ""
          print "Examples:"
          print "  provisioning cache config show"
          print "  provisioning cache config get ttl_final_config"
          print "  provisioning cache config set ttl_final_config 600"
          exit 1
        }
      }
    }

    "clear" => {
      let cache_type = if ($args | length) > 0 { $args | get 0 } else { "all" }
      cache-clear $cache_type
      print $"✓ Cleared cache: ($cache_type)"
    }

    "list" => {
      let cache_type = if ($args | length) > 0 { $args | get 0 } else { "*" }
      let items = (cache-list $cache_type)
      if ($items | length) > 0 {
        print $"Cache items \(type: ($cache_type)\):"
        $items | each { |item| print $"  ($item)" }
      } else {
        print "No cache items found"
      }
    }

    "help" => {
      print "
Cache Management Commands:

  provisioning cache status                    # Show cache status and statistics
  provisioning cache config show               # Show cache configuration
  provisioning cache config get <setting>      # Get specific cache setting
  provisioning cache config set <setting> <val> # Set cache setting
  provisioning cache clear [type]              # Clear cache (default: all)
  provisioning cache list [type]               # List cached items (default: all)
  provisioning cache help                      # Show this help message

Available settings (for get/set):
  enabled          - Cache enabled (true/false)
  ttl_final_config - TTL for final config (seconds)
  ttl_nickel          - TTL for Nickel compilation (seconds)
  ttl_sops         - TTL for SOPS decryption (seconds)

Examples:
  provisioning cache status
  provisioning cache config get ttl_final_config
  provisioning cache config set ttl_final_config 600
  provisioning cache config set enabled false
  provisioning cache clear nickel
  provisioning cache list
"
    }

    _ => {
      print $"❌ Unknown cache command: ($subcommand)"
      print ""
      print "Available cache commands:"
      print "  status              - Show cache status and statistics"
      print "  config show         - Show cache configuration"
      print "  config get <key>    - Get specific cache setting"
      print "  config set <k> <v>  - Set cache setting"
      print "  clear [type]        - Clear cache (all, nickel, sops, final)"
      print "  list [type]         - List cached items"
      print "  help                - Show this help message"
      print ""
      print "Examples:"
      print "  provisioning cache status"
      print "  provisioning cache config get ttl_final_config"
      print "  provisioning cache config set ttl_final_config 600"
      print "  provisioning cache clear nickel"
      exit 1
    }
  }
}

# Providers command handler - supports list, info, install, remove, installed, validate
export def handle_providers [ops: string, flags: record] {
  use ../../lib_provisioning/module_loader.nu *

  # Parse subcommand and arguments
  let parts = if ($ops | is-not-empty) {
    ($ops | str trim | split row " " | where { |x| ($x | is-not-empty) })
  } else {
    []
  }

  let subcommand = if ($parts | length) > 0 { $parts | get 0 } else { "list" }
  let args = if ($parts | length) > 1 { $parts | skip 1 } else { [] }

  match $subcommand {
    "list" => { handle_providers_list $flags $args }
    "info" => { handle_providers_info $args $flags }
    "install" => { handle_providers_install $args $flags }
    "remove" => { handle_providers_remove $args $flags }
    "installed" => { handle_providers_installed $args $flags }
    "validate" => { handle_providers_validate $args $flags }
    "help" | "-h" | "--help" => { show_providers_help }
    _ => {
      print $"❌ Unknown providers subcommand: ($subcommand)"
      print ""
      show_providers_help
      exit 1
    }
  }
}

# List all available providers
export def handle_providers_list [flags: record, args: list] {
  use ../../lib_provisioning/module_loader.nu *

  _print $"(_ansi green)PROVIDERS(_ansi reset) list: \n"

  # Parse flags
  let show_nickel = ($args | any { |x| $x == "--nickel" })
  let format_idx = ($args | enumerate | where item == "--format" | get 0?.index | default (-1))
  let format = if $format_idx >= 0 and ($args | length) > ($format_idx + 1) {
    $args | get ($format_idx + 1)
  } else {
    "table"
  }
  let no_cache = ($args | any { |x| $x == "--no-cache" })

  # Get providers using cached Nickel module loader
  let providers = if $no_cache {
    (discover-nickel-modules "providers")
  } else {
    (discover-nickel-modules-cached "providers")
  }

  match $format {
    "json" => {
      _print ($providers | to json) "json" "result" "table"
    }
    "yaml" => {
      _print ($providers | to yaml) "yaml" "result" "table"
    }
    _ => {
      # Table format - show summary or full with --nickel
      if $show_nickel {
        _print ($providers | to json) "json" "result" "table"
      } else {
        # Show simplified table
        let simplified = ($providers | each {|p|
          {name: $p.name, type: $p.type, version: $p.version}
        })
        _print ($simplified | to json) "json" "result" "table"
      }
    }
  }
}

# Show detailed provider information
export def handle_providers_info [args: list, flags: record] {
  use ../../lib_provisioning/module_loader.nu *

  if ($args | is-empty) {
    print "❌ Provider name required"
    print "Usage: provisioning providers info <provider> [--nickel] [--no-cache]"
    exit 1
  }

  let provider_name = $args | get 0
  let show_nickel = ($args | any { |x| $x == "--nickel" })
  let no_cache = ($args | any { |x| $x == "--no-cache" })

  print $"(_ansi blue_bold)📋 Provider Information: ($provider_name)(_ansi reset)"
  print ""

  let providers = if $no_cache {
    (discover-nickel-modules "providers")
  } else {
    (discover-nickel-modules-cached "providers")
  }
  let provider_info = ($providers | where name == $provider_name)

  if ($provider_info | is-empty) {
    print $"❌ Provider not found: ($provider_name)"
    exit 1
  }

  let info = ($provider_info | first)

  print $"  Name: ($info.name)"
  print $"  Type: ($info.type)"
  print $"  Path: ($info.path)"
  print $"  Has Nickel: ($info.has_nickel)"

  if $show_nickel and $info.has_nickel {
    print ""
    print "  (_ansi cyan_bold)Nickel Module:(_ansi reset)"
    print $"    Module Name: ($info.module_name)"
    print $"    Nickel Path: ($info.schema_path)"
    print $"    Version: ($info.version)"
    print $"    Edition: ($info.edition)"

    # Check for nickel.mod file
    let decl_mod = ($info.schema_path | path join "nickel.mod")
    if ($decl_mod | path exists) {
      print ""
      print $"  (_ansi cyan_bold)nickel.mod content:(_ansi reset)"
      open $decl_mod | lines | each {|line| print $"    ($line)"}
    }
  }

  print ""
}

# Install provider for infrastructure
export def handle_providers_install [args: list, flags: record] {
  use ../../lib_provisioning/module_loader.nu *

  if ($args | length) < 2 {
    print "❌ Provider name and infrastructure required"
    print "Usage: provisioning providers install <provider> <infra> [--version <v>]"
    exit 1
  }

  let provider_name = $args | get 0
  let infra_name = $args | get 1

  # Extract version flag if present
  let version_idx = ($args | enumerate | where item == "--version" | get 0?.index | default (-1))
  let version = if $version_idx >= 0 and ($args | length) > ($version_idx + 1) {
    $args | get ($version_idx + 1)
  } else {
    "0.0.1"
  }

  # Resolve infrastructure path
  let infra_path = (resolve_infra_path $infra_name)

  if ($infra_path | is-empty) {
    print $"❌ Infrastructure not found: ($infra_name)"
    exit 1
  }

  # Install provider
  install-provider $provider_name $infra_path --version $version

  print ""
  print $"(_ansi yellow_bold)💡 Next steps:(_ansi reset)"
  print $"  1. Check the manifest: ($infra_path)/providers.manifest.yaml"
  print $"  2. Update server definitions to use ($provider_name)"
  print $"  3. Run: nickel run defs/servers.ncl"
}

# Remove provider from infrastructure
export def handle_providers_remove [args: list, flags: record] {
  use ../../lib_provisioning/module_loader.nu *

  if ($args | length) < 2 {
    print "❌ Provider name and infrastructure required"
    print "Usage: provisioning providers remove <provider> <infra> [--force]"
    exit 1
  }

  let provider_name = $args | get 0
  let infra_name = $args | get 1
  let force = ($args | any { |x| $x == "--force" })

  # Resolve infrastructure path
  let infra_path = (resolve_infra_path $infra_name)

  if ($infra_path | is-empty) {
    print $"❌ Infrastructure not found: ($infra_name)"
    exit 1
  }

  # Confirmation unless forced
  if not $force {
    print $"(_ansi yellow)⚠️  This will remove provider ($provider_name) from ($infra_name)(_ansi reset)"
    print "   Nickel dependencies will be updated."
    let response = (input "Continue? (y/N): ")

    if ($response | str downcase) != "y" {
      print "❌ Cancelled"
      return
    }
  }

  # Remove provider
  remove-provider $provider_name $infra_path
}

# List installed providers for infrastructure
export def handle_providers_installed [args: list, flags: record] {
  if ($args | is-empty) {
    print "❌ Infrastructure name required"
    print "Usage: provisioning providers installed <infra> [--format <fmt>]"
    exit 1
  }

  let infra_name = $args | get 0

  # Parse format flag
  let format_idx = ($args | enumerate | where item == "--format" | get 0?.index | default (-1))
  let format = if $format_idx >= 0 and ($args | length) > ($format_idx + 1) {
    $args | get ($format_idx + 1)
  } else {
    "table"
  }

  # Resolve infrastructure path
  let infra_path = (resolve_infra_path $infra_name)

  if ($infra_path | is-empty) {
    print $"❌ Infrastructure not found: ($infra_name)"
    exit 1
  }

  let manifest_path = ($infra_path | path join "providers.manifest.yaml")

  if not ($manifest_path | path exists) {
    print $"❌ No providers.manifest.yaml found in ($infra_name)"
    exit 1
  }

  let manifest = (open $manifest_path)
  let providers = if ($manifest | get providers? | is-not-empty) {
    $manifest | get providers
  } else if ($manifest | get loaded_providers? | is-not-empty) {
    $manifest | get loaded_providers
  } else {
    []
  }

  print $"(_ansi blue_bold)📦 Installed providers for ($infra_name):(_ansi reset)"
  print ""

  match $format {
    "json" => {
      _print ($providers | to json) "json" "result" "table"
    }
    "yaml" => {
      _print ($providers | to yaml) "yaml" "result" "table"
    }
    _ => {
      _print ($providers | to json) "json" "result" "table"
    }
  }
}

# Validate provider installation
export def handle_providers_validate [args: list, flags: record] {
  use ../../lib_provisioning/module_loader.nu *

  if ($args | is-empty) {
    print "❌ Infrastructure name required"
    print "Usage: provisioning providers validate <infra> [--no-cache]"
    exit 1
  }

  let infra_name = $args | get 0
  let no_cache = ($args | any { |x| $x == "--no-cache" })

  print $"(_ansi blue_bold)🔍 Validating providers for ($infra_name)...(_ansi reset)"
  print ""

  # Resolve infrastructure path
  let infra_path = (resolve_infra_path $infra_name)

  if ($infra_path | is-empty) {
    print $"❌ Infrastructure not found: ($infra_name)"
    exit 1
  }

  mut validation_errors = []

  # Check manifest exists
  let manifest_path = ($infra_path | path join "providers.manifest.yaml")
  if not ($manifest_path | path exists) {
    $validation_errors = ($validation_errors | append "providers.manifest.yaml not found")
  } else {
    # Check each provider in manifest
    let manifest = (open $manifest_path)
    let providers = ($manifest | get providers? | default [])

    # Load providers once using cache
    let all_providers = if $no_cache {
      (discover-nickel-modules "providers")
    } else {
      (discover-nickel-modules-cached "providers")
    }

    for provider in $providers {
      print $"  Checking ($provider.name)..."

      # Check if provider exists in cached list
      let available = ($all_providers | where name == $provider.name)

      if ($available | is-empty) {
        $validation_errors = ($validation_errors | append $"Provider not found: ($provider.name)")
        print $"    ❌ Not found in extensions"
      } else {
        let provider_info = ($available | first)

        # Check if symlink exists
        let modules_dir = ($infra_path | path join ".nickel-modules")
        let link_path = ($modules_dir | path join $provider_info.module_name)

        if not ($link_path | path exists) {
          $validation_errors = ($validation_errors | append $"Symlink missing: ($link_path)")
          print $"    ❌ Symlink not found"
        } else {
          print $"    ✓ OK"
        }
      }
    }
  }

  # Check nickel.mod
  let nickel_mod_path = ($infra_path | path join "nickel.mod")
  if not ($nickel_mod_path | path exists) {
    $validation_errors = ($validation_errors | append "nickel.mod not found")
  }

  print ""

  # Report results
  if ($validation_errors | is-empty) {
    print "(_ansi green)✅ Validation passed - all providers correctly installed(_ansi reset)"
  } else {
    print "(_ansi red)❌ Validation failed:(_ansi reset)"
    for error in $validation_errors {
      print $"  • ($error)"
    }
    exit 1
  }
}

# Helper: Resolve infrastructure path
def resolve_infra_path [infra: string] {
  if ($infra | path exists) {
    return $infra
  }

  # Try workspace/infra path
  let workspace_path = $"workspace/infra/($infra)"
  if ($workspace_path | path exists) {
    return $workspace_path
  }

  # Try absolute workspace path
  let proj_root = ($env.PROVISIONING_ROOT? | default $env.HOME | path join "project-provisioning")
  let abs_workspace_path = ($proj_root | path join "workspace" "infra" $infra)
  if ($abs_workspace_path | path exists) {
    return $abs_workspace_path
  }

  return ""
}

# Show providers help
def show_providers_help [] {
  print $"
(_ansi cyan_bold)╔══════════════════════════════════════════════════╗(_ansi reset)
(_ansi cyan_bold)║(_ansi reset)  📦 PROVIDER MANAGEMENT                         (_ansi cyan_bold)║(_ansi reset)
(_ansi cyan_bold)╚══════════════════════════════════════════════════╝(_ansi reset)

(_ansi green_bold)[Available Providers](_ansi reset)
  (_ansi blue)provisioning providers list [--nickel] [--format <fmt>](_ansi reset)
    List all available providers
    Formats: table (default value), json, yaml

  (_ansi blue)provisioning providers info <provider> [--nickel](_ansi reset)
    Show detailed provider information with optional Nickel details

(_ansi green_bold)[Provider Installation](_ansi reset)
  (_ansi blue)provisioning providers install <provider> <infra> [--version <v>](_ansi reset)
    Install provider for an infrastructure
    Default version: 0.0.1

  (_ansi blue)provisioning providers remove <provider> <infra> [--force](_ansi reset)
    Remove provider from infrastructure
    --force skips confirmation prompt

  (_ansi blue)provisioning providers installed <infra> [--format <fmt>](_ansi reset)
    List installed providers for infrastructure
    Formats: table (default value), json, yaml

  (_ansi blue)provisioning providers validate <infra>(_ansi reset)
    Validate provider installation and configuration

(_ansi green_bold)EXAMPLES(_ansi reset)

  # List all providers
  provisioning providers list

  # Show Nickel module details
  provisioning providers info upcloud --nickel

  # Install provider
  provisioning providers install upcloud myinfra

  # List installed providers
  provisioning providers installed myinfra

  # Validate installation
  provisioning providers validate myinfra

  # Remove provider
  provisioning providers remove aws myinfra --force

(_ansi default_dimmed)💡 Use 'provisioning help providers' for more information(_ansi reset)
"
}

# Nu shell command handler
export def handle_nu [ops: string, flags: record] {
  let run_ops = if ($ops | str trim | str starts-with "-") {
    ""
  } else {
    let parts = ($ops | split row " ")
    if ($parts | is-empty) { "" } else { $parts | first }
  }

  if ($flags.infra | is-not-empty) and ($env.PROVISIONING_INFRA_PATH | path join $flags.infra | path exists) {
    cd ($env.PROVISIONING_INFRA_PATH | path join $flags.infra)
  }

  if ($flags.output_format | is-empty) {
    if ($run_ops | is-empty) {
      print (
        $"\nTo exit (_ansi purple_bold)NuShell(_ansi reset) session, with (_ansi default_dimmed)lib_provisioning(_ansi reset) loaded, " +
        $"use (_ansi green_bold)exit(_ansi reset) or (_ansi green_bold)[CTRL-D](_ansi reset)"
      )
      # Pass the provisioning configuration files to the Nu subprocess
      # This ensures the interactive session has the same config loaded as the calling environment
      let config_path = ($env.PROVISIONING_CONFIG? | default "")
      # Build library paths argument - needed for module resolution during parsing
      # Convert colon-separated string to -I flag arguments
      let lib_dirs = ($env.NU_LIB_DIRS? | default "")
      let lib_paths = if ($lib_dirs | is-not-empty) {
        ($lib_dirs | split row ":" | where { |x| ($x | is-not-empty) })
      } else {
        []
      }

      if ($config_path | is-not-empty) {
        # Pass config files AND library paths via -I flags for module resolution
        # Library paths are set via -I flags which enables module resolution during parsing phase
        if ($lib_paths | length) > 0 {
          # Construct command with -I flags for each library path
          let cmd = (mut cmd_parts = []; for path in $lib_paths { $cmd_parts = ($cmd_parts | append "-I" | append $path) }; $cmd_parts)
          # Start interactive Nushell with provisioning configuration loaded
          # The -i flag enables interactive mode (REPL) with full terminal features
          ^nu --config $"($config_path)/config.nu" --env-config $"($config_path)/env.nu" ...$cmd -i
        } else {
          ^nu --config $"($config_path)/config.nu" --env-config $"($config_path)/env.nu" -i
        }
      } else {
        # Fallback if PROVISIONING_CONFIG not set
        if ($lib_paths | length) > 0 {
          let cmd = (mut cmd_parts = []; for path in $lib_paths { $cmd_parts = ($cmd_parts | append "-I" | append $path) }; $cmd_parts)
          ^nu ...$cmd -i
        } else {
          ^nu -i
        }
      }
    } else {
      # Also pass library paths for single command execution
      let lib_dirs = ($env.NU_LIB_DIRS? | default "")
      let lib_paths = if ($lib_dirs | is-not-empty) {
        ($lib_dirs | split row ":" | where { |x| ($x | is-not-empty) })
      } else {
        []
      }

      if ($lib_paths | length) > 0 {
        let cmd = (mut cmd_parts = []; for path in $lib_paths { $cmd_parts = ($cmd_parts | append "-I" | append $path) }; $cmd_parts)
        ^nu ...$cmd -c $"($run_ops)"
      } else {
        ^nu -c $"($run_ops)"
      }
    }
  }
}

# List command handler
export def handle_list [ops: string, flags: record] {
  let target_list = if ($ops | is-not-empty) {
    let parts = ($ops | split row " ")
    if ($parts | is-empty) { "" } else { $parts | first }
  } else { "" }

  let list_ops = ($ops | str replace $"($target_list) " "" | str trim)
  on_list $target_list ($flags.onsel | default "") $list_ops
}

# QR code command handler
export def handle_qr [] {
  make_qr
}

# Nu info command handler
export def handle_nuinfo [] {
  print $"\n (_ansi yellow)Nu shell info(_ansi reset)"
  print (version)
}

# Plugins command handler
export def handle_plugins [ops: string, flags: record] {
  let subcommand = if ($ops | is-not-empty) {
    ($ops | split row " " | get 0)
  } else {
    "list"
  }

  let remaining_ops = if ($ops | is-not-empty) {
    ($ops | split row " " | skip 1 | str join " ")
  } else {
    ""
  }

  match $subcommand {
    "list" | "ls" => { handle_plugin_list $flags }
    "register" | "add" => { handle_plugin_register $remaining_ops $flags }
    "test" => { handle_plugin_test $remaining_ops $flags }
    "build" => { handle_plugin_build $remaining_ops $flags }
    "status" => { handle_plugin_status $flags }
    "help" => { show_plugin_help }
    _ => {
      print $"❌ Unknown plugin subcommand: ($subcommand)"
      print "Use 'provisioning plugin help' for available commands"
      exit 1
    }
  }
}

# List installed plugins with status
export def handle_plugin_list [flags: record] {
  use ../../lib_provisioning/plugins/mod.nu [list-plugins]

  print $"\n (_ansi cyan_bold)Installed Plugins(_ansi reset)\n"

  let plugins = (list-plugins)

  if ($plugins | length) > 0 {
    print ($plugins | table -e)
  } else {
    print "(_ansi yellow)No plugins found(_ansi reset)"
  }

  print $"\n(_ansi default_dimmed)💡 Use 'provisioning plugin register <name>' to register a plugin(_ansi reset)"
}

# Register plugin with Nushell
export def handle_plugin_register [ops: string, flags: record] {
  use ../../lib_provisioning/plugins/mod.nu [register-plugin]

  let plugin_name = if ($ops | is-not-empty) {
    ($ops | split row " " | get 0)
  } else {
    print $"(_ansi red)❌ Plugin name required(_ansi reset)"
    print $"Usage: provisioning plugin register <plugin_name>"
    exit 1
  }

  register-plugin $plugin_name
}

# Test plugin functionality
export def handle_plugin_test [ops: string, flags: record] {
  use ../../lib_provisioning/plugins/mod.nu [test-plugin]

  let plugin_name = if ($ops | is-not-empty) {
    ($ops | split row " " | get 0)
  } else {
    print $"(_ansi red)❌ Plugin name required(_ansi reset)"
    print $"Usage: provisioning plugin test <plugin_name>"
    print $"Valid plugins: auth, kms, tera, nickel"
    exit 1
  }

  test-plugin $plugin_name
}

# Build plugins from source
export def handle_plugin_build [ops: string, flags: record] {
  use ../../lib_provisioning/plugins/mod.nu [build-plugins]

  let plugin_name = if ($ops | is-not-empty) {
    ($ops | split row " " | get 0)
  } else {
    ""
  }

  if ($plugin_name | is-empty) {
    print $"\n(_ansi cyan)Building all plugins...(_ansi reset)"
    build-plugins
  } else {
    print $"\n(_ansi cyan)Building plugin: ($plugin_name)(_ansi reset)"
    build-plugins --plugin $plugin_name
  }
}

# Show plugin status
export def handle_plugin_status [flags: record] {
  use ../../lib_provisioning/plugins/mod.nu [plugin-build-info]
  use ../../lib_provisioning/plugins/auth.nu *
  use ../../lib_provisioning/plugins/kms.nu [plugin-kms-info]

  print $"\n(_ansi cyan_bold)Plugin Status(_ansi reset)\n"

  print $"(_ansi yellow_bold)Authentication Plugin:(_ansi reset)"
  let auth_status = (plugin-auth-status)
  print $"  Available: ($auth_status.plugin_available)"
  print $"  Enabled: ($auth_status.plugin_enabled)"
  print $"  Mode: ($auth_status.mode)"

  print $"\n(_ansi yellow_bold)KMS Plugin:(_ansi reset)"
  let kms_info = (plugin-kms-info)
  print $"  Available: ($kms_info.plugin_available)"
  print $"  Enabled: ($kms_info.plugin_enabled)"
  print $"  Backend: ($kms_info.default_backend)"
  print $"  Mode: ($kms_info.mode)"

  print $"\n(_ansi yellow_bold)Build Information:(_ansi reset)"
  let build_info = (plugin-build-info)
  if $build_info.exists {
    print $"  Source directory: ($build_info.plugins_dir)"
    print $"  Available sources: ($build_info.available_sources | length)"
  } else {
    print $"  Source directory: Not found"
  }
}

# Show plugin help
def show_plugin_help [] {
  print $"
(_ansi cyan_bold)╔══════════════════════════════════════════════════╗(_ansi reset)
(_ansi cyan_bold)║(_ansi reset)  🔌 PLUGIN MANAGEMENT                            (_ansi cyan_bold)║(_ansi reset)
(_ansi cyan_bold)╚══════════════════════════════════════════════════╝(_ansi reset)

(_ansi green_bold)[Plugin Operations](_ansi reset)
  (_ansi blue)plugin list(_ansi reset)              List all plugins with status
  (_ansi blue)plugin register <name>(_ansi reset)   Register plugin with Nushell
  (_ansi blue)plugin test <name>(_ansi reset)       Test plugin functionality
  (_ansi blue)plugin build [name](_ansi reset)      Build plugins from source
  (_ansi blue)plugin status(_ansi reset)            Show plugin status and info

(_ansi green_bold)[Available Plugins](_ansi reset)
  • (_ansi cyan)auth(_ansi reset) - JWT authentication with MFA support
  • (_ansi cyan)kms(_ansi reset) - Key Management Service integration
  • (_ansi cyan)tera(_ansi reset) - Template rendering engine
  • (_ansi cyan)nickel(_ansi reset) - Nickel configuration language

(_ansi green_bold)EXAMPLES(_ansi reset)

  # List all plugins
  provisioning plugin list

  # Register auth plugin
  provisioning plugin register nu_plugin_auth

  # Test KMS plugin
  provisioning plugin test kms

  # Build all plugins
  provisioning plugin build

  # Build specific plugin
  provisioning plugin build nu_plugin_auth

  # Show plugin status
  provisioning plugin status

(_ansi default_dimmed)💡 Plugins provide HTTP fallback when not registered
   Authentication and KMS work in both plugin and HTTP modes(_ansi reset)
"
}

# Guide command handler
export def handle_guide [ops: string, flags: record] {
  let guide_topic = if ($ops | is-not-empty) {
    ($ops | split row " " | get 0)
  } else {
    ""
  }

  # Define guide topics and their paths
  let guides = {
    "quickstart": "docs/guides/quickstart-cheatsheet.md",
    "from-scratch": "docs/guides/from-scratch.md",
    "scratch": "docs/guides/from-scratch.md",
    "start": "docs/guides/from-scratch.md",
    "deploy": "docs/guides/from-scratch.md",
    "list": "list_guides"
  }

  # Get docs directory
  let docs_dir = ($env.PROVISIONING_PATH | path join "docs" "guides")

  match $guide_topic {
    "" => {
      # Show guide list
      show_guide_list $docs_dir
    }

    "list" => {
      show_guide_list $docs_dir
    }

    _ => {
      # Try to find and display guide
      let guide_path = if ($guide_topic in ($guides | columns)) { $guides | get $guide_topic } else { null }

      if ($guide_path == null or $guide_path == "list_guides") {
        print $"(_ansi red)❌ Unknown guide:(_ansi reset) ($guide_topic)"
        print ""
        show_guide_list $docs_dir
        exit 1
      }

      let full_path = ($env.PROVISIONING_PATH | path join $guide_path)

      if not ($full_path | path exists) {
        print $"(_ansi red)❌ Guide file not found:(_ansi reset) ($full_path)"
        exit 1
      }

      # Display guide using best available viewer
      display_guide $full_path $guide_topic
    }
  }
}

# Display guide using best available markdown viewer
def display_guide [
  guide_path: path
  topic: string
] {
  print $"\n(_ansi cyan_bold)📖 Guide:(_ansi reset) ($topic)\n"

  # Check for viewers in order of preference: glow, bat, less, cat
  if (which glow | length) > 0 {
    ^glow $guide_path
  } else if (which bat | length) > 0 {
    ^bat --style=plain --paging=always $guide_path
  } else if (which less | length) > 0 {
    ^less $guide_path
  } else {
    open $guide_path
  }
}

# Show list of available guides
def show_guide_list [docs_dir: path] {
  print $"
(_ansi magenta_bold)╔══════════════════════════════════════════════════╗(_ansi reset)
(_ansi magenta_bold)║(_ansi reset)  📚 AVAILABLE GUIDES                             (_ansi magenta_bold)║(_ansi reset)
(_ansi magenta_bold)╚══════════════════════════════════════════════════╝(_ansi reset)

(_ansi green_bold)[Step-by-Step Guides](_ansi reset)

  (_ansi blue)provisioning guide from-scratch(_ansi reset)
    Complete deployment from zero to production
    (_ansi default_dimmed)Shortcuts: scratch, start, deploy(_ansi reset)

(_ansi green_bold)[Quick References](_ansi reset)

  (_ansi blue)provisioning guide quickstart(_ansi reset)
    Command shortcuts and quick reference
    (_ansi default_dimmed)Shortcuts: shortcuts, quick(_ansi reset)

(_ansi green_bold)USAGE(_ansi reset)

  # View guide
  provisioning guide <topic>

  # List all guides
  provisioning guide list
  provisioning howto        (_ansi default_dimmed)# shortcut(_ansi reset)

(_ansi green_bold)EXAMPLES(_ansi reset)

  # Complete deployment guide
  provisioning guide from-scratch

  # Quick command reference
  provisioning guide quickstart

(_ansi green_bold)VIEWING TIPS(_ansi reset)

  • (_ansi cyan)Best experience:(_ansi reset) Install glow for beautiful rendering
    (_ansi default_dimmed)brew install glow  # macOS(_ansi reset)

  • (_ansi cyan)Alternative:(_ansi reset) bat provides syntax highlighting
    (_ansi default_dimmed)brew install bat   # macOS(_ansi reset)

  • (_ansi cyan)Fallback:(_ansi reset) less/cat work on all systems

(_ansi default_dimmed)💡 All guides provide copy-paste ready commands
   Perfect for quick start and reference!(_ansi reset)
"
}
