#!/usr/bin/env bash
# SEO Insight — VPS bootstrap (run ONCE, as root). Does INSTALL.md §2–§3:
# base packages + UFW + Docker + Bun/Rust toolchains + PostgreSQL.
#
# Multi-disk aware: this box has a small `/` (~20 G) and a big `/data` (~213 G,
# RAID1). ALL heavy/growing state is placed on /data so `/` never fills:
#   • Docker images + volumes  → /data/docker     (the 8-container Firecrawl stack)
#   • app PostgreSQL data       → /data/postgres
#   • Firecrawl volumes         → /data/firecrawl/{redis,rabbitmq,postgres}
# (The app code in /opt/seo-insight stays on `/` — a few GB of build artifacts.)
#
#   sudo bash deploy/bootstrap.sh
#   sudo DB_PASSWORD='choose-one' bash deploy/bootstrap.sh   # else one is generated
set -euo pipefail

[ "$(id -u)" -eq 0 ] || { echo "Run as root: sudo bash deploy/bootstrap.sh"; exit 1; }

DATA=/data
# 256-bit (64 hex chars) — URL-safe for DATABASE_URL, no shell/psql escaping.
DB_PASSWORD="${DB_PASSWORD:-$(openssl rand -hex 32)}"
export DEBIAN_FRONTEND=noninteractive

echo "▸ /data partition check…"
if ! mountpoint -q "$DATA"; then
  echo "  ⚠  $DATA is NOT a separate mountpoint. Heavy data would land on '/'."
  echo "     Mount the big partition at /data first (see the installer's /data Ext4)."
  echo "     Continuing in 5s — Ctrl-C to abort."
  sleep 5
fi

echo "▸ Base packages (+ hardening: fail2ban, auto security updates)…"
apt update && apt upgrade -y
apt install -y git curl unzip build-essential pkg-config libssl-dev ufw ca-certificates \
               fail2ban unattended-upgrades
# Unattended security upgrades + brute-force protection on SSH.
dpkg-reconfigure -f noninteractive unattended-upgrades || true
systemctl enable --now fail2ban

echo "▸ App user 'seoinsight'…"
id seoinsight &>/dev/null ||
  adduser --system --group --home /home/seoinsight --shell /bin/bash seoinsight

echo "▸ Data dirs on $DATA…"
mkdir -p "$DATA"/docker "$DATA"/postgres \
         "$DATA"/firecrawl/redis "$DATA"/firecrawl/rabbitmq "$DATA"/firecrawl/postgres
chown -R seoinsight:seoinsight "$DATA"/firecrawl

# App build artifacts (node_modules, .next, cargo target ≈ 5-6 G) must NOT land on
# the small '/'. Keep the canonical /opt/seo-insight path but back it by /data via
# a symlink, so the systemd units / deploy.sh paths are unchanged.
echo "▸ App dir → $DATA/seo-insight (symlinked at /opt/seo-insight)…"
mkdir -p "$DATA"/seo-insight
chown seoinsight:seoinsight "$DATA"/seo-insight
ln -sfn "$DATA"/seo-insight /opt/seo-insight

# Firewall. UFW uses the iptables-nft backend (Ubuntu default) — supported by
# Docker; we never write raw `nft` rules. CAVEAT: Docker-published ports bypass
# UFW (they go through the DOCKER chain, not INPUT). That's harmless here because
# the ONLY published port is Firecrawl's api, bound to 127.0.0.1:3002 — nothing
# Docker-managed is reachable from outside. If you ever publish a container on
# 0.0.0.0, filter it in the DOCKER-USER chain, NOT via UFW.
echo "▸ Firewall — SSH (rate-limited) + HTTP/HTTPS…"
ufw limit OpenSSH          # rate-limit SSH to blunt brute-force
ufw allow 80/tcp           # Let's Encrypt HTTP-01 challenge + http→https redirect
ufw allow 443/tcp
ufw --force enable

echo "▸ Docker (official apt repo; data-root → $DATA/docker)…"
if ! command -v docker &>/dev/null; then
  # Docker's official GPG key
  install -m 0755 -d /etc/apt/keyrings
  curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
  chmod a+r /etc/apt/keyrings/docker.asc
  # Apt source (deb822) — codename detected from the running Ubuntu
  tee /etc/apt/sources.list.d/docker.sources >/dev/null <<DOCKER_SRC
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
DOCKER_SRC
  apt update
  apt install -y docker-ce docker-ce-cli containerd.io \
                 docker-buildx-plugin docker-compose-plugin
fi
# Pin the data-root to /data so images/volumes don't fill the small '/'.
mkdir -p /etc/docker
cat > /etc/docker/daemon.json <<JSON
{ "data-root": "$DATA/docker" }
JSON
systemctl enable docker
systemctl restart docker
usermod -aG docker seoinsight

echo "▸ Bun + Rust + wasm-pack (as seoinsight)…"
sudo -u seoinsight -i bash <<'EOF'
set -e
# Bun (prebuilt binary; needs unzip, installed above)
command -v "$HOME/.bun/bin/bun" >/dev/null 2>&1 || curl -fsSL https://bun.sh/install | bash
# Rust toolchain
[ -d "$HOME/.cargo" ] || curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source "$HOME/.cargo/env"
# Resilient crates.io downloads for the project builds (build:wasm + gsc-worker).
mkdir -p "$HOME/.cargo"
grep -q 'retry = 10' "$HOME/.cargo/config.toml" 2>/dev/null || cat >> "$HOME/.cargo/config.toml" <<CARGO
[net]
retry = 10
[http]
multiplexing = false
CARGO
# wasm-pack — PREBUILT binary (no cargo compile → avoids the crates.io reset).
command -v wasm-pack >/dev/null 2>&1 || curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
EOF

echo "▸ PostgreSQL (cluster data → $DATA/postgres)…"
apt install -y postgresql postgresql-contrib
PGVER=$(ls /etc/postgresql | sort -V | tail -1)
if [ ! -d "$DATA/postgres/$PGVER/main" ]; then
  systemctl stop postgresql 2>/dev/null || true
  # Drop the default cluster apt created on '/'. It's already stopped, so do NOT
  # pass --stop — that re-stop errors "not running" and aborts the drop.
  pg_dropcluster "$PGVER" main 2>/dev/null || true
  pg_createcluster -d "$DATA/postgres/$PGVER/main" "$PGVER" main
  systemctl start postgresql
fi

echo "▸ Role + database (idempotent)…"
sudo -u postgres psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='seoinsight'" | grep -q 1 ||
  sudo -u postgres psql -c "CREATE ROLE seoinsight LOGIN PASSWORD '$DB_PASSWORD';"
sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname='seo_insight'" | grep -q 1 ||
  sudo -u postgres psql -c "CREATE DATABASE seo_insight OWNER seoinsight;"

echo
echo "✓ Bootstrap done (Postgres ${PGVER} on $DATA/postgres, Docker on $DATA/docker)."
echo
echo "  DATABASE_URL for /opt/seo-insight/.env.production (first run):"
echo "    DATABASE_URL=postgresql://seoinsight:${DB_PASSWORD}@localhost:5432/seo_insight"
echo
echo "  Hardening done: UFW (SSH rate-limited + 443), fail2ban, auto security"
echo "  upgrades. RECOMMENDED next — switch SSH to key-only (after confirming your"
echo "  key works), then: sudo sed -i 's/^#\\?PasswordAuthentication.*/PasswordAuthentication no/'"
echo "  /etc/ssh/sshd_config && sudo systemctl reload ssh"
echo
echo "  Next: INSTALL.md §4 (clone) → §5 (.env) → §6 (Firecrawl) → §7 build →"
echo "        §8 systemd → §9 Nginx."
