
#use utils * 
#use defs * 
use lib_provisioning *

# - > Query  infrastructure and services
export def "main query" [
  #hostname?: string      # Server hostname in settings
  ...args                 # Args for create command 
  --infra (-i): string    # Infra path 
  --settings (-s): string # Settings path 
  --serverpos (-p): int   # Server position in settings 
  --check (-c)            # Only check mode no servers will be created 
  --wait (-w)             # Wait servers to be created 
  --outfile: string      # Optional output format: json | yaml | csv | text | md | nuon 
  --find (-f): string     # Optional query find a value (empty if no value found)
  --cols (-l): string     # Optional query columns list separated with comma 
  --target(-t): string    # Target element for query: servers-status | servers | servers-info | servers-def | defs 
  --ips                   # Optional query get IPS only for target "servers-info" 
  --prov: string          # Optional provider name to filter query
  --ai_query: string      # Natural language query using AI
  --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
  --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
  }
  # Handle AI query first if provided
  if ($ai_query | is-not-empty) {
    use ../lib_provisioning/ai/lib.nu *
    if (is_ai_enabled) and (get_ai_config).enable_query_ai {
      # Get current infrastructure context for AI
      let curr_settings = if $infra != null { 
        if $settings != null { 
          (load_settings --infra $infra --settings $settings)
        } else {  
          (load_settings --infra $infra)
        }
      } else {
        if $settings != null { 
          (load_settings --settings $settings)
        } else {  
          (load_settings)
        }
      }
      
      let context = {
        infra: ($infra | default "")
        provider: ($prov | default "")
        available_targets: ["servers", "servers-status", "servers-info", "servers-def", "defs"]
        output_format: ($out | default "text")
      }
      
      let ai_response = (ai_process_query $ai_query $context)
      print $ai_response
      return
    } else {
      print "AI query processing is disabled or not configured"
      return
    }
  }

  parse_help_command "query" --end
  if $debug { $env.PROVISIONING_DEBUG = true } 
  #use defs [ load_settings ]
  let curr_settings = if $infra != null { 
    if $settings != null { 
      (load_settings --infra $infra --settings $settings)
    } else {  
      (load_settings --infra $infra)
    }
  } else {
    if $settings != null { 
      (load_settings --settings $settings)
    } else {  
      (load_settings)
    }
  }
  let cmd_target = if ($target | is-empty )  { 
    ($args | get -o 0 | default "")
  } else { $target }
  #let str_out = if $outfile == null { "none" } else { $outfile }
  let str_out = if $out == null { "" } else { $out }
  let str_cols = if $cols == null { "" } else { $cols }
  let str_find = if $find == null { "" } else { $find }
  #use lib_provisioning * 
  match $cmd_target {
    "server" | "servers" => { 
      #use utils/format.nu datalist_to_format
      _print (datalist_to_format $str_out 
        (mw_query_servers $curr_settings $str_find $cols --prov $prov --serverpos $serverpos)
      )
    },
    "server-status" | "servers-status" |  "server-info" | "servers-info" => { 
      let list_cols = if ($cmd_target | str contains "status") {
        if ($str_cols | str contains "state") { $str_cols } else { $str_cols + ",state" }
      } else {
        $str_cols
      }
      # not use $str_cols to filter previous $ips selection  
      (out_data_query_info
        $curr_settings
        (mw_servers_info $curr_settings $str_find --prov $prov --serverpos $serverpos)
        #(mw_servers_info $curr_settings $find $cols --prov $prov --serverpos $serverpos)
        $list_cols
        $str_out
        $ips 
      )
    },
    "servers-def" | "server-def" => {
      let data = if $str_find != "" { ($curr_settings.data.servers | find $find) } else { $curr_settings.data.servers}
      (out_data_query_info
        $curr_settings
        $data
        $str_cols
        $str_out
        false
      )
    },
    "def" | "defs" => {
      let data = if $str_find != "" { ($curr_settings.data | find $find) } else { $curr_settings.data}
      (out_data_query_info
        $curr_settings
        [ $data ]
        $str_cols
        $str_out
        false
      )
    }
    _ => {
      (throw-error $"🛑 ($env.PROVISIONING_NAME) query " $"Invalid option (_ansi red)($cmd_target)(_ansi reset)"
         $"($env.PROVISIONING_NAME) query --target ($cmd_target)" --span (metadata $cmd_target).span
      )
    }
  }
  cleanup $curr_settings.wk_path
  if $outfile == null { end_run "query" }
}
def out_data_query_info [
  settings: record
  data: list
  cols: string
  outfile:  string
  ips: bool
]: nothing -> nothing {
  if ($data | get -o 0 | is-empty) {
    if $env.PROVISIONING_DEBUG { print $"🛑 ($env.PROVISIONING_NAME) query (_ansi red)no data found(_ansi reset)" } 
    _print ""
    return 
  }
  let sel_data = if ($cols | is-not-empty) { 
    $data | select -o ($cols | split row ",")
  } else {
    $data
  }
  #use (prov-middleware) mw_servers_ips
  #use utils/format.nu datalist_to_format
  print (datalist_to_format $outfile $sel_data)
  # let data_ips = (($data).ip_addresses? | flatten | find "public")
  if $ips { 
    let ips_result = (mw_servers_ips $settings $data) 
    print $ips_result
  }
}
