#!/usr/bin/env nu
# Info: Prepare for kubernetes default installation
# Author: JesusPerezLorenzo
# Release: 1.0.2
# Date: 30-12-2023

use lib_provisioning/cmd/env.nu *
use lib_provisioning/cmd/lib.nu *

use lib_provisioning/utils/ui.nu *

print $"(_ansi green_bold)OS(_ansi reset) with ($env.PROVISIONING_VARS) "

let defs = load_defs

if $env.PROVISIONING_RESOURCES == null {
  print $"🛑 PROVISIONING_RESOURCES not found"
  exit 1
}
let resources_path = $env.PROVISIONING_RESOURCES
if not ($resources_path | path exists) {  ^mkdir -p $resources_path  }

#let WORK_PATH = ${WORK_PATH:-/tmp}
#[ ! -d "$WORK_PATH" ] && mkdir -p "$WORK_PATH"
#export LC_CTYPE=C.UTF-8
#export LANG=C.UTF-8

export def copy_certs [
  run_root: string
] {
  let provision_path = ($defs.taskserv.prov_etcd_path | default "" | str replace "~" $env.HOME)
  if $provision_path == "" {
    print $"🛑 prov_path not found taskserv definition"
    return false
  }
  let src = if ($defs.taskserv.prov_etcd_path | str starts-with "/" ) {
    $defs.taskserv.prov_etcd_path
  } else if ($defs.taskserv.prov_etcd_path | str starts-with "resources/" ) {
    ($env.PROVISIONING_SETTINGS_SRC_PATH | path join $defs.taskserv.prov_etcd_path)
  } else {
    ($env.PROVISIONING_SETTINGS_SRC_PATH | path join "resources" | path join $defs.taskserv.prov_etcd_path)
  }

  # Auto-fetch certs from running etcd nodes when the local etcdcerts/ dir is empty.
  # Derives workspace root and infra name from PROVISIONING_SETTINGS_SRC_PATH —
  # no dependency on /etc/hosts or SSH config.
  if not ($src | path join "ca.crt" | path exists) {
    print $"⚠ ($src)/ca.crt not found — fetching etcd certs from nodes..."
    let infra_path     = $env.PROVISIONING_SETTINGS_SRC_PATH
    let workspace_root = ($infra_path | path dirname | path dirname)
    let infra_name     = ($infra_path | path basename)
    let fetch_script   = ($workspace_root | path join "scripts" "fetch-etcd-certs.nu")
    if not ($fetch_script | path exists) {
      print $"🛑 fetch-etcd-certs.nu not found at ($fetch_script)"
      return false
    }
    let res = (do { ^nu $fetch_script $infra_name } | complete)
    if $res.exit_code != 0 {
      print $"🛑 fetch-etcd-certs failed:\n($res.stderr)"
      return false
    }
    print $res.stdout
    if not ($src | path join "ca.crt" | path exists) {
      print $"🛑 ca.crt still missing after fetch — aborting"
      return false
    }
  }
  let etcd_certs_path = ($defs.taskserv.etcd_certs_path | default "" | str replace "~" $env.HOME)
  if $etcd_certs_path == "" { print "Error etcd_certs_path not found" ; exit 1 }
  if not ($run_root | path join $etcd_certs_path | path exists) { ^mkdir -p ($run_root | path join $etcd_certs_path)  }
  let etcd_cluster_name = ($defs.taskserv.etcd_cluster_name  | default "")
  if $etcd_cluster_name == "" {
    print $"🛑 etcd_cluster_name not found in taskserv definition"
    return false
  }
  let raw_etcd_peer = ($defs.taskserv.etcd_peers | default "")
  let etcd_peer = if $raw_etcd_peer == "" or $raw_etcd_peer == "$hostname" {
    $defs.server.hostname
  } else {
    $raw_etcd_peer
  }
  for name in [ca $etcd_peer $etcd_cluster_name] {
    if not ($src | path join $"($name).key" | path exists) { continue }
    open ($src | path join $"($name).key") -r | from json |
    if (sops_cmd "is_sops" ($src | path join $"($name).key")) {
      let content = (sops_cmd "decrypt" ($src | path join $"($name).key") --error_exit)
      if $content != ""  { $content | save -f ($run_root | path join $etcd_certs_path | path join $"($name).key") }
    } else {
      cp ($src | path join $"($name).key") ($run_root | path join $etcd_certs_path | path join $"($name).key" )
    }
  }
  if ($run_root | path join $etcd_certs_path | path join $"($etcd_peer).key" | path exists ) {
    (cp ($run_root | path join $etcd_certs_path | path join $"($etcd_peer).key")
      ($run_root | path join $etcd_certs_path | path join "server.key"))
    (mv ($run_root | path join $etcd_certs_path | path join $"($etcd_peer).key")
      ($run_root | path join $etcd_certs_path | path join "peer.key"))
  }
  if ($src | path join "ca.crt" | path exists)  {
    cp ($src | path join "ca.crt") ($run_root | path join $etcd_certs_path | path join "ca.crt")
  }
  if ($src | path join $"($etcd_peer).crt" | path exists)  {
    cp ($src | path join $"($etcd_peer).crt") ($run_root | path join $etcd_certs_path | path join "server.crt")
    cp ($src | path join $"($etcd_peer).crt") ($run_root | path join $etcd_certs_path | path join "peer.crt")
  }
  if ($run_root | path join $etcd_certs_path | path join $"($etcd_cluster_name).key" | path exists)  {
    ( mv ($run_root | path join $etcd_certs_path | path join $"($etcd_cluster_name).key")
      ($run_root | path join $etcd_certs_path | path join "healthcheck-client.key"))
  }
  if ($src | path join $"($etcd_cluster_name).crt" | path exists)  {
    ( cp ($src | path join $"($etcd_cluster_name).crt")
      ($run_root | path join $etcd_certs_path | path join "healthcheck-client.crt"))
  }
  print $"ETCD Certs copied from ($src) to ($run_root | path join $etcd_certs_path)"
  true
}

def fetch_join_command [cp_host: string, cp_ip: string, run_root: string]: nothing -> bool {
  let ssh_key = ($env.PROVISIONING_SSH_KEY? | default "~/.ssh/htz_ops" | str replace "~" $env.HOME)
  let ssh_opts = if ($ssh_key | path exists) {
    ["-o" "StrictHostKeyChecking=accept-new" "-o" "ConnectTimeout=10" "-i" $ssh_key]
  } else {
    ["-o" "StrictHostKeyChecking=accept-new" "-o" "ConnectTimeout=10"]
  }
  let cache_path = ($env.HOME | path join ".cache" "provisioning" $"k8s-join-($cp_host).sh")
  let cache_valid = if ($cache_path | path exists) {
    let age_sec = ((date now) - (ls $cache_path | get 0.modified)) / 1sec
    $age_sec < 3600
  } else { false }
  let raw_join = if $cache_valid {
    print "✓ prepare: using cached join command (< 1h old)"
    open --raw $cache_path
  } else {
    let script = "export PATH=/usr/local/bin:/usr/bin:/bin
if command -v kubeadm >/dev/null 2>&1; then
  kubeadm token create --print-join-command 2>/dev/null
else
  echo 'ERROR: kubeadm not found' >&2; exit 1
fi"
    let res = (do -i { $script | ^ssh ...$ssh_opts $"root@($cp_host)" "bash -s" } | complete)
    if $res.exit_code != 0 or ($res.stdout | str trim | is-empty) {
      print $"🛑 prepare: failed to get join command from CP ($cp_host): ($res.stderr)"
      exit 1
    }
    let out = ($res.stdout | str trim)
    ^mkdir -p ($cache_path | path dirname)
    $out | save -f $cache_path
    $out
  }
  let join_cmd = if ($cp_ip | is-not-empty) {
    $raw_join | str replace "127.0.0.1" $cp_ip
  } else { $raw_join }
  #print $"join_cmd = ($join_cmd) "
  #$"#!/usr/bin/env bash\n($join_cmd) --ignore-preflight-errors=all\n" | save -f ($run_root | path join "k8s_join.sh")
  $"($join_cmd) --ignore-preflight-errors=all\n" | save -f ($run_root | path join "k8s_join.sh")
  ^chmod +x ($run_root | path join "k8s_join.sh")
  print $"✓ prepare: k8s_join.sh ready CP=($cp_host), endpoint=($cp_ip):6443"
  true
}

def main [] {
  let run_root = $env.PROVISIONING_WK_ENV_PATH
  let TEMPLATES_PATH = ($run_root | path join "templates")
  let server_hostname = ($defs.server.hostname | default "")
  let cp_name = ($defs.taskserv.cp_name | default "")
  let cp_ip   = ($defs.taskserv.cp_ip?   | default "" | str trim)
  let is_worker = ($cp_name | is-not-empty) and ($server_hostname != $cp_name)
  let K8S_TPL = ($defs.taskserv.tpl | default "" | str replace ".j2" "")
  let K8S_CONFIG = ($K8S_TPL | str replace ".j2" "")
  if not $is_worker and ($K8S_TPL | is-not-empty) {
    if not ($run_root | path join "resources" | path exists) { ^mkdir -p ($run_root | path join "resources") }
    if ($TEMPLATES_PATH | path join $K8S_TPL | path exists) {
      cp ($TEMPLATES_PATH | path join $K8S_TPL) ($run_root | path join "resources" | path join $K8S_CONFIG)
    } else if ($TEMPLATES_PATH | path join $"($K8S_TPL).j2" | path exists) {
      cp ($TEMPLATES_PATH | path join $"($K8S_TPL).j2") ($run_root | path join "resources" | path join $"($K8S_CONFIG).j2")
    }
  }
  let res = if not $is_worker and $defs.taskserv.etcd_mode == "external" {
    copy_certs $run_root
  } else if $is_worker {
    fetch_join_command $cp_name $cp_ip $run_root
  } else { true }
  rm -rf ($run_root | path join "templates")
  $res
}
