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

log() { echo "[pulse-install] $*"; }
die() { echo "[pulse-install] ERROR: $*" >&2; exit 1; }

if [ "${EUID:-$(id -u)}" -ne 0 ]; then
  die "Run as root (or with sudo)."
fi

read -r -p "Reinstall from scratch (will delete /opt/pulse and ALL volumes)? [y/N]: " WIPE
WIPE="${WIPE:-N}"

PULSE_DIR="/opt/pulse"

if [[ "${WIPE}" =~ ^[Yy]$ ]]; then
  log "Stopping and removing existing Pulse stack (if any)..."
  if [ -d "${PULSE_DIR}" ]; then
    cd "${PULSE_DIR}" || true
    if [ -f docker-compose.su pawse.yml ]; then
      true
    fi
    if [ -f docker-compose-supabase.yml ]; then
      COMPOSE_FILES="-f docker-compose-supabase.yml"
      if [ -f docker-compose.override.yml ]; then
        COMPOSE_FILES="$COMPOSE_FILES -f docker-compose.override.yml"
      fi
      if [ -f docker-compose.noise.yml ]; then
        COMPOSE_FILES="$COMPOSE_FILES -f docker-compose.noise.yml"
      fi
      docker compose $COMPOSE_FILES down -v --remove-orphans || true
    fi
  fi
  rm -rf "${PULSE_DIR}"
fi

read -r -p "Domain for Pulse (e.g. chat.example.com): " DOMAIN
if [ -z "${DOMAIN}" ]; then
  die "Domain is required."
fi

read -r -p "Enable Caddy HTTPS proxy? [y/N]: " ENABLE_CADDY
ENABLE_CADDY="${ENABLE_CADDY:-N}"
if [[ "${ENABLE_CADDY}" =~ ^[Yy]$ ]]; then
  read -r -p "TLS email (for Let's Encrypt): " TLS_EMAIL
  if [ -z "${TLS_EMAIL}" ]; then
    die "TLS email is required when enabling Caddy."
  fi
fi

read -r -p "Postgres password (leave blank to generate): " POSTGRES_PASSWORD
if [ -z "${POSTGRES_PASSWORD}" ]; then
  POSTGRES_PASSWORD="$(openssl rand -hex 16)"
  log "Generated Postgres password: ${POSTGRES_PASSWORD}"
fi

read -r -p "Pulse port [4991]: " PULSE_PORT
PULSE_PORT="${PULSE_PORT:-4991}"

read -r -p "Public IP (optional; leave blank to auto-detect): " PUBLIC_IP
if [ -z "${PUBLIC_IP}" ]; then
  PUBLIC_IP="$(curl -fsSL https://api.ipify.org || true)"
  if [ -n "${PUBLIC_IP}" ]; then
    log "Detected public IP: ${PUBLIC_IP}"
  else
    log "Public IP not set."
  fi
fi

log "Installing base packages..."
apt-get update -y
apt-get install -y ca-certificates curl gnupg git ufw openssl

if ! command -v docker >/dev/null 2>&1; then
  log "Installing Docker..."
  install -m 0755 -d /etc/apt/keyrings
  curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
  chmod a+r /etc/apt/keyrings/docker.gpg
  . /etc/os-release
  echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian ${VERSION_CODENAME} stable" \
    | tee /etc/apt/sources.list.d/docker.list > /dev/null
  apt-get update -y
  apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
fi

if ! command -v bun >/dev/null 2>&1; then
  log "Installing Bun..."
  curl -fsSL https://bun.sh/install | bash
fi

export BUN_INSTALL="${BUN_INSTALL:-/root/.bun}"
export PATH="${BUN_INSTALL}/bin:${PATH}"

log "Cloning Pulse..."
mkdir -p "${PULSE_DIR}"
if [ -d "${PULSE_DIR}/.git" ]; then
  git -C "${PULSE_DIR}" fetch --all --prune
  git -C "${PULSE_DIR}" reset --hard origin/main
else
  git clone https://github.com/plsechat/pulse-chat.git "${PULSE_DIR}"
fi

cd "${PULSE_DIR}"

log "Generating JWT and Supabase keys..."
KEY_OUTPUT="$(bun docker/generate-keys.ts)"
JWT_SECRET="$(echo "${KEY_OUTPUT}" | grep -E '^JWT_SECRET=' | head -n1 | cut -d'=' -f2-)"
SUPABASE_ANON_KEY="$(echo "${KEY_OUTPUT}" | grep -E '^SUPABASE_ANON_KEY=' | head -n1 | cut -d'=' -f2-)"
SUPABASE_SERVICE_ROLE_KEY="$(echo "${KEY_OUTPUT}" | grep -E '^SUPABASE_SERVICE_ROLE_KEY=' | head -n1 | cut -d'=' -f2-)"

if [ -z "${JWT_SECRET}" ] || [ -z "${SUPABASE_ANON_KEY}" ] || [ -z "${SUPABASE_SERVICE_ROLE_KEY}" ]; then
  die "Failed to parse generated keys."
fi

log "Writing .env..."
cp -f .env.supabase.example .env

sed -i \
  -e "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=${POSTGRES_PASSWORD}|" \
  -e "s|^JWT_SECRET=.*|JWT_SECRET=${JWT_SECRET}|" \
  -e "s|^SUPABASE_ANON_KEY=.*|SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}|" \
  -e "s|^SUPABASE_SERVICE_ROLE_KEY=.*|SUPABASE_SERVICE_ROLE_KEY=${SUPABASE_SERVICE_ROLE_KEY}|" \
  -e "s|^SITE_URL=.*|SITE_URL=https://${DOMAIN}|" \
  .env

if [ -n "${PUBLIC_IP}" ]; then
  if grep -q '^PUBLIC_IP=' .env; then
    sed -i "s|^PUBLIC_IP=.*|PUBLIC_IP=${PUBLIC_IP}|" .env
  else
    echo "PUBLIC_IP=${PUBLIC_IP}" >> .env
  fi
fi

if grep -q '^PULSE_PORT=' .env; then
  sed -i "s|^PULSE_PORT=.*|PULSE_PORT=${PULSE_PORT}|" .env
else
  echo "PULSE_PORT=${PULSE_PORT}" >> .env
fi

if [[ "${ENABLE_CADDY}" =~ ^[Yy]$ ]]; then
  log "Writing Caddyfile and compose override..."
  cat > "${PULSE_DIR}/Caddyfile" <<EOF
${DOMAIN} {
  encode gzip
  reverse_proxy pulse:4991
  tls ${TLS_EMAIL}
}
EOF

  cat > "${PULSE_DIR}/docker-compose.override.yml" <<'EOF'
services:
  caddy:
    image: caddy:2
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
volumes:
  caddy_data:
  caddy_config:
EOF
else
  rm -f "${PULSE_DIR}/docker-compose.override.yml" "${PULSE_DIR}/Caddyfile" || true
fi

log "Configuring firewall (ufw)..."
ufw allow OpenSSH >/dev/null 2>&1 || true
if [[ "${ENABLE_CADDY}" =~ ^[Yy]$ ]]; then
  ufw allow 80/tcp >/dev/null 2>&1 || true
  ufw allow 443/tcp >/dev/null 2>&1 || true
  ufw allow 443/udp >/dev/null 2>&1 || true
else
  ufw allow "${PULSE_PORT}/tcp" >/dev/null 2>&1 || true
fi
ufw allow 40000:40020/tcp >/dev/null 2>&1 || true
ufw allow 40000:40020/udp >/dev/null 2>&1 || true
ufw --force enable >/dev/null 2>&1 || true

log "Starting Pulse (Supabase stack)..."
COMPOSE_FILES="-f docker-compose-supabase.yml"
if [ -f docker-compose.override.yml ]; then
  COMPOSE_FILES="$COMPOSE_FILES -f docker-compose.override.yml"
fi

docker compose $COMPOSE_FILES up -d --build

log "Done."
if [[ "${ENABLE_CADDY}" =~ ^[Yy]$ ]]; then
  log "Pulse: https://${DOMAIN}"
else
  log "Pulse: http://${DOMAIN}:${PULSE_PORT}"
fi
log "If this is the first run, watch logs to get the security token:"
log "  docker logs -f pulse | head -n 200"
