#!/usr/bin/env nu
# Info: Script to run Provisioning Module Management
# Author: JesusPerezLorenzo
# Release: 1.0.0
# Date: 29-09-2025

use std log

use lib_provisioning *
use env.nu *

# - > Help on Module
export def "main help" [
  --src: string = ""
  --notitles       # not titles
  --out: string    # Print Output format: json, yaml, text (default)
]: nothing -> nothing {
  if $notitles == null or not $notitles { show_titles }
  ^$"($env.PROVISIONING_NAME)" -mod module --help
  if ($out | is-not-empty) { $env.PROVISIONING_NO_TERMINAL = false }
  print (provisioning_options $src)
  if not $env.PROVISIONING_DEBUG { end_run "" }
}

# > Module Management - Discovery and loading with template support
def main [
  ...args: string  # Other options, use help to get info
  -v               # Show version
  -i               # Show Info
  --version (-V)   # Show version with title
  --info (-I)      # Show Info with title
  --about (-a)     # Show About
  --notitles       # Do not show banner titles
  --format: string = "table"  # Output format: table, json, yaml, names
  --layer: string = "workspace"  # Layer: workspace, infra, all
  --type: string = "taskservs"  # Module type: taskservs, providers, clusters
  --category: string = ""  # Filter by category
  --group: string = ""  # Filter by group
  --manifest: string = "providers.manifest.yaml"  # Manifest file name
  --kcl            # Show KCL module info
  --validate       # Validate after loading
  --template-type: string = "all"  # Template type: taskservs, providers, servers, clusters
  --from: string = ""  # Template to base on
  --dry-run        # Show what would be done
  --override-file: string = ""  # Override file path
  --modules: list<string> = []  # Modules list
  --template: string = ""  # Template name
  --provider: string = "upcloud"  # Default provider
  --overwrite      # Overwrite existing
  --force (-f)     # Force overwrite existing files
  --check (-c)     # Only check mode, no actual changes
  --yes (-y)       # Confirm task
  --debug (-x)     # Use Debug mode
  --xm             # Debug with PROVISIONING_METADATA
  --xld            # Log level with DEBUG PROVISIONING_LOG_LEVEL=debug
  --metadata       # Error with metadata (-xm)
  --helpinfo (-h)  # For more details use options "help" (no dashes)
  --out: string    # Print Output format: json, yaml, text (default)
]: nothing -> nothing {
  if ($out | is-not-empty) {
    $env.PROVISIONING_OUT = $out
    $env.PROVISIONING_NO_TERMINAL = true
  }
  # Set NO_TITLES to prevent double display when called from main provisioning
  $env.PROVISIONING_NO_TITLES = true
  provisioning_init $helpinfo "module" $args
  if $version or $v { ^$env.PROVISIONING_NAME -v ; exit }
  if $info or $i { ^$env.PROVISIONING_NAME -i ; exit }
  if $about {
    _print (get_about_info)
    exit
  }
  if $debug { $env.PROVISIONING_DEBUG = true }
  if $metadata { $env.PROVISIONING_METADATA = true }

  let task = if ($args | length) > 0 { ($args | get 0) } else { "" }
  let ops = if ($args | length) > 1 { ($args | skip 1 | str join " ") } else { "" }

  $env.PROVISIONING_MODULE = "module"

  match $task {
    "h" | "help" => {
      # Redirect to main categorized help system
      exec $"($env.PROVISIONING_NAME)" help development --notitles
    },
    "discover" => {
      let module_type = if ($ops | is-not-empty) and not ($ops | str starts-with "-") {
        ($ops | split row " " | get 0)
      } else {
        $type
      }
      let query = if ($ops | is-not-empty) and not ($ops | str starts-with "-") {
        let parts = ($ops | split row " ")
        if ($parts | length) > 1 { $parts | get 1 } else { "" }
      } else {
        ""
      }

      print $"🔍 Discovering ($module_type) modules..."

      let module_loader = ($env.PROVISIONING? | default "/usr/local/provisioning" | path join "core" "cli" "module-loader")

      mut cmd = [$module_loader "discover" $module_type]
      if ($query | is-not-empty) { $cmd = ($cmd | append $query) }
      if ($format | is-not-empty) { $cmd = ($cmd | append ["--format" $format]) }
      if ($category | is-not-empty) { $cmd = ($cmd | append ["--category" $category]) }
      if ($group | is-not-empty) { $cmd = ($cmd | append ["--group" $group]) }

      ^nu ...$cmd
    },
    "load" => {
      let parts = ($ops | split row " ")
      let module_type = if ($parts | length) > 0 and not (($parts | get 0) | str starts-with "-") {
        $parts | get 0
      } else {
        $type
      }
      let workspace = if ($parts | length) > 1 and not (($parts | get 1) | str starts-with "-") {
        $parts | get 1
      } else {
        "."
      }
      let module_names = if ($parts | length) > 2 {
        $parts | skip 2 | where { not ($in | str starts-with "-") }
      } else {
        $modules
      }

      if ($module_names | is-empty) {
        print "❌ No modules specified for loading"
        print "Use 'provisioning module help' for usage"
        exit 1
      }

      print $"📦 Loading ($module_names | length) ($module_type) into ($workspace) at layer ($layer)"

      let module_loader = ($env.PROVISIONING? | default "/usr/local/provisioning" | path join "core" "cli" "module-loader")

      mut cmd = [$module_loader "load" $module_type $workspace ...$module_names]
      if ($layer | is-not-empty) { $cmd = ($cmd | append ["--layer" $layer]) }
      if $validate { $cmd = ($cmd | append "--validate") }
      if $force { $cmd = ($cmd | append "--force") }

      ^nu ...$cmd
    },
    "list" => {
      let parts = ($ops | split row " ")
      let module_type = if ($parts | length) > 0 and not (($parts | get 0) | str starts-with "-") {
        $parts | get 0
      } else {
        $type
      }
      let workspace = if ($parts | length) > 1 and not (($parts | get 1) | str starts-with "-") {
        $parts | get 1
      } else {
        "."
      }

      print $"📋 Listing ($module_type) in ($workspace) for layer ($layer)"

      let module_loader = ($env.PROVISIONING? | default "/usr/local/provisioning" | path join "core" "cli" "module-loader")

      mut cmd = [$module_loader "list" $module_type $workspace]
      if ($layer | is-not-empty) { $cmd = ($cmd | append ["--layer" $layer]) }
      if ($format | is-not-empty) { $cmd = ($cmd | append ["--format" $format]) }

      ^nu ...$cmd
    },
    "unload" => {
      let parts = ($ops | split row " ")
      let module_type = if ($parts | length) > 0 and not (($parts | get 0) | str starts-with "-") {
        $parts | get 0
      } else {
        $type
      }
      let workspace = if ($parts | length) > 1 and not (($parts | get 1) | str starts-with "-") {
        $parts | get 1
      } else {
        "."
      }
      let module_name = if ($parts | length) > 2 and not (($parts | get 2) | str starts-with "-") {
        $parts | get 2
      } else {
        ""
      }

      if ($module_name | is-empty) {
        print "❌ No module specified for unloading"
        print "Use 'provisioning module help' for usage"
        exit 1
      }

      print $"🗑️  Unloading ($module_name) from ($workspace) at layer ($layer)"

      let module_loader = ($env.PROVISIONING? | default "/usr/local/provisioning" | path join "core" "cli" "module-loader")

      mut cmd = [$module_loader "unload" $module_type $workspace $module_name]
      if ($layer | is-not-empty) { $cmd = ($cmd | append ["--layer" $layer]) }

      ^nu ...$cmd
    },
    "sync-kcl" => {
      let infra = if ($ops | is-not-empty) and not ($ops | str starts-with "-") {
        ($ops | split row " " | get 0)
      } else {
        ""
      }

      if ($infra | is-empty) {
        print "❌ No infrastructure specified"
        print "Use 'provisioning module sync-kcl <infra>' to sync KCL dependencies"
        exit 1
      }

      print $"🔄 Syncing KCL dependencies for ($infra)"

      let module_loader = ($env.PROVISIONING? | default "/usr/local/provisioning" | path join "core" "cli" "module-loader")

      mut cmd = [$module_loader "sync-kcl" $infra]
      if ($manifest | is-not-empty) { $cmd = ($cmd | append ["--manifest" $manifest]) }
      if $kcl { $cmd = ($cmd | append "--kcl") }

      ^nu ...$cmd
    },
    "init" => {
      let workspace = if ($ops | is-not-empty) and not ($ops | str starts-with "-") {
        ($ops | split row " " | get 0)
      } else {
        "."
      }

      print $"🚀 Initializing workspace: ($workspace)"

      let module_loader = ($env.PROVISIONING? | default "/usr/local/provisioning" | path join "core" "cli" "module-loader")

      mut cmd = [$module_loader "init" $workspace]
      if not ($modules | is-empty) { $cmd = ($cmd | append ["--modules" ($modules | to json)]) }
      if ($template | is-not-empty) { $cmd = ($cmd | append ["--template" $template]) }
      if ($provider | is-not-empty) { $cmd = ($cmd | append ["--provider" $provider]) }

      ^nu ...$cmd
    },
    "validate" => {
      let workspace = if ($ops | is-not-empty) and not ($ops | str starts-with "-") {
        ($ops | split row " " | get 0)
      } else {
        "."
      }

      print $"🔍 Validating workspace: ($workspace)"

      let module_loader = ($env.PROVISIONING? | default "/usr/local/provisioning" | path join "core" "cli" "module-loader")

      ^nu $module_loader "validate" $workspace
    },
    "info" => {
      let workspace = if ($ops | is-not-empty) and not ($ops | str starts-with "-") {
        ($ops | split row " " | get 0)
      } else {
        "."
      }

      print $"📊 Workspace information: ($workspace)"

      let module_loader = ($env.PROVISIONING? | default "/usr/local/provisioning" | path join "core" "cli" "module-loader")

      ^nu $module_loader "info" $workspace
    },
    "template" => {
      let subcommand = if ($ops | is-not-empty) and not ($ops | str starts-with "-") {
        ($ops | split row " " | get 0)
      } else {
        ""
      }

      let module_loader = ($env.PROVISIONING? | default "/usr/local/provisioning" | path join "core" "cli" "module-loader")

      match $subcommand {
        "list" => {
          print $"📋 Listing templates (type: ($template_type))"

          mut cmd = [$module_loader "template" "list"]
          if ($template_type | is-not-empty) { $cmd = ($cmd | append ["--template-type" $template_type]) }
          if ($format | is-not-empty) { $cmd = ($cmd | append ["--format" $format]) }

          ^nu ...$cmd
        },
        "apply" => {
          let parts = ($ops | split row " " | skip 1)
          let template_name = if ($parts | length) > 0 { $parts | get 0 } else { "" }
          let target = if ($parts | length) > 1 { $parts | get 1 } else { "" }

          if ($template_name | is-empty) or ($target | is-empty) {
            print "❌ Missing template name or target"
            print "Use 'provisioning module template apply <template> <target>'"
            exit 1
          }

          if $dry_run {
            print $"🔍 [DRY RUN] Would apply template ($template_name) to ($target)"
          } else {
            print $"📥 Applying template ($template_name) to ($target)"
          }

          mut cmd = [$module_loader "template" "apply" $template_name $target]
          if ($override_file | is-not-empty) { $cmd = ($cmd | append ["--override-file" $override_file]) }
          if $dry_run { $cmd = ($cmd | append "--dry-run") }

          ^nu ...$cmd
        },
        _ => {
          print $"❌ Unknown template subcommand: ($subcommand)"
          print "Available: list, apply"
          exit 1
        }
      }
    },
    _ => {
      print $"❌ Unknown task: ($task)"
      print "Use 'provisioning module help' for available commands"
      print ""
      print "Available commands:"
      print "  discover <type> [query]              - Discover available modules"
      print "  load <type> <workspace> <modules...> - Load modules into workspace"
      print "  list <type> <workspace>              - List loaded modules"
      print "  unload <type> <workspace> <module>   - Unload module from workspace"
      print "  sync-kcl <infra>                     - Sync KCL dependencies"
      print "  init <workspace>                     - Initialize workspace with modules"
      print "  validate <workspace>                 - Validate workspace integrity"
      print "  info <workspace>                     - Show workspace information"
      print "  template list                        - List available templates"
      print "  template apply <name> <target>       - Apply template to target"
      exit 1
    }
  }
}
