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

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

CMD_NAME="${VM_PROVISION_CMD_NAME:-fireclaw provision}"

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

Each option updates the saved instance config, then guest provisioning reruns
with the result. With no options, provisioning reruns with the saved config.

Options:
  --telegram-token <token>
  --no-telegram                        (clear the saved token; disables Telegram in the guest)
  --telegram-users <csv>
  --model <id>
  --skills <csv>
  --openclaw-image <image>
  --anthropic-api-key <key>
  --openai-api-key <key>
  --minimax-api-key <key>
  --skip-browser-install
  --browser-install                    (re-enable browser install)
  -h|--help
EOF
}

csv_values() {
  printf '%s' "$1" | tr ',' '\n' | sed 's/^[[:space:]]*//; s/[[:space:]]*$//; /^$/d'
}

validate_no_newline() {
  local name="$1"
  local value="$2"
  [[ "$value" != *$'\n'* && "$value" != *$'\r'* ]] || die "$name must not contain newlines"
}

require_option_value() {
  local opt="$1"
  local value="${2-}"
  [[ -n "$value" && "$value" != --* ]] || die "Missing value for $opt"
}

set_kv() {
  local file="$1"
  local key="$2"
  local value="$3"
  local tmp
  validate_no_newline "key" "$key"
  validate_no_newline "$key" "$value"
  tmp="$(mktemp)"
  awk -F= -v key="$key" '$1 != key { print }' "$file" > "$tmp"
  printf "%s=%s\n" "$key" "$value" >> "$tmp"
  install -m 600 "$tmp" "$file"
  rm -f "$tmp"
}

saved_value() {
  local file="$1"
  local key="$2"
  grep "^$key=" "$file" | tail -n 1 | cut -d= -f2- || true
}

if [[ "${1:-}" == "-h" || "${1:-}" == "--help" || "${1:-}" == "help" ]]; then
  usage
  exit 0
fi

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

INSTANCE="$1"
shift

declare -A OVERRIDES=()

while [[ $# -gt 0 ]]; do
  case "$1" in
    --telegram-token) require_option_value "$1" "${2-}"; OVERRIDES[TELEGRAM_TOKEN]="$2"; shift 2 ;;
    --no-telegram) OVERRIDES[TELEGRAM_TOKEN]=""; shift ;;
    --telegram-users) require_option_value "$1" "${2-}"; OVERRIDES[TELEGRAM_USERS]="$2"; shift 2 ;;
    --model) require_option_value "$1" "${2-}"; OVERRIDES[MODEL]="$2"; shift 2 ;;
    --skills) require_option_value "$1" "${2-}"; OVERRIDES[SKILLS]="$2"; shift 2 ;;
    --openclaw-image) require_option_value "$1" "${2-}"; OVERRIDES[OPENCLAW_IMAGE]="$2"; shift 2 ;;
    --anthropic-api-key) require_option_value "$1" "${2-}"; OVERRIDES[ANTHROPIC_API_KEY]="$2"; shift 2 ;;
    --openai-api-key) require_option_value "$1" "${2-}"; OVERRIDES[OPENAI_API_KEY]="$2"; shift 2 ;;
    --minimax-api-key) require_option_value "$1" "${2-}"; OVERRIDES[MINIMAX_API_KEY]="$2"; shift 2 ;;
    --skip-browser-install) OVERRIDES[SKIP_BROWSER_INSTALL]="true"; shift ;;
    --browser-install) OVERRIDES[SKIP_BROWSER_INSTALL]="false"; shift ;;
    *)
      die "Unknown option: $1"
      ;;
  esac
done

validate_instance_id "$INSTANCE"
require_root

# load_instance_env resets the key variables from saved state, so remember
# what the caller passed in the environment before it runs.
ENV_ANTHROPIC_API_KEY="${ANTHROPIC_API_KEY:-}"
ENV_OPENAI_API_KEY="${OPENAI_API_KEY:-}"
ENV_MINIMAX_API_KEY="${MINIMAX_API_KEY:-}"

load_instance_env "$INSTANCE"

ENV_FILE="$(instance_env "$INSTANCE")"
PROVISION_VARS="$(instance_dir "$INSTANCE")/provision.vars"
[[ -f "$PROVISION_VARS" ]] || die "Missing provision vars: $PROVISION_VARS"
[[ -f "$REPO_ROOT/scripts/provision-guest.sh" ]] || die "Missing: $REPO_ROOT/scripts/provision-guest.sh"

if [[ -n "${OVERRIDES[TELEGRAM_USERS]:-}" ]]; then
  [[ -n "$(csv_values "${OVERRIDES[TELEGRAM_USERS]}")" ]] || die "--telegram-users must include at least one allowed Telegram user ID"
fi

effective() {
  local key="$1"
  local fallback="$2"
  if [[ -v "OVERRIDES[$key]" ]]; then
    printf '%s' "${OVERRIDES[$key]}"
  else
    printf '%s' "$fallback"
  fi
}

# Keys passed via the environment fill in for empty saved values, matching
# the behavior the provider-key error message advertises.
if [[ -z "$(effective ANTHROPIC_API_KEY "${ANTHROPIC_API_KEY:-}")" && -n "$ENV_ANTHROPIC_API_KEY" ]]; then
  OVERRIDES[ANTHROPIC_API_KEY]="$ENV_ANTHROPIC_API_KEY"
fi
if [[ -z "$(effective OPENAI_API_KEY "${OPENAI_API_KEY:-}")" && -n "$ENV_OPENAI_API_KEY" ]]; then
  OVERRIDES[OPENAI_API_KEY]="$ENV_OPENAI_API_KEY"
fi
if [[ -z "$(effective MINIMAX_API_KEY "${MINIMAX_API_KEY:-}")" && -n "$ENV_MINIMAX_API_KEY" ]]; then
  OVERRIDES[MINIMAX_API_KEY]="$ENV_MINIMAX_API_KEY"
fi

# Validate the post-override view BEFORE persisting anything, so a rejected
# run leaves the saved config exactly as it was.
EFFECTIVE_TELEGRAM_TOKEN="$(effective TELEGRAM_TOKEN "$(saved_value "$PROVISION_VARS" TELEGRAM_TOKEN)")"
EFFECTIVE_TELEGRAM_USERS="$(effective TELEGRAM_USERS "${TELEGRAM_USERS:-}")"
if [[ -n "$EFFECTIVE_TELEGRAM_TOKEN" ]]; then
  if [[ -z "$(csv_values "$EFFECTIVE_TELEGRAM_USERS")" ]]; then
    die "Telegram is enabled but TELEGRAM_USERS is empty; rerun with: sudo $CMD_NAME $INSTANCE --telegram-users <csv>"
  fi
fi

EFFECTIVE_MODEL="$(effective MODEL "${MODEL:-}")"
ANTHROPIC_API_KEY="$(effective ANTHROPIC_API_KEY "${ANTHROPIC_API_KEY:-}")"
OPENAI_API_KEY="$(effective OPENAI_API_KEY "${OPENAI_API_KEY:-}")"
MINIMAX_API_KEY="$(effective MINIMAX_API_KEY "${MINIMAX_API_KEY:-}")"
require_model_provider_key "$EFFECTIVE_MODEL"

# TELEGRAM_TOKEN lives only in provision.vars; every other key is mirrored
# into the .env state file that load_instance_env reads.
for key in "${!OVERRIDES[@]}"; do
  set_kv "$PROVISION_VARS" "$key" "${OVERRIDES[$key]}"
  if [[ "$key" != "TELEGRAM_TOKEN" ]]; then
    set_kv "$ENV_FILE" "$key" "${OVERRIDES[$key]}"
  fi
done

if ! wait_for_ssh "$VM_IP" "$SSH_KEY_PATH" 180 "$INSTANCE"; then
  die "VM SSH unreachable. Start it first: fireclaw start $INSTANCE"
fi

scp -i "$SSH_KEY_PATH" -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile="$(ssh_known_hosts_file "$INSTANCE")" \
  "$REPO_ROOT/scripts/provision-guest.sh" "ubuntu@$VM_IP:/tmp/provision-guest.sh"
scp -i "$SSH_KEY_PATH" -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile="$(ssh_known_hosts_file "$INSTANCE")" \
  "$PROVISION_VARS" "ubuntu@$VM_IP:/tmp/provision.vars"

ssh -i "$SSH_KEY_PATH" -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile="$(ssh_known_hosts_file "$INSTANCE")" \
  "ubuntu@$VM_IP" "sudo bash /tmp/provision-guest.sh /tmp/provision.vars"

systemctl enable --now "$(proxy_service "$INSTANCE")"

if ! wait_for_instance_health "$INSTANCE" "$VM_IP" "$HOST_PORT" "$SSH_KEY_PATH" 30; then
  die "Health checks did not pass for $INSTANCE after provisioning"
fi

echo "✓ VM provisioning complete"
echo "  Instance: $INSTANCE"
echo "  VM IP:    $VM_IP"
echo "  Port:     $HOST_PORT"
echo "  Health:   up (guest + proxy)"
