use lib_provisioning *
use utils.nu *
use ssh.nu *
# Provider middleware now available through lib_provisioning

# > Servers state
export def "main state" [
  new_state?: string  # Server new state
  name?: string       # Server hostname in settings
  ...args                 # Args for create command
  --infra (-i): string     # Infra directory
  --settings (-s): string # Settings path
  --outfile (-o): string  # Output file
  --serverpos (-p): int   # Server position in settings
  --check (-c)     # Only check mode no servers will be created
  --wait (-w)      # Wait servers to be created
  --select: string # Select with task as option
  --debug (-x)     # Use Debug mode
  --xm             # Debug with PROVISIONING_METADATA
  --xc             # Debuc 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
  --metadata       # Error with metadata (-xm)
  --notitles       # not tittles
  --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
    }
    provisioning_init $helpinfo "servers state" $args
    if $debug { $env.PROVISIONING_DEBUG = true }
    if $metadata { $env.PROVISIONING_METADATA = true }
    if ($new_state | is-empty) {
        (throw-error $"🛑 no new state found " $"for servers "
        "in main state" --span (metadata $serverpos).span)
        exit 0
    }
    let task = if ($args | length) > 0 {
        ($args| get 0)
    } else {
        let str_task = (($env.PROVISIONING_ARGS? | default "") | str replace "create " " " )
        let str_task = if  $name != null {
           ($str_task | str replace $name "")
        } else {
            $str_task
        }
        ($str_task | str trim | split row " " | get -o 0 | default "" |
            split row "-" | get -o 0 | default  "" | str trim )
    }
    let other = if ($args | length) > 0 { ($args| skip 1) } else { "" }
    let ops = $"($env.PROVISIONING_ARGS? | default "") " | str replace $" ($task) " "" | str trim

    match $task {
        "" if $name == "h" => {
            ^$"($env.PROVISIONING_NAME)" -mod server create help --notitles
            exit 0
        },
        "" if $name == "help" => {
            ^$"($env.PROVISIONING_NAME)" -mod server create --help
            _print (provisioning_options "create")
        },
        "state" => {
            let the_new_state = if $new_state == "restart" or $new_state == "rs" {
                "restart"
            } else { $new_state }
            let run_state = {
                let curr_settings = (find_get_settings --infra $infra --settings $settings)
                $env.WK_CNPROV = $curr_settings.wk_path
                let match_name = if $name == null or $name == "" { "" } else { $name}
                on_state_servers $curr_settings $the_new_state $wait $match_name $serverpos
            }
            let result = desktop_run_notify $"($env.PROVISIONING_NAME) servers state to ($new_state)" "-> " $run_state --timeout 11sec
        },
        _ => {
          invalid_task "servers status" $"($task) ($name)" --end
        }
    }
    # "" | "create"
    if not $notitles and not $env.PROVISIONING_DEBUG { end_run "" }
}
export def on_state_servers [
  settings: record   # Settings record
  new_state: string
  wait: bool         # Wait for creation
  hostname?: string  # Server hostname in settings
  serverpos?: int    # Server position in settings
  --notitles       # not tittles
]: nothing -> list {
    let match_hostname = if $hostname != null {
        $hostname
    } else if $serverpos != null  {
        let total = $settings.data.servers | length
        let pos = if $serverpos == -1 {
            _print $"Use number form 0 to ($total)"
            $serverpos
        } else if $serverpos <= $total {
            $serverpos - 0
        } else {
            (throw-error $"🛑 server pos" $"($serverpos) from ($total) servers"
              "on_state" --span (metadata $serverpos).span)
            exit 0
        }
        ($settings.data.servers | get $pos).hostname
    }
    #use ../../../providers/prov_lib/middleware.nu  mw_server_state
    $settings.data.servers | enumerate | par-each { |it|
        if $match_hostname == null or $match_hostname == "" or $it.item.hostname == $match_hostname  {
            (mw_server_state $it.item $new_state true $wait $settings)
            if $new_state != "stop" and $wait {
                let ip = (mw_get_ip $settings $it.item $it.item.liveness_ip false )
                _print $it.item.liveness_ip
                if ($ip | is-not-empty) {
                    _print $"liveness (_ansi purple)($ip):($it.item.liveness_port)(_ansi reset)"
                    if (wait_for_server $it.index $it.item $settings $ip) {
                        _print $"✅ server (_ansi blue)($it.item.hostname)(_ansi reset) (_ansi green_bold)completed(_ansi reset)"
                    }
                }
            }
            _print $"\n(_ansi blue_reverse)----🌥 ----🌥 ----🌥 ---- oOo ----🌥 ----🌥 ----🌥 ---- (_ansi reset)\n"
        }
    }
}
