#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)"
source "$SCRIPT_DIR/vm-common.sh"

CMD_NAME="${VM_CTL_CMD_NAME:-fireclaw}"

usage() {
  cat <<EOF
Usage: $CMD_NAME <command> [instance]

Commands:
  list
  status [id]
  start <id>
  stop <id>
  restart <id>
  logs <id> [guest|host]
  shell <id> [command...]
  token <id>
  destroy <id> [--force]
EOF
}

ssh_run() {
  local ip="$1"; shift
  local key="${SSH_KEY_PATH:-$HOME/.ssh/vmdemo_vm}"
  ssh -i "$key" -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=/dev/null "ubuntu@$ip" "$@"
}

_color() {
  local val="$1"
  local green=$'\033[32m' red=$'\033[31m' yellow=$'\033[33m' reset=$'\033[0m'
  case "$val" in
    active|up)       printf '%s%s%s' "$green"  "$val" "$reset" ;;
    inactive|down)   printf '%s%s%s' "$red"    "$val" "$reset" ;;
    failed)          printf '%s%s%s' "$red"    "$val" "$reset" ;;
    *)               printf '%s%s%s' "$yellow" "$val" "$reset" ;;
  esac
}

_print_status_table() {
  local -a ids=() ips=() ports=() vms=() proxies=() healths=()
  local id ip port vm proxy health

  while IFS='|' read -r id ip port vm proxy health; do
    ids+=("$id"); ips+=("$ip"); ports+=("$port")
    vms+=("$vm"); proxies+=("$proxy"); healths+=("$health")
  done

  [[ ${#ids[@]} -gt 0 ]] || { echo "(no instances)"; return; }

  local hdr=$'\033[1;37m' reset=$'\033[0m' dim=$'\033[2m'
  printf "${hdr}%-14s %-14s %-7s %-10s %-10s %-8s${reset}\n" \
    "INSTANCE" "IP" "PORT" "VM" "PROXY" "HEALTH"
  printf "${dim}%-14s %-14s %-7s %-10s %-10s %-8s${reset}\n" \
    "--------" "----------" "-----" "------" "-------" "------"

  for i in "${!ids[@]}"; do
    printf "%-14s %-14s %-7s %-10b %-10b %-8b\n" \
      "${ids[$i]}" "${ips[$i]}" "${ports[$i]}" \
      "$(_color "${vms[$i]}")" "$(_color "${proxies[$i]}")" "$(_color "${healths[$i]}")"
  done
}

cmd_list() {
  shopt -s nullglob
  local rows=()
  for d in "$STATE_ROOT"/.vm-*/; do
    local id
    id="$(basename "$d" | sed 's/^\.vm-//')"
    if [[ ! "$id" =~ ^[a-z0-9_-]+$ ]]; then
      warn "Skipping invalid instance state directory: $d"
      continue
    fi
    load_instance_env "$id"
    local ssh_key="${SSH_KEY_PATH:-$HOME/.ssh/vmdemo_vm}"
    local health="down"
    local host_health="down"
    local guest_health="down"
    curl -fsS "http://127.0.0.1:$HOST_PORT/health" >/dev/null 2>&1 && host_health="up"
    if check_guest_health "$id" "$VM_IP" "$ssh_key"; then
      guest_health="up"
    fi
    if [[ "$host_health" == "up" || "$guest_health" == "up" ]]; then
      health="up"
    fi
    local vm_state proxy_state
    vm_state="$(systemctl is-active "$(vm_service "$id")" 2>/dev/null)" || vm_state="inactive"
    proxy_state="$(systemctl is-active "$(proxy_service "$id")" 2>/dev/null)" || proxy_state="inactive"
    rows+=("${id}|${VM_IP}|${HOST_PORT}|${vm_state}|${proxy_state}|${health}")
  done
  shopt -u nullglob
  printf '%s\n' "${rows[@]}" | _print_status_table
}

cmd_status_one() {
  local id="$1"
  validate_instance_id "$id"
  load_instance_env "$id"
  local ssh_key="${SSH_KEY_PATH:-$HOME/.ssh/vmdemo_vm}"
  local vm_state proxy_state health host_health guest_health guest
  vm_state="$(systemctl is-active "$(vm_service "$id")" 2>/dev/null)" || vm_state="inactive"
  proxy_state="$(systemctl is-active "$(proxy_service "$id")" 2>/dev/null)" || proxy_state="inactive"
  health="down"
  host_health="down"
  guest_health="down"
  curl -fsS "http://127.0.0.1:$HOST_PORT/health" >/dev/null 2>&1 && host_health="up"
  guest="unknown"
  if wait_for_ssh "$VM_IP" "$ssh_key" 1; then
    guest="$(ssh_run "$VM_IP" "systemctl is-active openclaw-$id.service" 2>/dev/null)" || guest="unknown"
    if check_guest_health "$id" "$VM_IP" "$ssh_key"; then
      guest_health="up"
    fi
  fi
  if [[ "$host_health" == "up" || "$guest_health" == "up" ]]; then
    health="up"
  fi

  local bold=$'\033[1m' dim=$'\033[2m' reset=$'\033[0m'
  printf "${bold}%s${reset}\n" "$id"
  printf "  %-16s %s\n" "IP" "$VM_IP"
  printf "  %-16s %s\n" "Proxy port" "$HOST_PORT"
  printf "  %-16s %b\n" "VM" "$(_color "$vm_state")"
  printf "  %-16s %b\n" "Proxy" "$(_color "$proxy_state")"
  printf "  %-16s %b\n" "Guest service" "$(_color "$guest")"
  printf "  %-16s %b\n" "Health" "$(_color "$health")"
  printf "  %-16s %b\n" "  Host health" "$(_color "$host_health")"
  printf "  %-16s %b\n" "  Guest health" "$(_color "$guest_health")"
}

cmd_status() {
  if [[ $# -eq 1 ]]; then
    cmd_status_one "$1"
    return
  fi
  cmd_list
}

cmd_start() {
  local id="$1"
  validate_instance_id "$id"
  require_root
  load_instance_env "$id"

  systemctl enable --now "$(vm_service "$id")"
  wait_for_ssh "$VM_IP" "$SSH_KEY_PATH" 180 || die "VM started but SSH unreachable"

  ssh_run "$VM_IP" "sudo systemctl enable --now openclaw-$id.service" || warn "Guest service start failed"
  systemctl enable --now "$(proxy_service "$id")"

  cmd_status_one "$id"
}

cmd_stop() {
  local id="$1"
  validate_instance_id "$id"
  require_root
  load_instance_env "$id"

  systemctl stop "$(proxy_service "$id")" 2>/dev/null || true
  if wait_for_ssh "$VM_IP" "$SSH_KEY_PATH" 1; then
    ssh_run "$VM_IP" "sudo systemctl stop openclaw-$id.service" || true
  fi
  systemctl stop "$(vm_service "$id")"
  cmd_status_one "$id"
}

cmd_restart() {
  cmd_stop "$1"
  cmd_start "$1"
}

cmd_logs() {
  local id="$1"
  local mode="${2:-guest}"
  validate_instance_id "$id"
  load_instance_env "$id"

  if [[ "$mode" == "host" ]]; then
    journalctl -u "$(vm_service "$id")" -u "$(proxy_service "$id")" -f
    return
  fi

  wait_for_ssh "$VM_IP" "$SSH_KEY_PATH" 30 || die "VM SSH unavailable"
  ssh_run "$VM_IP" "sudo journalctl -u openclaw-$id.service -f"
}

cmd_shell() {
  local id="$1"
  shift || true
  validate_instance_id "$id"
  load_instance_env "$id"
  wait_for_ssh "$VM_IP" "$SSH_KEY_PATH" 30 || die "VM SSH unavailable"

  if [[ $# -gt 0 ]]; then
    ssh_run "$VM_IP" "$*"
  else
    ssh -i "$SSH_KEY_PATH" -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=/dev/null "ubuntu@$VM_IP"
  fi
}

cmd_token() {
  local id="$1"
  validate_instance_id "$id"
  cat "$(instance_token "$id")"
}

cmd_destroy() {
  local id="$1"
  local force="${2:-}"
  validate_instance_id "$id"
  require_root
  load_instance_env "$id"

  if [[ "$force" != "--force" ]]; then
    read -r -p "Destroy '$id' and remove VM assets? [y/N] " confirm
    [[ "$confirm" =~ ^[Yy]$ ]] || { echo "Cancelled"; return; }
  fi

  systemctl stop "$(proxy_service "$id")" 2>/dev/null || true
  systemctl stop "$(vm_service "$id")" 2>/dev/null || true
  systemctl disable "$(proxy_service "$id")" 2>/dev/null || true
  systemctl disable "$(vm_service "$id")" 2>/dev/null || true

  rm -f "/etc/systemd/system/$(proxy_service "$id")"
  rm -f "/etc/systemd/system/$(vm_service "$id")"
  systemctl daemon-reload

  rm -rf "$(instance_dir "$id")" "$(fc_instance_dir "$id")"

  echo "Destroyed: $id"
}

[[ $# -ge 1 ]] || { usage; exit 1; }

cmd="$1"
shift || true

case "$cmd" in
  list) cmd_list ;;
  status) cmd_status "$@" ;;
  start) [[ $# -eq 1 ]] || die "Usage: $CMD_NAME start <id>"; cmd_start "$1" ;;
  stop) [[ $# -eq 1 ]] || die "Usage: $CMD_NAME stop <id>"; cmd_stop "$1" ;;
  restart) [[ $# -eq 1 ]] || die "Usage: $CMD_NAME restart <id>"; cmd_restart "$1" ;;
  logs) [[ $# -ge 1 ]] || die "Usage: $CMD_NAME logs <id> [guest|host]"; cmd_logs "$@" ;;
  shell) [[ $# -ge 1 ]] || die "Usage: $CMD_NAME shell <id> [command...]"; id="$1"; shift; cmd_shell "$id" "$@" ;;
  token) [[ $# -eq 1 ]] || die "Usage: $CMD_NAME token <id>"; cmd_token "$1" ;;
  destroy) [[ $# -ge 1 ]] || die "Usage: $CMD_NAME destroy <id> [--force]"; cmd_destroy "$@" ;;
  -h|--help|help) usage ;;
  *) die "Unknown command: $cmd" ;;
esac
