#!/usr/bin/env bash
#
# NOVA AGENT INSTALLER
# Standalone script for curl-based installation
#
# Usage:
#   curl -fsSL https://get.novaaiops.com/install.sh | sudo bash -s -- --api URL --token TOKEN
#   OR
#   NOVA_API_KEY="your_key" curl -fsSL https://get.novaaiops.com/install.sh | sudo bash
#
# Command Line Arguments:
#   --api URL         - API endpoint URL (e.g., https://api.novaaiops.com)
#   --token TOKEN     - Your Nova AI agent install token
#   --name NAME       - Custom node name (default: hostname)
#
# Environment Variables:
#   NOVA_API_KEY      - Required: Your Nova AI agent API key
#   NOVA_ENDPOINT     - API endpoint (default: https://app.novaaiops.com/api)
#   NOVA_NODE_NAME    - Node name (default: hostname)
#   NOVA_DEBUG        - Set to 1 for verbose output
#

set -euo pipefail

# ─── Colours ────────────────────────────────────────────────────────────────
# Brand greens are 24-bit RGB sampled directly from the Nova AI logo robot
# (Nova-AI-Ops-Website-green-Design-best/nova-logo.png). Same three stops the
# `nova` CLI banner uses, so the install flow and the post-install CLI feel
# like one product.
#
#   #90F127  LIME    — logo top highlight   (top of art, left ◆, accents)
#   #58BA18  BRAND   — logo body fill       (mid art, WELCOME letters, success)
#   #105707  FOREST  — logo deep shadow     (bottom art, right ◆)
LIME="\033[38;2;144;241;39m"
BRAND="\033[38;2;88;186;24m"
FOREST="\033[38;2;16;87;7m"
DIM="\033[38;2;139;148;158m"
FG="\033[38;2;201;209;217m"

# Legacy palette tokens — kept so any echo lines elsewhere in this script
# that still reference PURPLE/PINK/ORANGE collapse onto the green ramp
# instead of producing the old purple/pink/orange.
PURPLE="$LIME"
PINK="$BRAND"
ORANGE="$FOREST"

BLUE="\033[38;5;39m"
GREEN="$BRAND"
GRAY="\033[38;5;245m"
RED="\033[38;5;196m"
YELLOW="\033[38;5;226m"
BOLD="\033[1m"
RESET="\033[0m"

# Parse command line arguments
while [[ $# -gt 0 ]]; do
  case $1 in
    --api)
      NOVA_ENDPOINT="$2/api"
      shift 2
      ;;
    --token)
      NOVA_API_KEY="$2"
      shift 2
      ;;
    --name)
      NOVA_NODE_NAME="$2"
      shift 2
      ;;
    --debug)
      NOVA_DEBUG=1
      shift
      ;;
    *)
      shift
      ;;
  esac
done

# Configuration (command line args override environment variables)
NOVA_API_KEY="${NOVA_API_KEY:-}"
NOVA_ENDPOINT="${NOVA_ENDPOINT:-https://app.novaaiops.com/api}"
NOVA_NODE_NAME="${NOVA_NODE_NAME:-$(hostname)}"
SERVICE_NAME="nova-ai-agent"
BINARY_PATH="/usr/local/bin/nova-ai-agent"
CONFIG_DIR="/etc/nova"
CONFIG_FILE="${CONFIG_DIR}/agent.yaml"
SYSTEMD_UNIT_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
DATA_DIR="/var/lib/nova"
LOG_DIR="/var/log/nova"

# Agent download URL - extract base URL from endpoint
ENDPOINT_BASE="${NOVA_ENDPOINT%/api}"
AGENT_DOWNLOAD_BASE="${NOVA_DOWNLOAD_URL:-${ENDPOINT_BASE}/downloads/agent}"

# Build a horizontal rule split into three coloured segments — lime →
# brand → forest — same tri-colour pattern the `nova` CLI banner draws
# above and below its ASCII art. $1 = total width in characters.
tri_rule() {
  local width="${1:-72}"
  local a=$((width / 3))
  local b=$((width / 3))
  local c=$((width - a - b))
  local out=""
  out+="${LIME}"; for ((i = 0; i < a; i++)); do out+="━"; done
  out+="${BRAND}"; for ((i = 0; i < b; i++)); do out+="━"; done
  out+="${FOREST}"; for ((i = 0; i < c; i++)); do out+="━"; done
  out+="${RESET}"
  printf "    %b\n" "$out"
}

print_logo() {
  echo ""
  tri_rule 84
  echo ""
  # ASCII art rows cycle through the same three logo stops as the CLI banner.
  # Single-line "NOVA AGENT" wordmark — 84-col content + 4-col indent = 88.
  echo -e "    ${LIME}███╗   ██╗ ██████╗ ██╗   ██╗ █████╗      █████╗  ██████╗ ███████╗███╗   ██╗████████╗${RESET}"
  echo -e "    ${BRAND}████╗  ██║██╔═══██╗██║   ██║██╔══██╗    ██╔══██╗██╔════╝ ██╔════╝████╗  ██║╚══██╔══╝${RESET}"
  echo -e "    ${FOREST}██╔██╗ ██║██║   ██║██║   ██║███████║    ███████║██║  ███╗█████╗  ██╔██╗ ██║   ██║   ${RESET}"
  echo -e "    ${LIME}██║╚██╗██║██║   ██║╚██╗ ██╔╝██╔══██║    ██╔══██║██║   ██║██╔══╝  ██║╚██╗██║   ██║   ${RESET}"
  echo -e "    ${BRAND}██║ ╚████║╚██████╔╝ ╚████╔╝ ██║  ██║    ██║  ██║╚██████╔╝███████╗██║ ╚████║   ██║   ${RESET}"
  echo -e "    ${FOREST}╚═╝  ╚═══╝ ╚═════╝   ╚═══╝  ╚═╝  ╚═╝    ╚═╝  ╚═╝ ╚═════╝ ╚══════╝╚═╝  ╚═══╝   ╚═╝   ${RESET}"
  echo ""
  # WELCOME caption — bracketed by lime/forest diamonds, brand-green text.
  # Indent chosen so the caption sits roughly centred under the 84-col rule.
  echo -e "                       ${BOLD}${LIME}◆  ${BRAND}Welcome to NOVA AGENT${FOREST}  ◆${RESET}"
  echo ""
  echo -e "        ${DIM}Multi-distro agent  ·  metrics, logs, runbooks  ·  AI remediation${RESET}"
  echo ""
  tri_rule 84
  echo ""
}

step() { echo -e "${BLUE}${BOLD}▸ $*${RESET}"; }
substep() { echo -e "${GRAY}  • $*${RESET}"; }
success() { echo -e "${GREEN}✔ $*${RESET}"; }
error() { echo -e "${RED}✗ $*${RESET}" >&2; }
warn() { echo -e "${YELLOW}⚠ $*${RESET}"; }
info() { echo -e "${GRAY}$*${RESET}"; }
# Hard-fail with a red error message and non-zero exit. Used by download_agent
# when the canonical agent script can't be fetched / verified — installing a
# stale or partial binary would silently produce broken installs, so we'd
# rather block the install than let the user end up with a phantom agent.
fail() { error "$*"; exit 1; }

detect_arch() {
  case "$(uname -m)" in
    x86_64)  echo "amd64" ;;
    aarch64) echo "arm64" ;;
    armv7l)  echo "armv7" ;;
    *)
      error "Unsupported architecture: $(uname -m)"
      exit 1
      ;;
  esac
}

check_root() {
  if [[ $EUID -ne 0 ]]; then
    error "This installer must be run as root or with sudo"
    info "Run: sudo bash -c \"\$(curl -fsSL https://get.novaaiops.com/install.sh)\""
    exit 1
  fi
}

check_prerequisites() {
  step "Checking prerequisites"

  # Check for systemd
  if ! command -v systemctl &> /dev/null; then
    error "systemd is required but not found"
    exit 1
  fi

  # Check for curl
  if ! command -v curl &> /dev/null; then
    error "curl is required but not found"
    info "Install with: apt-get install curl  or  yum install curl"
    exit 1
  fi

  success "Prerequisites satisfied"
}

check_api_key() {
  if [[ -z "$NOVA_API_KEY" ]]; then
    echo ""
    error "Install token is required"
    echo ""
    info "To get your install token:"
    info "  1. Go to https://app.novaaiops.com/instances"
    info "  2. Click 'Quick Install' then 'Generate Install Token'"
    info "  3. Copy the install command"
    echo ""
    info "Example usage:"
    echo -e "${BLUE}  curl -fsSL https://get.novaaiops.com/install.sh | sudo bash -s -- --api \"https://api.novaaiops.com\" --token \"your_token\"${RESET}"
    echo ""
    info "Or use environment variable:"
    echo -e "${BLUE}  NOVA_API_KEY=\"your_token\" curl -fsSL https://get.novaaiops.com/install.sh | sudo bash${RESET}"
    echo ""
    exit 1
  fi

  success "Install token provided"
}

download_agent() {
  step "Installing Nova AI agent"

  # Detect OS so we pick the right sibling agent. macOS hosts get the
  # darwin-native script (vm_stat / iostat / launchctl); everything else
  # gets the Linux script. (Windows runs install.ps1, not this file.)
  local OS_KIND="linux"
  case "$(uname -s)" in
    Darwin) OS_KIND="macos" ;;
    Linux)  OS_KIND="linux" ;;
    *)      OS_KIND="linux" ;;  # best-effort default for other unix-likes
  esac
  local AGENT_FILE="nova-ai-agent.sh"
  if [ "$OS_KIND" = "macos" ]; then
    AGENT_FILE="nova-ai-agent.macos.sh"
  fi
  substep "Platform: ${OS_KIND}_$(detect_arch)"

  # Fetch the canonical agent + persistent-shell helper from the platform's
  # /api/agent-script/ endpoint instead of inlining a copy. The previous
  # installer baked a v2.0.0 heredoc into this script, so every new install
  # got a 7-month-stale agent regardless of the version in the repo. Fetching
  # at install-time means the agent always matches the deployed backend.
  #
  # Both files are content-addressable: we pull the SHA-256 first via the
  # /api/agent-script/version endpoint and verify the body matches before
  # `chmod +x`. A mismatch aborts the install rather than installing a
  # tampered or partial download.
  local AGENT_SRC="${NOVA_ENDPOINT%/api}/api/agent-script/${AGENT_FILE}"
  local RUNNER_SRC="${NOVA_ENDPOINT%/api}/api/agent-script/nova-shell-runner.py"
  local VERSION_SRC="${NOVA_ENDPOINT%/api}/api/agent-script/version?file=${AGENT_FILE}"

  substep "Fetching agent metadata from $VERSION_SRC"
  local META
  META=$(curl -fsSL --max-time 15 "$VERSION_SRC" 2>/dev/null) ||     fail "Could not reach $VERSION_SRC — is the API URL correct and reachable?"
  local AGENT_VERSION AGENT_SHA
  AGENT_VERSION=$(echo "$META" | grep -oE '"version":"[^"]+"' | head -1 | cut -d'"' -f4)
  AGENT_SHA=$(    echo "$META" | grep -oE '"sha256":"[^"]+"'  | head -1 | cut -d'"' -f4)
  [ -n "$AGENT_VERSION" ] || fail "Could not parse agent version from $VERSION_SRC"
  [ -n "$AGENT_SHA"     ] || fail "Could not parse agent sha256 from $VERSION_SRC"

  substep "Downloading agent v${AGENT_VERSION} (sha256: ${AGENT_SHA:0:16}...)"
  local TMP_AGENT
  TMP_AGENT=$(mktemp /tmp/nova-ai-agent.XXXXXX)
  curl -fsSL --max-time 60 -o "$TMP_AGENT" "$AGENT_SRC" ||     fail "Failed to download agent from $AGENT_SRC"
  local GOT_SHA
  GOT_SHA=$(sha256sum "$TMP_AGENT" | awk '{print $1}')
  if [ "$GOT_SHA" != "$AGENT_SHA" ]; then
    rm -f "$TMP_AGENT"
    fail "Agent sha256 mismatch: got $GOT_SHA, expected $AGENT_SHA — aborting install"
  fi
  install -m 0755 "$TMP_AGENT" "$BINARY_PATH"
  rm -f "$TMP_AGENT"

  # Persistent-shell helper (v2.2.0+). Without this, Nova Shell remote-exec
  # falls back to stateless mode (each command in a fresh `bash -c`, losing
  # cwd/env/aliases between commands). Fetched best-effort — older backends
  # may not serve it yet, in which case we just skip with a warning.
  local TMP_RUNNER
  TMP_RUNNER=$(mktemp /tmp/nova-shell-runner.XXXXXX)
  if curl -fsSL --max-time 30 -o "$TMP_RUNNER" "$RUNNER_SRC" 2>/dev/null && [ -s "$TMP_RUNNER" ]; then
    install -m 0755 "$TMP_RUNNER" "/usr/local/bin/nova-shell-runner.py"
    substep "Persistent-shell helper installed at /usr/local/bin/nova-shell-runner.py"
  else
    substep "Persistent-shell helper not available on this backend — skipping (Nova Shell will run in legacy mode)"
  fi
  rm -f "$TMP_RUNNER"

  success "Agent v${AGENT_VERSION} installed to $BINARY_PATH"
}

write_config() {
  step "Creating configuration"

  mkdir -p "$CONFIG_DIR" "$DATA_DIR" "$LOG_DIR"

  printf "api_key: %s\nnode_name: %s\nendpoint_url: %s\nlog_level: info\nlog_file: %s\ndata_dir: %s\nmetrics_interval: 15\nheartbeat_interval: 30\n" \
    "$NOVA_API_KEY" "$NOVA_NODE_NAME" "$NOVA_ENDPOINT" "${LOG_DIR}/agent.log" "$DATA_DIR" \
    > "$CONFIG_FILE"

  chmod 600 "$CONFIG_FILE"
  success "Configuration written to $CONFIG_FILE"
}

create_systemd_unit() {
  step "Creating systemd service"

  cat > "$SYSTEMD_UNIT_FILE" << EOF
[Unit]
Description=NOVA AI Ops Agent
Documentation=https://docs.novaaiops.com/agent
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=root
Group=root
ExecStart=${BINARY_PATH} --config=${CONFIG_FILE}
Restart=on-failure
RestartSec=10s
StandardOutput=journal
StandardError=journal
SyslogIdentifier=${SERVICE_NAME}

# Security hardening
NoNewPrivileges=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF

  success "Systemd unit created"
}

start_service() {
  step "Starting Nova AI agent service"

  systemctl daemon-reload
  systemctl enable "$SERVICE_NAME" 2>/dev/null || true

  if systemctl start "$SERVICE_NAME"; then
    sleep 2
    if systemctl is-active --quiet "$SERVICE_NAME"; then
      success "Service started and running"
    else
      warn "Service started but may have issues"
      info "Check logs: journalctl -u $SERVICE_NAME -n 50"
    fi
  else
    error "Failed to start service"
    info "Check logs: journalctl -u $SERVICE_NAME -n 50"
    exit 1
  fi
}

register_agent() {
  step "Registering agent with Nova AI"

  # Exchange install token for agent credentials
  local response
  response=$(curl -sS -X POST "${NOVA_ENDPOINT}/agent/register" \
    -H "Content-Type: application/json" \
    -d "{
      \"token\": \"${NOVA_API_KEY}\",
      \"hostname\": \"${NOVA_NODE_NAME}\",
      \"osType\": \"linux\",
      \"agentVersion\": \"1.0.0\",
      \"metadata\": {
        \"arch\": \"$(detect_arch)\",
        \"installer\": \"curl-install\"
      }
    }" 2>&1)

  # Check if registration succeeded
  if echo "$response" | grep -q '"success":true'; then
    # Extract agent credentials from response
    AGENT_ID=$(echo "$response" | grep -o '"agentId":"[^"]*"' | cut -d'"' -f4)
    AGENT_SECRET=$(echo "$response" | grep -o '"agentSecret":"[^"]*"' | cut -d'"' -f4)

    if [[ -n "$AGENT_ID" && -n "$AGENT_SECRET" ]]; then
      success "Agent registered: $AGENT_ID"

      # Write config with printf to guarantee single-line values (heredoc + long
      # keys can wrap in some terminal/shell combinations, breaking YAML parsing)
      printf "agent_id: %s\nagent_secret: %s\napi_key: %s\nnode_name: %s\nendpoint_url: %s\nlog_level: info\nlog_file: %s\ndata_dir: %s\nmetrics_interval: 15\nheartbeat_interval: 30\n" \
        "$AGENT_ID" "$AGENT_SECRET" "$AGENT_SECRET" "$NOVA_NODE_NAME" "$NOVA_ENDPOINT" "${LOG_DIR}/agent.log" "$DATA_DIR" \
        > "$CONFIG_FILE"
      chmod 600 "$CONFIG_FILE"
      success "Config updated with agent credentials"
    else
      warn "Could not parse agent credentials from response"
      info "Response: $response"
    fi
  else
    warn "Agent registration failed - will use install token for auth"
    info "Response: $response"
  fi
}

send_initial_heartbeat() {
  step "Sending initial heartbeat"

  # Determine auth header based on available credentials
  local auth_header
  if [[ -f "$CONFIG_FILE" ]]; then
    local agent_secret=$(grep "agent_secret:" "$CONFIG_FILE" 2>/dev/null | awk '{print $2}')
    if [[ -n "$agent_secret" ]]; then
      auth_header="X-Agent-API-Key: $agent_secret"
    else
      auth_header="X-Agent-API-Key: ${NOVA_API_KEY}"
    fi
  else
    auth_header="X-Agent-API-Key: ${NOVA_API_KEY}"
  fi

  local response
  if response=$(curl -sS -X POST "${NOVA_ENDPOINT}/agents/heartbeat" \
    -H "$auth_header" \
    -H "Content-Type: application/json" \
    -d "{
      \"hostname\": \"${NOVA_NODE_NAME}\",
      \"os\": \"linux\",
      \"arch\": \"$(detect_arch)\",
      \"agentVersion\": \"1.0.0\",
      \"timestamp\": $(date +%s)
    }" 2>&1); then
    success "Heartbeat sent"
  else
    warn "Initial heartbeat failed (agent will retry)"
    info "Response: $response"
  fi
}

print_summary() {
  echo ""
  tri_rule 72
  echo ""
  echo -e "    ${BOLD}${BRAND}✓  INSTALLATION COMPLETE${RESET}      ${DIM}— Nova AI agent is now reporting${RESET}"
  echo ""
  echo -e "    ${DIM}Service${RESET}    ${BRAND}$SERVICE_NAME (running)${RESET}"
  echo -e "    ${DIM}Binary${RESET}     ${FG}$BINARY_PATH${RESET}"
  echo -e "    ${DIM}Config${RESET}     ${FG}$CONFIG_FILE${RESET}"
  echo -e "    ${DIM}Logs${RESET}       ${FG}journalctl -u $SERVICE_NAME -f${RESET}"
  echo ""
  echo -e "    ${BOLD}${LIME}Next steps${RESET}"
  echo -e "      ${DIM}1.${RESET}  ${LIME}https://app.novaaiops.com/instances${RESET}     ${DIM}— see your instance live${RESET}"
  echo -e "      ${DIM}2.${RESET}  ${BRAND}systemctl status $SERVICE_NAME${RESET}    ${DIM}— quick health check${RESET}"
  echo -e "      ${DIM}3.${RESET}  ${FOREST}journalctl -u $SERVICE_NAME -f${RESET}    ${DIM}— tail the agent logs${RESET}"
  echo ""
  tri_rule 72
  echo ""
}

main() {
  # print_logo already prints the WELCOME caption + tagline + tri-rule
  # frame; the redundant "NOVA AI AGENT INSTALLER" double-rule block that
  # used to sit here was making the header read as two competing titles.
  print_logo

  check_root
  check_prerequisites
  check_api_key

  # Check for existing installation
  if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
    warn "Nova AI agent is already installed and running"
    info "To reinstall, first run: systemctl stop $SERVICE_NAME"
    info "Then run this installer again"
    exit 0
  fi

  download_agent
  write_config
  register_agent
  create_systemd_unit
  start_service
  send_initial_heartbeat

  print_summary
}

main "$@"