#!/usr/bin/env nu
# lian_build catalog CLI — ephemeral build runner management via hcloud.
# Entry: prvng runners <list|status|kill|gc> [name]

export-env {
    let lib_dirs_raw = ($env.NU_LIB_DIRS? | default "")
    let current_lib_dirs = if ($lib_dirs_raw | describe) == "string" {
        if ($lib_dirs_raw | is-empty) { [] } else { ($lib_dirs_raw | split row ":") }
    } else { $lib_dirs_raw }
    let dynamic = ($env.PROVISIONING? | default "" | path join "core" "nulib")
    $env.NU_LIB_DIRS = ([
        "/opt/provisioning/core/nulib"
        "/usr/local/provisioning/core/nulib"
    ] | append $current_lib_dirs
      | append (if ($dynamic | is-not-empty) { [$dynamic] } else { [] }))
}

use cli/flags.nu [parse_common_flags]

def hcloud-servers []: nothing -> list<record> {
    let r = (do { ^hcloud server list --output json } | complete)
    if $r.exit_code != 0 {
        error make { msg: $"hcloud server list failed: ($r.stderr | str trim)" }
    }
    $r.stdout | from json
}

def format-server [s: record]: nothing -> record {
    let priv = ($s.private_net | get 0? | default {} | get ip? | default "—")
    {
        name:       $s.name
        status:     $s.status
        public_ip:  $s.public_net.ipv4.ip
        private_ip: $priv
        type:       $s.server_type.name
        location:   $s.datacenter.location.name
        age:        $s.created
    }
}

def runners-list []: nothing -> nothing {
    let servers = (hcloud-servers)
    let runners = ($servers | where { |s| ($s.name | str starts-with "runner-") or ($s.name | str starts-with "buildkit-runner-") })
    if ($runners | is-empty) {
        print "no active runners"
        return
    }
    $runners | each { |s| format-server $s } | table
}

def runners-status [name: string]: nothing -> nothing {
    if ($name | is-empty) {
        error make { msg: "runners status requires a server name" }
    }
    let r = (do { ^hcloud server describe $name --output json } | complete)
    if $r.exit_code != 0 {
        error make { msg: $"hcloud server describe failed: ($r.stderr | str trim)" }
    }
    $r.stdout | from json | table
}

def runners-kill [name: string, confirmed: bool]: nothing -> nothing {
    if ($name | is-empty) {
        error make { msg: "runners kill requires a server name" }
    }
    if not $confirmed {
        let answer = (input $"Delete runner '($name)'? [y/N]: " | str downcase | str trim)
        if $answer != "y" { print "aborted"; return }
    }
    let r = (do { ^hcloud server delete $name } | complete)
    if $r.exit_code != 0 {
        error make { msg: $"hcloud server delete failed: ($r.stderr | str trim)" }
    }
    print $"deleted ($name)"
}

def runners-gc [confirmed: bool]: nothing -> nothing {
    let servers = (hcloud-servers)
    let orphans = ($servers
        | where { |s|
            (($s.name | str starts-with "runner-") or ($s.name | str starts-with "buildkit-runner-"))
            and $s.status != "running"
        })
    if ($orphans | is-empty) {
        print "no stopped/errored runners to collect"
        return
    }
    print $"Found ($orphans | length) orphaned runner(s):"
    $orphans | each { |s| format-server $s } | table
    if not $confirmed {
        let answer = (input "Delete all? [y/N]: " | str downcase | str trim)
        if $answer != "y" { print "aborted"; return }
    }
    $orphans | each { |s|
        let r = (do { ^hcloud server delete $s.name } | complete)
        if $r.exit_code == 0 {
            print $"deleted ($s.name)"
        } else {
            print $"error deleting ($s.name): ($r.stderr | str trim)"
        }
    }
}

def runners-help []: nothing -> nothing {
    print "Usage: prvng runners <command> [name]"
    print ""
    print "Commands:"
    print "  list              List all active build runners"
    print "  status <name>     Show runner details"
    print "  kill <name>       Delete a runner"
    print "  gc                Delete all stopped/errored runners"
}

def main [
    command: string = ""
    ...rest: string
    --yes (-y)
    --debug (-x)
    --notitles
]: nothing -> nothing {
    if $debug { $env.PROVISIONING_DEBUG = true }
    let name = ($rest | get 0? | default "")
    let flags = (parse_common_flags { yes: $yes, debug: $debug, notitles: $notitles })
    let confirmed = ($flags.auto_confirm? | default false)
    match $command {
        "list" | "l" | ""  => { runners-list }
        "status" | "s"     => { runners-status $name }
        "kill" | "k" | "d" => { runners-kill $name $confirmed }
        "gc"               => { runners-gc $confirmed }
        _                  => { runners-help }
    }
}
