#!/usr/bin/env bash
# ─────────────────────────────────────────────────────────────
# RackPlane Agent Installer
# curl -sSL https://get.rackplane.io/install.sh | sudo bash
#
# Non-interactive mode (for auto-updates):
#   install.sh --auto --token=TOKEN --node-id=NODE_ID
# ─────────────────────────────────────────────────────────────
set -euo pipefail

# ── Hardcoded Server ────────────────────────────────────────

RACKPLANE_SERVER="rackplane.io:9090"
DOWNLOAD_BASE="https://rackplane.io"

# ── Configuration ───────────────────────────────────────────

INSTALL_DIR="/usr/local/bin"
CONFIG_DIR="/etc/rackplane"
DATA_DIR="/var/lib/rackplane"
LOG_DIR="/var/log/rackplane"
SERVICE_USER="rackplane"

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
DIM='\033[2m'
NC='\033[0m'

# ── Parse CLI Arguments ────────────────────────────────────

AUTO_MODE=false
CLI_TOKEN=""
CLI_NODE_ID=""

for arg in "$@"; do
    case "$arg" in
        --auto)           AUTO_MODE=true ;;
        --token=*)        CLI_TOKEN="${arg#--token=}" ;;
        --node-id=*)      CLI_NODE_ID="${arg#--node-id=}" ;;
        *)                ;;
    esac
done

info()  { [ "$AUTO_MODE" = "true" ] && return; echo -e "${CYAN}  ▸${NC} $*"; }
ok()    { [ "$AUTO_MODE" = "true" ] && return; echo -e "${GREEN}  ✓${NC} $*"; }
warn()  { [ "$AUTO_MODE" = "true" ] && return; echo -e "${YELLOW}  ⚠${NC} $*"; }
err()   { echo -e "${RED}  ✗${NC} $*" >&2; }
die()   { err "$*"; exit 1; }

prompt() {
    local var_name="$1" prompt_text="$2" default="${3:-}"
    local input
    if [ -n "$default" ]; then
        echo -en "  ${BOLD}${prompt_text}${NC} ${DIM}[${default}]${NC}: "
    else
        echo -en "  ${BOLD}${prompt_text}${NC}: "
    fi
    read -r input < /dev/tty
    if [ -n "$input" ]; then
        eval "$var_name='$input'"
    elif [ -n "$default" ]; then
        eval "$var_name='$default'"
    else
        eval "$var_name=''"
    fi
}

confirm() {
    local prompt_text="$1" default="${2:-y}"
    local input
    if [ "$default" = "y" ]; then
        echo -en "  ${prompt_text} ${DIM}[Y/n]${NC}: "
    else
        echo -en "  ${prompt_text} ${DIM}[y/N]${NC}: "
    fi
    read -r input < /dev/tty
    input="${input:-$default}"
    case "$input" in
        [yY]|[yY][eE][sS]) return 0 ;;
        *) return 1 ;;
    esac
}

# ── Banner ──────────────────────────────────────────────────

if [ "$AUTO_MODE" != "true" ]; then
echo ""
echo -e "${CYAN}  ┌──────────────────────────────────────────────────┐${NC}"
echo -e "${CYAN}  │${NC}${BOLD}          RackPlane Agent Installer               ${NC}${CYAN}│${NC}"
echo -e "${CYAN}  │${NC}${DIM}          https://rackplane.io                    ${NC}${CYAN}│${NC}"
echo -e "${CYAN}  └──────────────────────────────────────────────────┘${NC}"
echo ""
fi

# ── Preflight Checks ───────────────────────────────────────

if [ "$(id -u)" -ne 0 ]; then
    die "Root required. Run: curl -sSL https://get.rackplane.io/install.sh | sudo bash"
fi

# Detect OS
if [ -f /etc/os-release ]; then
    . /etc/os-release
    OS_ID="${ID:-unknown}"
    OS_VERSION="${VERSION_ID:-unknown}"
else
    die "Unsupported system (missing /etc/os-release)"
fi

# Detect architecture
UNAME_ARCH="$(uname -m)"
case "$UNAME_ARCH" in
    x86_64)           ARCH="amd64" ;;
    aarch64|arm64)    ARCH="arm64" ;;
    armv7l|armhf)     ARCH="armv7" ;;
    *)                die "Unsupported architecture: $UNAME_ARCH" ;;
esac

OS="$(uname -s | tr '[:upper:]' '[:lower:]')"

info "Detected ${BOLD}${OS_ID} ${OS_VERSION}${NC} (${ARCH})"

# Check existing installation
UPGRADE=false
if command -v rackplane-agent &>/dev/null; then
    EXISTING_VER=$(rackplane-agent --version 2>/dev/null || echo "unknown")
    if [ "$AUTO_MODE" = "true" ]; then
        UPGRADE=true
    else
        warn "rackplane-agent is already installed (${EXISTING_VER})"
        echo ""
        if confirm "Upgrade the agent?"; then
            UPGRADE=true
        else
            echo ""
            ok "Installation cancelled"
            exit 0
        fi
    fi
fi

# ── Interactive Setup ───────────────────────────────────────

if [ "$AUTO_MODE" = "true" ]; then
    # Auto mode — load existing config, override with CLI args.
    EXISTING_TOKEN=""
    EXISTING_NODE_ID=""
    if [ -f "${CONFIG_DIR}/agent.env" ]; then
        EXISTING_TOKEN=$(grep -oP '^\s*RACKPLANE_ORG_TOKEN=\K.*' "${CONFIG_DIR}/agent.env" 2>/dev/null || true)
        EXISTING_NODE_ID=$(grep -oP '^\s*RACKPLANE_NODE_ID=\K.*' "${CONFIG_DIR}/agent.env" 2>/dev/null || true)
    fi
    RACKPLANE_TOKEN="${CLI_TOKEN:-$EXISTING_TOKEN}"
    RACKPLANE_NODE_ID="${CLI_NODE_ID:-${EXISTING_NODE_ID:-$(hostname -s 2>/dev/null || echo "node")}}"

    if [ -z "$RACKPLANE_TOKEN" ]; then
        die "Auto mode requires --token=TOKEN or an existing config"
    fi
else
    echo ""
    echo -e "  ${BOLD}Setup${NC}"
    echo -e "  ${DIM}────────────────────────────────────────────────${NC}"
    echo ""

    # Load existing config values when upgrading.
    EXISTING_TOKEN=""
    EXISTING_NODE_ID=""
    if [ "$UPGRADE" = "true" ] && [ -f "${CONFIG_DIR}/agent.env" ]; then
        EXISTING_TOKEN=$(grep -oP '^\s*RACKPLANE_ORG_TOKEN=\K.*' "${CONFIG_DIR}/agent.env" 2>/dev/null || true)
        EXISTING_NODE_ID=$(grep -oP '^\s*RACKPLANE_NODE_ID=\K.*' "${CONFIG_DIR}/agent.env" 2>/dev/null || true)
        if [ -n "$EXISTING_TOKEN" ]; then
            info "Found existing license key: ${EXISTING_TOKEN:0:12}…"
        fi
    fi

    # License key
    RACKPLANE_TOKEN=""
    if [ -n "$EXISTING_TOKEN" ]; then
        prompt RACKPLANE_TOKEN "License key" "$EXISTING_TOKEN"
    else
        prompt RACKPLANE_TOKEN "License key"
    fi

    if [ -z "$RACKPLANE_TOKEN" ]; then
        echo ""
        die "A license key is required. Create one at https://rackplane.io/settings/license-keys"
    fi

    # Node ID
    DEFAULT_NODE_ID="${EXISTING_NODE_ID:-$(hostname -s 2>/dev/null || echo "node")}"
    RACKPLANE_NODE_ID=""
    prompt RACKPLANE_NODE_ID "Node ID" "$DEFAULT_NODE_ID"

    echo ""
    echo -e "  ${DIM}────────────────────────────────────────────────${NC}"
    echo -e "  ${DIM}Server${NC}       ${RACKPLANE_SERVER}"
    echo -e "  ${DIM}Node ID${NC}      ${RACKPLANE_NODE_ID}"
    echo -e "  ${DIM}License key${NC}  ${RACKPLANE_TOKEN:0:12}…"
    echo -e "  ${DIM}────────────────────────────────────────────────${NC}"
    echo ""

    if ! confirm "Proceed with installation?"; then
        echo ""
        ok "Installation cancelled"
        exit 0
    fi

    echo ""
fi

# ── Dependency Check ────────────────────────────────────────

check_cmd() { command -v "$1" &>/dev/null; }

for cmd in curl; do
    if ! check_cmd "$cmd"; then
        info "Installing ${cmd}..."
        case "$OS_ID" in
            ubuntu|debian)
                apt-get update -qq && apt-get install -y -qq "$cmd" >/dev/null 2>&1
                ;;
            centos|rhel|rocky|alma|fedora)
                dnf install -y -q "$cmd" >/dev/null 2>&1 || yum install -y -q "$cmd" >/dev/null 2>&1
                ;;
            *)
                die "Please install '${cmd}' manually and re-run the installer"
                ;;
        esac
    fi
done

# ── Download Agent Binary ──────────────────────────────────

DOWNLOAD_URL="${DOWNLOAD_BASE}/api/v1/agent/download?os=${OS}&arch=${ARCH}"

info "Downloading rackplane-agent (${OS}/${ARCH})..."

TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT

curl -fsSL -o "${TMPDIR}/rackplane-agent" "$DOWNLOAD_URL" 2>/dev/null || \
    die "Download failed. Check your network connection."

# Verify we got an actual binary, not an HTML error page
if file "${TMPDIR}/rackplane-agent" 2>/dev/null | grep -qiE 'text|html'; then
    die "Downloaded file is not a valid binary. Please try again later."
fi

install -m 0755 "${TMPDIR}/rackplane-agent" "${INSTALL_DIR}/rackplane-agent"
INSTALLED_VER=$("${INSTALL_DIR}/rackplane-agent" --version 2>/dev/null || echo "latest")
ok "Installed rackplane-agent ${INSTALLED_VER} → ${INSTALL_DIR}/rackplane-agent"

# Create 'rackplane' convenience symlink for CLI usage.
ln -sf "${INSTALL_DIR}/rackplane-agent" "${INSTALL_DIR}/rackplane"
ok "CLI available as 'rackplane' (status, logs, reconnect, version)"

# ── Install Docker (if needed) ──────────────────────────────

if check_cmd docker; then
    ok "Docker already installed ($(docker --version 2>/dev/null | head -c 40))"
else
    info "Installing Docker..."
    curl -fsSL https://get.docker.com | sh -s -- --quiet
    systemctl enable --now docker >/dev/null 2>&1
    ok "Docker installed"
fi

# ── Create User & Directories ──────────────────────────────

if ! id "$SERVICE_USER" &>/dev/null; then
    useradd --system --shell /usr/sbin/nologin --home-dir "$DATA_DIR" --create-home "$SERVICE_USER"
    ok "Created system user: ${SERVICE_USER}"
fi

# Add rackplane user to docker group
usermod -aG docker "$SERVICE_USER" 2>/dev/null || true

mkdir -p "$CONFIG_DIR" \
         "$DATA_DIR"/{vms,images,sftp,state,containers} \
         "$LOG_DIR"
chown -R "$SERVICE_USER":"$SERVICE_USER" "$DATA_DIR" "$LOG_DIR"

# ── Configuration ───────────────────────────────────────────

if [ ! -f "${CONFIG_DIR}/agent.env" ] || [ "$UPGRADE" = "true" ]; then
    cat > "${CONFIG_DIR}/agent.env" <<ENVFILE
# RackPlane Agent Configuration
# Generated by installer on $(date -u +"%Y-%m-%dT%H:%M:%SZ")

# Node identifier
RACKPLANE_NODE_ID=${RACKPLANE_NODE_ID}

# License key
RACKPLANE_ORG_TOKEN=${RACKPLANE_TOKEN}

# Server address (gRPC)
RACKPLANE_SERVER_ADDR=${RACKPLANE_SERVER}

# Data directory
RACKPLANE_DATA_DIR=${DATA_DIR}

# Docker socket
DOCKER_HOST=unix:///var/run/docker.sock

# SFTP for game server file access
RACKPLANE_SFTP_ENABLED=true
RACKPLANE_SFTP_ADDR=:2022
RACKPLANE_SFTP_HOST_KEY=${DATA_DIR}/sftp_host_key

# Agent poll interval (seconds)
RACKPLANE_POLL_INTERVAL=30
ENVFILE
    chmod 600 "${CONFIG_DIR}/agent.env"
    chown root:root "${CONFIG_DIR}/agent.env"
    ok "Configuration written to ${CONFIG_DIR}/agent.env"
else
    ok "Existing config preserved at ${CONFIG_DIR}/agent.env"
fi

# ── Systemd Service ────────────────────────────────────────

cat > /etc/systemd/system/rackplane-agent.service <<EOF
[Unit]
Description=RackPlane Agent
Documentation=https://docs.rackplane.io
After=network-online.target docker.service
Wants=network-online.target
Requires=docker.service

[Service]
Type=simple
User=root
EnvironmentFile=${CONFIG_DIR}/agent.env
ExecStart=${INSTALL_DIR}/rackplane-agent
Restart=on-failure
RestartSec=10
LimitNOFILE=65536
TimeoutStartSec=30
TimeoutStopSec=30

# Hardening
NoNewPrivileges=false
ProtectSystem=strict
ReadWritePaths=${DATA_DIR} ${LOG_DIR} /var/run/docker.sock /tmp
ProtectHome=true
ProtectKernelTunables=false
ProtectKernelModules=true
PrivateTmp=true

# Logging
StandardOutput=append:${LOG_DIR}/agent.log
StandardError=append:${LOG_DIR}/agent-error.log

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable rackplane-agent >/dev/null 2>&1
ok "Systemd service installed and enabled"

# ── Kernel Tweaks ───────────────────────────────────────────

info "Applying network tuning..."

cat > /etc/sysctl.d/99-rackplane.conf <<'SYSCTL'
net.ipv4.ip_forward = 1
net.ipv4.conf.all.forwarding = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
vm.swappiness = 10
SYSCTL

sysctl --system -q 2>/dev/null || true
ok "Kernel parameters configured"

# ── Start Agent ─────────────────────────────────────────────

info "Starting agent..."

if [ "$UPGRADE" = "true" ]; then
    systemctl restart rackplane-agent
else
    systemctl start rackplane-agent
fi

sleep 2
if systemctl is-active --quiet rackplane-agent; then
    ok "Agent is running"
else
    warn "Agent failed to start — check: journalctl -u rackplane-agent"
fi

# ── Summary ─────────────────────────────────────────────────

if [ "$AUTO_MODE" != "true" ]; then
echo ""
echo -e "${GREEN}  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "  ${BOLD}RackPlane agent installed successfully${NC}"
echo ""
echo -e "  ${DIM}Binary${NC}   ${INSTALL_DIR}/rackplane-agent"
echo -e "  ${DIM}Config${NC}   ${CONFIG_DIR}/agent.env"
echo -e "  ${DIM}Data${NC}     ${DATA_DIR}"
echo -e "  ${DIM}Logs${NC}     ${LOG_DIR}"
echo -e "  ${DIM}Server${NC}   ${RACKPLANE_SERVER}"
echo -e "  ${DIM}Node${NC}     ${RACKPLANE_NODE_ID}"
echo ""
echo -e "  ${DIM}The agent is running and connected to ${RACKPLANE_SERVER}${NC}"
echo -e "${GREEN}  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
fi
