#!/bin/sh
set -eu

INSTALL_DIR="/opt/libreqos-endpoint"
HOSTNAME_VALUE=""
ENROLLMENT_TOKEN=""
CONTROL_URL="https://api-bufferbloat.libreqos.com"

usage() {
    printf '%s\n' "Usage: install.sh --hostname libreqos.example.com --token lqep_enroll_..."
}

while [ "$#" -gt 0 ]; do
    case "$1" in
        --hostname)
            HOSTNAME_VALUE="${2:-}"
            shift 2
            ;;
        --token)
            ENROLLMENT_TOKEN="${2:-}"
            shift 2
            ;;
        --control-url)
            CONTROL_URL="${2:-}"
            shift 2
            ;;
        --install-dir)
            INSTALL_DIR="${2:-}"
            shift 2
            ;;
        *)
            usage
            exit 2
            ;;
    esac
done

if [ "$(id -u)" -ne 0 ]; then
    printf '%s\n' "Run this installer through sudo." >&2
    exit 1
fi

case "$HOSTNAME_VALUE" in
    ""|*[!A-Za-z0-9.-]*|.*|*..*|*.)
        printf '%s\n' "A valid dedicated hostname is required." >&2
        exit 1
        ;;
esac

case "$ENROLLMENT_TOKEN" in
    lqep_enroll_*) ;;
    *)
        printf '%s\n' "A valid one-time enrollment token is required." >&2
        exit 1
        ;;
esac

if [ ! -f /etc/os-release ]; then
    printf '%s\n' "This installer supports Linux hosts with Docker Engine." >&2
    exit 1
fi

if ! command -v curl >/dev/null 2>&1; then
    apt-get update
    DEBIAN_FRONTEND=noninteractive apt-get install -y curl ca-certificates
fi

install_docker() {
    . /etc/os-release
    case "${ID:-}" in
        debian|ubuntu) ;;
        *)
            printf '%s\n' "Automatic Docker installation supports Debian and Ubuntu." >&2
            printf '%s\n' "Install Docker Engine with the Compose plugin, then run this command again." >&2
            exit 1
            ;;
    esac
    apt-get update
    DEBIAN_FRONTEND=noninteractive apt-get install -y ca-certificates curl
    install -m 0755 -d /etc/apt/keyrings
    curl -fsSL "https://download.docker.com/linux/$ID/gpg" \
        -o /etc/apt/keyrings/docker.asc
    chmod a+r /etc/apt/keyrings/docker.asc
    arch="$(dpkg --print-architecture)"
    codename="${VERSION_CODENAME:-}"
    if [ -z "$codename" ]; then
        printf '%s\n' "Unable to determine the operating system codename." >&2
        exit 1
    fi
    printf '%s\n' \
        "deb [arch=$arch signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/$ID $codename stable" \
        >/etc/apt/sources.list.d/docker.list
    apt-get update
    DEBIAN_FRONTEND=noninteractive apt-get install -y \
        docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    systemctl enable --now docker
}

if ! command -v docker >/dev/null 2>&1 || ! docker compose version >/dev/null 2>&1; then
    install_docker
fi

install -d -m 0750 "$INSTALL_DIR"

cat >"$INSTALL_DIR/.env" <<EOF
LIBREQOS_HOSTNAME=$HOSTNAME_VALUE
LIBREQOS_ENROLLMENT_TOKEN=$ENROLLMENT_TOKEN
LIBREQOS_CONTROL_URL=$CONTROL_URL
LIBREQOS_ENDPOINT_IMAGE=ghcr.io/libreqoe/measurement-endpoint:stable
EOF
chmod 0600 "$INSTALL_DIR/.env"

cat >"$INSTALL_DIR/Caddyfile" <<'EOF'
{$LIBREQOS_HOSTNAME} {
	reverse_proxy endpoint:8081
}
EOF

cat >"$INSTALL_DIR/docker-compose.yml" <<'EOF'
services:
  state-init:
    image: alpine:3.22
    container_name: libreqos-state-init
    restart: "no"
    command: ["sh", "-c", "chown -R 1000:1000 /data"]
    volumes:
      - endpoint-state:/data

  endpoint:
    image: ${LIBREQOS_ENDPOINT_IMAGE:-ghcr.io/libreqoe/measurement-endpoint:stable}
    container_name: libreqos-endpoint
    restart: unless-stopped
    depends_on:
      state-init:
        condition: service_completed_successfully
    expose:
      - "8081"
    volumes:
      - endpoint-state:/data
    environment:
      LIBREQOS_PUBLIC_URL: "https://${LIBREQOS_HOSTNAME}"
      LIBREQOS_INSECURE_HTTP: "true"
      LIBREQOS_CONTROL_URL: "${LIBREQOS_CONTROL_URL:-https://api-bufferbloat.libreqos.com}"
      LIBREQOS_ENROLLMENT_TOKEN: "${LIBREQOS_ENROLLMENT_TOKEN}"
      LIBREQOS_UPDATE_CHANNEL: "stable"
    labels:
      wud.watch: "true"
      wud.watch.digest: "true"
      wud.trigger.include: "docker.local"

  caddy:
    image: caddy:2-alpine
    container_name: libreqos-caddy
    restart: unless-stopped
    depends_on:
      - endpoint
    ports:
      - "80:80/tcp"
      - "443:443/tcp"
    environment:
      LIBREQOS_HOSTNAME: "${LIBREQOS_HOSTNAME}"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy-data:/data
      - caddy-config:/config

  updater:
    image: getwud/wud:8.2.2
    container_name: libreqos-updater
    restart: unless-stopped
    environment:
      WUD_WATCHER_LOCAL_WATCHBYDEFAULT: "false"
      WUD_WATCHER_LOCAL_CRON: "*/5 * * * *"
      WUD_TRIGGER_DOCKER_LOCAL_AUTO: "true"
      WUD_TRIGGER_DOCKER_LOCAL_PRUNE: "true"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

volumes:
  endpoint-state:
  caddy-data:
  caddy-config:
EOF

cd "$INSTALL_DIR"
docker compose config >/dev/null
docker compose pull
docker compose up -d

printf '%s\n' "Waiting for HTTPS and control-plane enrollment..."
enrolled="false"
attempt=0
while [ "$attempt" -lt 60 ]; do
    attempt=$((attempt + 1))
    health="$(curl -fsS --max-time 5 "https://$HOSTNAME_VALUE/health" 2>/dev/null || true)"
    if printf '%s' "$health" | grep -q '"enrolled":true'; then
        enrolled="true"
        break
    fi
    sleep 2
done

if [ "$enrolled" = "true" ]; then
    sed -i 's/^LIBREQOS_ENROLLMENT_TOKEN=.*/LIBREQOS_ENROLLMENT_TOKEN=/' "$INSTALL_DIR/.env"
    docker compose up -d --force-recreate endpoint
    printf '%s\n' "LibreQoS endpoint enrolled successfully."
    printf '%s\n' "Status: https://$HOSTNAME_VALUE/health"
else
    printf '%s\n' "The containers are running, but enrollment was not confirmed." >&2
    printf '%s\n' "Confirm DNS-only resolution and inbound TCP 80/443, then run:" >&2
    printf '%s\n' "  cd $INSTALL_DIR && docker compose logs --tail=100 caddy endpoint" >&2
    exit 1
fi
