#!/usr/bin/env bash
# =============================================================================
#  OrthoGlobe server provisioning — native services (no Docker)
# =============================================================================
#  Stack installed:
#    - Node.js 22 LTS (NodeSource)
#    - pnpm (via corepack)
#    - PostgreSQL 16 (PGDG)
#    - Redis 7 (Ubuntu default)
#    - Caddy 2 (official repo)
#    - systemd unit for the Next.js app
#    - UFW + Fail2ban + automatic security updates
#
#  Safe to re-run. First run WIPES everything orthoglobe-related so you
#  start from a known-clean state.
#
#  Run as root:   bash remote-provision.sh
# =============================================================================
set -euo pipefail

if [[ $EUID -ne 0 ]]; then echo "Run as root" >&2; exit 1; fi

DEPLOY_USER="${DEPLOY_USER:-deploy}"
APP_HOME="/home/$DEPLOY_USER/orthoglobe"
APP_DB_NAME="${APP_DB_NAME:-orthoglobe}"
APP_DB_USER="${APP_DB_USER:-orthoglobe}"
APP_DB_PASSWORD="${APP_DB_PASSWORD:-}"  # Will be generated if blank
SERVER_IP="$(hostname -I | awk '{print $1}')"
DEFAULT_DOMAIN="${DEFAULT_DOMAIN:-${SERVER_IP//./-}.nip.io}"

export DEBIAN_FRONTEND=noninteractive

log()  { printf '\n\033[1;34m>>> %s\033[0m\n' "$*"; }
warn() { printf '\033[1;33m!!! %s\033[0m\n' "$*"; }

# -----------------------------------------------------------------------------
# 1. Wipe anything that might conflict with our stack
# -----------------------------------------------------------------------------
log "WIPE: stopping old services + removing previous installs"

# Stop any orthoglobe-related services first.
for unit in orthoglobe.service orthoglobe-web.service orthoglobe-app.service; do
  systemctl disable --now "$unit" 2>/dev/null || true
  rm -f "/etc/systemd/system/$unit"
done
systemctl daemon-reload

# Purge Docker so it can't hold ports 80/443 or compete for resources.
# Previous tenants (e.g. Coolify) may have left containers running — kill
# containers BEFORE stopping the daemon, then purge packages + flush the
# docker iptables chains so UFW/Caddy can bind freely afterwards.
if command -v docker >/dev/null 2>&1 || dpkg -l 2>/dev/null | grep -qE '^ii\s+(docker|containerd)'; then
  warn "Removing Docker + all containers/images/volumes/networks"
  docker ps -aq 2>/dev/null | xargs -r docker rm -f 2>/dev/null || true
  docker volume ls -q 2>/dev/null | xargs -r docker volume rm -f 2>/dev/null || true
  docker network ls --filter type=custom -q 2>/dev/null | xargs -r docker network rm 2>/dev/null || true
  systemctl disable --now docker.socket docker.service containerd.service 2>/dev/null || true
  # docker-compose-v2, docker.io, docker-ce, docker-ce-rootless-extras, containerd.io, containerd, runc
  apt-get purge -y -qq \
    docker-compose-v2 docker-compose docker-compose-plugin \
    docker.io docker-ce docker-ce-cli docker-ce-rootless-extras docker-buildx-plugin \
    containerd.io containerd runc 2>/dev/null || true
  rm -rf /var/lib/docker /var/lib/containerd /etc/docker /root/.docker
  # Flush docker iptables chains so they don't linger and block UFW rules.
  for chain in DOCKER DOCKER-USER DOCKER-FORWARD DOCKER-ISOLATION-STAGE-1 DOCKER-ISOLATION-STAGE-2 DOCKER-INGRESS; do
    iptables -F "$chain" 2>/dev/null || true
    iptables -X "$chain" 2>/dev/null || true
  done
  iptables -t nat -F DOCKER 2>/dev/null || true
  iptables -t nat -X DOCKER 2>/dev/null || true
fi

# Remove any other webserver that would grab ports 80/443.
apt-get purge -y -qq nginx apache2 lighttpd 2>/dev/null || true

# Pre-existing postgres / redis / caddy / nodejs — fully purge + remove data.
# We want a known-clean state.
for pkg in \
    postgresql postgresql-contrib postgresql-16 postgresql-client \
    postgresql-client-16 postgresql-common \
    redis redis-server redis-tools \
    caddy \
    nodejs npm; do
  if dpkg -l 2>/dev/null | grep -q "^ii\s\+$pkg\b"; then
    apt-get purge -y -qq "$pkg" 2>/dev/null || true
  fi
done
apt-get autoremove -y -qq
apt-get autoclean -y -qq

rm -rf /var/lib/postgresql /etc/postgresql /var/lib/redis /etc/redis \
       /etc/caddy /var/lib/caddy

# Clean the prior deploy user's tree.
if id -u "$DEPLOY_USER" >/dev/null 2>&1; then
  rm -rf "/home/$DEPLOY_USER/orthoglobe"
fi

# -----------------------------------------------------------------------------
# 2. Base tooling
# -----------------------------------------------------------------------------
log "Updating package lists + installing base tools"
apt-get update -qq
apt-get install -y -qq \
  curl gnupg ca-certificates lsb-release apt-transport-https \
  build-essential python3 git rsync htop tmux \
  ufw fail2ban unattended-upgrades \
  pwgen

dpkg-reconfigure -f noninteractive unattended-upgrades

# -----------------------------------------------------------------------------
# 3. Deploy user
# -----------------------------------------------------------------------------
log "Creating deploy user '$DEPLOY_USER'"
if ! id -u "$DEPLOY_USER" >/dev/null 2>&1; then
  adduser --disabled-password --gecos "OrthoGlobe deploy" "$DEPLOY_USER"
fi
usermod -aG sudo "$DEPLOY_USER"
mkdir -p "/home/$DEPLOY_USER/.ssh"
chmod 700 "/home/$DEPLOY_USER/.ssh"
if [[ -f /root/.ssh/authorized_keys ]]; then
  cp /root/.ssh/authorized_keys "/home/$DEPLOY_USER/.ssh/"
fi
chown -R "$DEPLOY_USER:$DEPLOY_USER" "/home/$DEPLOY_USER/.ssh"
chmod 600 "/home/$DEPLOY_USER/.ssh/authorized_keys" 2>/dev/null || true
echo "$DEPLOY_USER ALL=(ALL) NOPASSWD:ALL" > "/etc/sudoers.d/90-$DEPLOY_USER"
chmod 440 "/etc/sudoers.d/90-$DEPLOY_USER"

mkdir -p "$APP_HOME"
chown -R "$DEPLOY_USER:$DEPLOY_USER" "/home/$DEPLOY_USER"

# -----------------------------------------------------------------------------
# 4. Node.js 22 LTS
# -----------------------------------------------------------------------------
log "Installing Node.js 22 + pnpm"
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt-get install -y -qq nodejs
corepack enable
# Install pnpm globally (reliable when package.json pins a specific pnpm).
npm install -g --force pnpm@latest

# -----------------------------------------------------------------------------
# 5. PostgreSQL 16 (PGDG)
# -----------------------------------------------------------------------------
log "Installing PostgreSQL 16"
install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc \
  | gpg --dearmor -o /etc/apt/keyrings/pgdg.gpg
chmod a+r /etc/apt/keyrings/pgdg.gpg
echo "deb [signed-by=/etc/apt/keyrings/pgdg.gpg] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" \
  > /etc/apt/sources.list.d/pgdg.list
apt-get update -qq
apt-get install -y -qq postgresql-16 postgresql-client-16
systemctl enable --now postgresql

if [[ -z "$APP_DB_PASSWORD" ]]; then
  APP_DB_PASSWORD="$(pwgen -s 32 1)"
fi

# Idempotent role + database creation.
sudo -u postgres psql -v ON_ERROR_STOP=1 <<SQL
DO \$\$
BEGIN
  IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='$APP_DB_USER') THEN
    CREATE ROLE $APP_DB_USER LOGIN PASSWORD '$APP_DB_PASSWORD';
  ELSE
    ALTER ROLE $APP_DB_USER WITH PASSWORD '$APP_DB_PASSWORD';
  END IF;
END \$\$;
SQL

if ! sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname='$APP_DB_NAME'" | grep -q 1; then
  sudo -u postgres createdb -O "$APP_DB_USER" "$APP_DB_NAME"
fi
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE $APP_DB_NAME TO $APP_DB_USER;" >/dev/null

# -----------------------------------------------------------------------------
# 6. Redis
# -----------------------------------------------------------------------------
log "Installing Redis"
apt-get install -y -qq redis-server
# Bind to localhost only.
sed -i 's/^# *bind .*/bind 127.0.0.1 ::1/' /etc/redis/redis.conf
sed -i 's/^# *protected-mode .*/protected-mode yes/' /etc/redis/redis.conf
systemctl enable --now redis-server

# -----------------------------------------------------------------------------
# 7. Caddy 2
# -----------------------------------------------------------------------------
log "Installing Caddy 2"
curl -fsSL 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
  | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -fsSL 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
  > /etc/apt/sources.list.d/caddy-stable.list
apt-get update -qq
apt-get install -y -qq caddy

# -----------------------------------------------------------------------------
# 8. Firewall
# -----------------------------------------------------------------------------
log "Configuring UFW"
ufw --force reset
ufw default deny incoming
ufw default allow outgoing
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 443/udp
echo y | ufw enable
systemctl enable --now fail2ban

# -----------------------------------------------------------------------------
# 9. Swap (2 GB if none exists)
# -----------------------------------------------------------------------------
if ! swapon --show | grep -q '/'; then
  log "Creating 2 GB swap file"
  fallocate -l 2G /swapfile
  chmod 600 /swapfile
  mkswap /swapfile
  swapon /swapfile
  echo '/swapfile none swap sw 0 0' >> /etc/fstab
fi

# -----------------------------------------------------------------------------
# 10. Write the DB password to /etc/orthoglobe.env for the app
# -----------------------------------------------------------------------------
mkdir -p /etc/orthoglobe
cat > /etc/orthoglobe/db.env <<ENV
# Written by provision.sh — consumed by /etc/orthoglobe/app.env
POSTGRES_USER=$APP_DB_USER
POSTGRES_PASSWORD=$APP_DB_PASSWORD
POSTGRES_DB=$APP_DB_NAME
DATABASE_URL=postgres://$APP_DB_USER:$APP_DB_PASSWORD@127.0.0.1:5432/$APP_DB_NAME
REDIS_URL=redis://127.0.0.1:6379
ENV
chmod 640 /etc/orthoglobe/db.env
chown root:"$DEPLOY_USER" /etc/orthoglobe/db.env

echo "$DEFAULT_DOMAIN" > /etc/orthoglobe/domain

cat <<EOF

========================================================
 Provisioning complete.

 Node:       $(node --version)
 pnpm:       $(pnpm --version 2>/dev/null)
 Postgres:   $(sudo -u postgres psql -tAc 'SELECT version()' | head -c 40)
 Redis:      $(redis-cli --version)
 Caddy:      $(caddy version | head -1)

 DB user:    $APP_DB_USER
 DB name:    $APP_DB_NAME
 DB pass:    written to /etc/orthoglobe/db.env (mode 640)

 Default domain (change later): $DEFAULT_DOMAIN

 Next: upload the app source to $APP_HOME and run
       deploy/scripts/remote-app-start.sh
========================================================
EOF
