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

# Sot Lab Authentik + Ampache bootstrap for webpi.
# Run on webpi with sudo: sudo bash deploy-sotlab-auth-music.sh
# Safe defaults:
# - NAS music is mounted read-only.
# - Docker services bind to 127.0.0.1 only.
# - Cloudflare/Caddy public routing is NOT changed by this script.
# - Existing Sot Lab users/profile gate remains untouched.

if [[ ${EUID} -ne 0 ]]; then
  echo "ERROR: run as root: sudo bash $0" >&2
  exit 1
fi

export DEBIAN_FRONTEND=noninteractive

APP_ROOT=/srv/apps
AUTH_DIR=${APP_ROOT}/sotlab-authentik
MUSIC_DIR=${APP_ROOT}/sotlab-music
SECRETS_DIR=${APP_ROOT}/sotlab-secrets
NAS_MOUNT=/mnt/main_nas_music
NAS_SHARE='//192.168.1.64/Music'
ADMIN_UID=1000
ADMIN_GID=1000

mkdir -p "$AUTH_DIR" "$MUSIC_DIR" "$SECRETS_DIR" "$NAS_MOUNT"
chmod 700 "$SECRETS_DIR"

apt-get update
apt-get install -y ca-certificates curl gnupg cifs-utils docker.io docker-compose
systemctl enable --now docker

compose() {
  if docker compose version >/dev/null 2>&1; then
    docker compose "$@"
  else
    docker-compose "$@"
  fi
}

# Mount NAS Music read-only through Samba guest share.
FSTAB_LINE="${NAS_SHARE} ${NAS_MOUNT} cifs guest,ro,iocharset=utf8,nofail,_netdev,x-systemd.automount,uid=${ADMIN_UID},gid=${ADMIN_GID},file_mode=0444,dir_mode=0555 0 0"
if ! grep -Fq "${NAS_SHARE} ${NAS_MOUNT} cifs" /etc/fstab; then
  cp -a /etc/fstab "/etc/fstab.sotlab.$(date +%Y%m%d-%H%M%S).bak"
  printf '\n# Sot Lab Music NAS mount — managed by deploy-sotlab-auth-music.sh\n%s\n' "$FSTAB_LINE" >> /etc/fstab
fi
systemctl daemon-reload
mount "$NAS_MOUNT" || true

if ! mountpoint -q "$NAS_MOUNT"; then
  echo "ERROR: NAS music mount failed at $NAS_MOUNT" >&2
  echo "Check that //192.168.1.64/Music is reachable from webpi." >&2
  exit 1
fi

# Generate secrets only once.
secret() { openssl rand -base64 48 | tr -d '\n'; }

if [[ ! -f "$AUTH_DIR/.env" ]]; then
  AUTH_PG_PASS=$(secret)
  AUTH_SECRET=$(secret)
  AUTH_BOOTSTRAP_PASSWORD=$(openssl rand -base64 24 | tr -d '\n')
  cat > "$AUTH_DIR/.env" <<EOF_ENV
PG_DB=authentik
PG_USER=authentik
PG_PASS=${AUTH_PG_PASS}
AUTHENTIK_SECRET_KEY=${AUTH_SECRET}
AUTHENTIK_TAG=2026.8.0
COMPOSE_PORT_HTTP=127.0.0.1:9000
COMPOSE_PORT_HTTPS=127.0.0.1:9443
AUTHENTIK_BOOTSTRAP_EMAIL=sott@sotlab.co.uk
AUTHENTIK_BOOTSTRAP_PASSWORD=${AUTH_BOOTSTRAP_PASSWORD}
EOF_ENV
  chmod 600 "$AUTH_DIR/.env"
  cat > "$SECRETS_DIR/authentik-bootstrap.txt" <<EOF_AUTH
Authentik bootstrap admin:
URL after routing: https://auth.sotlab.co.uk/
Local URL on webpi: http://127.0.0.1:9000/
Username/email: sott@sotlab.co.uk
Password: ${AUTH_BOOTSTRAP_PASSWORD}
EOF_AUTH
  chmod 600 "$SECRETS_DIR/authentik-bootstrap.txt"
fi

cat > "$AUTH_DIR/compose.yml" <<'EOF_COMPOSE_AUTH'
services:
  postgresql:
    image: docker.io/library/postgres:16-alpine
    restart: unless-stopped
    env_file:
      - .env
    environment:
      POSTGRES_DB: ${PG_DB:-authentik}
      POSTGRES_PASSWORD: ${PG_PASS:?database password required}
      POSTGRES_USER: ${PG_USER:-authentik}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
      start_period: 20s
      interval: 30s
      retries: 5
      timeout: 5s
    volumes:
      - database:/var/lib/postgresql/data

  server:
    image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG:-2026.8.0}
    command: server
    restart: unless-stopped
    depends_on:
      postgresql:
        condition: service_healthy
    env_file:
      - .env
    environment:
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
      AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
    ports:
      - ${COMPOSE_PORT_HTTP:-127.0.0.1:9000}:9000
      - ${COMPOSE_PORT_HTTPS:-127.0.0.1:9443}:9443
    shm_size: 512mb
    volumes:
      - ./data:/data
      - ./custom-templates:/templates

  worker:
    image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG:-2026.8.0}
    command: worker
    restart: unless-stopped
    depends_on:
      postgresql:
        condition: service_healthy
    env_file:
      - .env
    environment:
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
      AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
    user: root
    shm_size: 512mb
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./data:/data
      - ./certs:/certs
      - ./custom-templates:/templates

volumes:
  database:
EOF_COMPOSE_AUTH

if [[ ! -f "$MUSIC_DIR/.env" ]]; then
  AMP_DB_ROOT=$(secret)
  AMP_DB_PASS=$(secret)
  AMP_ADMIN_PASS=$(openssl rand -base64 24 | tr -d '\n')
  cat > "$MUSIC_DIR/.env" <<EOF_ENV
DB_HOST=db
DB_PORT=3306
DB_NAME=ampache
DB_USER=root
DB_PASSWORD=${AMP_DB_ROOT}
AMPACHE_DB_USER=ampache
AMPACHE_DB_PASSWORD=${AMP_DB_PASS}
AMPACHE_ADMIN_USER=sott
AMPACHE_ADMIN_PASSWORD=${AMP_ADMIN_PASS}
AMPACHE_ADMIN_EMAIL=sott@sotlab.co.uk
DISABLE_INOTIFYWAIT_CLEAN=0
EOF_ENV
  chmod 600 "$MUSIC_DIR/.env"
  cat > "$SECRETS_DIR/ampache-bootstrap.txt" <<EOF_AMP
Ampache bootstrap admin:
URL after routing: https://music.sotlab.co.uk/
Local URL on webpi: http://127.0.0.1:9001/
Username: sott
Password: ${AMP_ADMIN_PASS}
Initial catalog path inside Ampache container: /media
EOF_AMP
  chmod 600 "$SECRETS_DIR/ampache-bootstrap.txt"
fi

cat > "$MUSIC_DIR/compose.yml" <<'EOF_COMPOSE_MUSIC'
services:
  db:
    image: mariadb:lts
    restart: unless-stopped
    env_file:
      - .env
    environment:
      MARIADB_ROOT_PASSWORD: ${DB_PASSWORD:?database root password required}
      MARIADB_DATABASE: ${DB_NAME:-ampache}
      MARIADB_USER: ${AMPACHE_DB_USER:-ampache}
      MARIADB_PASSWORD: ${AMPACHE_DB_PASSWORD:?ampache db password required}
    healthcheck:
      test: ["CMD-SHELL", "healthcheck.sh --connect --innodb_initialized"]
      start_period: 20s
      interval: 30s
      retries: 5
      timeout: 5s
    volumes:
      - db:/var/lib/mysql

  ampache:
    image: ampache/ampache:8.0.1
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    env_file:
      - .env
    environment:
      DB_HOST: ${DB_HOST:-db}
      DB_PORT: ${DB_PORT:-3306}
      DB_NAME: ${DB_NAME:-ampache}
      DB_USER: ${DB_USER:-root}
      DB_PASSWORD: ${DB_PASSWORD}
      AMPACHE_DB_USER: ${AMPACHE_DB_USER:-ampache}
      AMPACHE_DB_PASSWORD: ${AMPACHE_DB_PASSWORD}
      AMPACHE_ADMIN_USER: ${AMPACHE_ADMIN_USER:-sott}
      AMPACHE_ADMIN_PASSWORD: ${AMPACHE_ADMIN_PASSWORD}
      AMPACHE_ADMIN_EMAIL: ${AMPACHE_ADMIN_EMAIL:-sott@sotlab.co.uk}
      DISABLE_INOTIFYWAIT_CLEAN: ${DISABLE_INOTIFYWAIT_CLEAN:-0}
    ports:
      - "127.0.0.1:9001:80"
    volumes:
      - ./log:/var/log/ampache
      - /mnt/main_nas_music:/media:ro

volumes:
  db:
EOF_COMPOSE_MUSIC

mkdir -p "$AUTH_DIR/custom-templates" "$AUTH_DIR/certs" "$MUSIC_DIR/log"
chown -R admin:admin "$AUTH_DIR" "$MUSIC_DIR"

# Pull and start. This can take a while on Raspberry Pi.
compose -f "$AUTH_DIR/compose.yml" --env-file "$AUTH_DIR/.env" up -d
compose -f "$MUSIC_DIR/compose.yml" --env-file "$MUSIC_DIR/.env" up -d

printf '\nWaiting for local HTTP endpoints...\n'
for i in $(seq 1 60); do
  AUTH_CODE=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 3 http://127.0.0.1:9000/if/flow/initial-setup/ || true)
  AMP_CODE=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 3 http://127.0.0.1:9001/ || true)
  printf 'attempt %02d: authentik=%s ampache=%s\n' "$i" "$AUTH_CODE" "$AMP_CODE"
  [[ "$AUTH_CODE" =~ ^(200|302|303|404)$ && "$AMP_CODE" =~ ^(200|302|303)$ ]] && break
  sleep 5
done

printf '\nDocker status:\n'
compose -f "$AUTH_DIR/compose.yml" ps
compose -f "$MUSIC_DIR/compose.yml" ps

printf '\nNAS mount sample:\n'
find "$NAS_MOUNT" -maxdepth 1 -mindepth 1 | sed -n '1,12p'

printf '\nSecrets were stored root-readable at:\n'
printf '  %s/authentik-bootstrap.txt\n' "$SECRETS_DIR"
printf '  %s/ampache-bootstrap.txt\n' "$SECRETS_DIR"
printf '\nPublic Caddy/cloudflared routing was NOT changed.\n'
