#!/usr/bin/env nu
# Info: Script to run Provisioning
# Author: JesusPerezLorenzo
# Release: 1.0.4
# Date: 6-2-2024

#use std  # assert
use std log

# Detect project root and set up module paths early
# This ensures NU_LIB_DIRS is properly configured before loading modules
export-env {
    # Project root detection: look for kcl.mod or provisioning structure
    let potential_roots = [
        $env.PWD
        ($env.PWD | path dirname)
        ($env.PWD | path dirname | path dirname)
    ]

    let matching_roots = ($potential_roots
        | where ($it | path join "kcl.mod" | path exists)
            or ($it | path join "core" "nulib" | path exists))

    let project_root = if ($matching_roots | length) > 0 {
        $matching_roots | first
    } else {
        $env.PWD
    }

    # Update PWD in NU_LIB_DIRS to use detected project root
    if ($env.NU_LIB_DIRS? | default [] | any {|path| $path == $env.PWD}) {
        $env.NU_LIB_DIRS = ($env.NU_LIB_DIRS | each {|path|
            if $path == $env.PWD { $project_root } else { $path }
        })
    }

    # Add project-local env if it exists - will be loaded after main env.nu
}

use lib_provisioning *
use env.nu *

#Load all main defs
use main_provisioning *

#module srv { use instances.nu * }

use servers/ssh.nu *
use servers/utils.nu *
use taskservs/utils.nu find_taskserv
# Help on provisioning commands
export def "main help" [
  category?: string  # Optional category: infrastructure, orchestration, development, workspace, concepts
  --notitles       # not titles
  --out: string    # Print Output format: json, yaml, text (default)
] {
  if $notitles == null or not $notitles { show_titles }
  if ($out | is-not-empty) { $env.PROVISIONING_NO_TERMINAL = false }
  print (provisioning_options $category)
  if not $env.PROVISIONING_DEBUG { end_run "" }
}

def main [
  ...args: string  # Other options, use help to get info
  --infra (-i): string     # Cloud directory
  --settings (-s): string # Settings path
  --serverpos (-p): int   # Server position in settings
  --outfile (-o): string  # Output file
  --template(-t): string  # Template path or name in PROVISION_KLOUDS_PATH
  --check (-c)     # Only check mode no servers will be created
  --yes (-y)       # confirm task
  --wait (-w)      # Wait servers to be created
  --keepstorage    # keep storage
  --select: string # Select with task as option
  --onsel: string  # On selection: e (edit) | v (view) | l (list) | t (tree)
  --infras: string # Infra list names separated by commas
  --new (-n): string    # New infrastructure name
  --debug (-x)     # Use Debug mode
  --xm             # Debug with PROVISIONING_METADATA
  --xc             # Debug for task and services locally PROVISIONING_DEBUG_CHECK
  --xr             # Debug for remote servers PROVISIONING_DEBUG_REMOTE
  --xld            # Log level with DEBUG PROVISIONING_LOG_LEVEL=debug
  --nc             # Not clean working settings
  --metadata       # Error with metadata (-xm)
  --notitles       # not tittles
  --environment: string    # Environment override (dev/test/prod)
  --dep-option: string     # Workspace dependency option: workspace-home, home-package, git-package, publish-repo
  --dep-url: string        # Dependency URL for git-package or publish-repo
  --dry-run                # Show what would be done without doing it (pack command)
  --force (-f)             # Skip confirmation prompts (pack/delete commands)
  --all                    # Process all items (pack clean command)
  --keep-latest: int       # Keep N latest versions (pack clean command)
  --activate (-a)          # Activate workspace as default (workspace commands)
  --interactive (-I)       # Interactive workspace creation wizard
  -v               # Show version
  --version (-V)   # Show version with title
  --info (-I)      # Show Info  with title
  --about (-a)     # Show About
  --helpinfo (-h)  # For more details use options "help" (no dashes)
  --out: string    # Print Output format: json, yaml, text (default)
  --view           # Print with highlight
  --inputfile: string  # Input format: json, yaml, text (default)
  --include_notuse # Include servers not use
]: nothing -> nothing {
  # Initialize provisioning system
  provisioning_init $helpinfo "" $args

  # Parse all flags into normalized structure
  let parsed_flags = (parse_common_flags {
    version: $version, v: $v, info: $info, about: $about,
    debug: $debug, metadata: $metadata, xc: $xc, xr: $xr, xld: $xld,
    check: $check, yes: $yes, wait: $wait, keepstorage: $keepstorage,
    nc: $nc, include_notuse: $include_notuse,
    out: $out, notitles: $notitles, view: $view,
    infra: $infra, infras: $infras, settings: $settings, outfile: $outfile,
    template: $template, select: $select, onsel: $onsel, serverpos: $serverpos,
    new: $new, environment: $environment,
    dep_option: $dep_option, dep_url: $dep_url,
    dry_run: $dry_run, force: $force, all: $all, keep_latest: $keep_latest,
    activate: $activate, interactive: $interactive
  })

  # Handle version, info, about flags
  if $parsed_flags.show_version { ^$env.PROVISIONING_NAME -v ; exit }
  if $parsed_flags.show_info { ^$env.PROVISIONING_NAME -i ; exit }
  if $parsed_flags.show_about { _print (get_about_info) ; exit }

  # Dispatch command to appropriate handler
  dispatch_command $args $parsed_flags

  # End run if not in debug mode
  if not ($env.PROVISIONING_DEBUG? | default false) { end_run "" }
}

export def get_show_info [
  ops: list
  curr_settings: record
  out: string
]: nothing -> record  {
  match ($ops | get -o 0 | default "") {
    "set" |"setting" | "settings" => $curr_settings,
    "def" | "defs" |"defsetting" | "defsettings" => {
      let src = ($curr_settings | get -o src | default "");
      let src_path = ($curr_settings | get -o src_path | default "");
      let def_settings = if ($src_path | path join $src | path exists) {
        open -r ($src_path | path join $src)
      } else { "" }
      let main_path = ($env.PROVISIONING | path join "kcl" | path join "settings.k")
      let src_main_settings = if ($main_path | path exists) {
        open -r $main_path
      } else { "" }
      {
        def: $src,
        def_path: $src_path,
        infra: ($curr_settings | get -o infra | default ""),
        infra_path: ($curr_settings | get -o infra_path | default ""),
        def_settings: $def_settings,
        main_path: $main_path,
        main_settings: $src_main_settings,
      }
    },
    "server" |"servers" | "s" => {
      let servers = ($curr_settings | get -o data | get -o servers |  default {})
      let item = ($ops | get -o 1 | default "")
      if ($item | is-empty) {
        $servers
      } else {
        let server = (find_server $item $servers ($out | default ""))
        let def_target = ($ops | get -o 2 | default "")
        match $def_target {
          "t" | "task" | "taskserv" => {
            let task = ($ops | get -o 3 | default "")
            (find_taskserv $curr_settings $server $task ($out | default ""))
          },
          _ => $server,
        }
      }
    },
    "serverdefs" |"serversdefs" | "sd" => {
      (find_serversdefs $curr_settings)
    },
    "provgendefs" |"provgendef" | "pgd" => {
      (find_provgendefs)
    },
    "taskservs" |"taskservs" | "ts" => {
      #(list_taskservs $curr_settings)
      let list_taskservs = (taskservs_list)
      if ($list_taskservs | length) == 0 {
          _print $"🛑 no items found for (_ansi cyan)taskservs list(_ansi reset)"
          return
      }
      $list_taskservs
    },
    "taskservsgendefs" |"taskservsgendef" | "tsd" => {
      let defs_path = ($env.PROVISIONING_TASKSERVS_PATH | path join $env.PROVISIONING_GENERATE_DIRPATH | path join $env.PROVISIONING_GENERATE_DEFSFILE)
      if ($defs_path | path exists) {
        open $defs_path
      }
    },
    "cost" | "costs" | "c" | "price" | "prices" | "p" => {
      (servers_walk_by_costs $curr_settings "" false false "stdout")
    },
    "alldata" => ($curr_settings | get -o data | default {}
       | merge { costs: (servers_walk_by_costs $curr_settings "" false false "stdout") }
    ),
    "data" | _ => {
      if ($out | is-not-empty) {
        ($curr_settings | get -o data | default {})
      } else {
          print ($" (_ansi cyan_bold)($curr_settings | get -o data | get -o main_name | default '')"
            + $"(_ansi reset): (_ansi yellow_bold)($curr_settings | get -o data | get -o main_title | default '') (_ansi reset)"
          )
          print ($curr_settings | get -o data | default {} | merge { servers: ''})
          ($curr_settings | get -o data | default {} | get -o servers | each {|item|
              print $"\n server:  (_ansi cyan_bold)($item.hostname | default '') (_ansi reset)"
              print $item
          })
          ""
      }
    },
  }
}
