
# Selective imports replacing `use ../lib_provisioning *` (ADR-025 Phase 4).
use lib_provisioning/ai/lib.nu [ai_process_query get_ai_config is_ai_enabled]
use lib_provisioning/utils/clean.nu [cleanup]
use lib_provisioning/utils/error.nu [throw-error]
use lib_provisioning/utils/format.nu [datalist_to_format]
use lib_provisioning/utils/help.nu [parse_help_command]
use lib_provisioning/utils/init.nu [get-provisioning-name]
use lib_provisioning/utils/interface.nu [_ansi _print end_run]
use lib_provisioning/utils/settings.nu [load load_settings]

# 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)
] {
  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 }

  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)
    }
  }

  if ($curr_settings | is-empty) or ($curr_settings == null) {
    print "🛑 Failed to load infrastructure settings"
    if ($infra | is-not-empty) { print $"  Infra path: ($infra)" }
    if ($settings | is-not-empty) { print $"  Settings file: ($settings)" }
    exit 1
  }

  let cmd_target = if ($target | is-empty )  {
    if ($args | is-empty) { "" } else { $args | first }
  } else { $target }
  let str_out = if $out == null { "" } else { $out }
  let str_cols = if $cols == null { "" } else { $cols }
  let str_find = if $find == null { "" } else { $find }

  match $cmd_target {
    "server" | "servers" => {
      _print (datalist_to_format $str_out
        (mw_query_servers $curr_settings $str_find $str_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)
        $list_cols
        $str_out
        $ips
      )
    },
    "servers-def" | "server-def" => {
      let data = if $str_find != "" { ($curr_settings.data.servers | find $str_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 $str_find) } else { $curr_settings.data}
      (out_data_query_info
        $curr_settings
        [ $data ]
        $str_cols
        $str_out
        false
      )
    }
    _ => {
      (throw-error $"🛑 ((get-provisioning-name)) query " $"Invalid option (_ansi red)($cmd_target)(_ansi reset)"
         $"((get-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
] {
  if ($data | is-empty) or (($data | first | default null) == null) {
    if $env.PROVISIONING_DEBUG { print $"🛑 ((get-provisioning-name)) query (_ansi red)no data found(_ansi reset)" }
    _print ""
    return
  }
  let sel_data = if ($cols | is-not-empty) {
    let col_list = ($cols | split row ",")
    $data | select ...$col_list
  } else {
    $data
  }
  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
  }
}
