#!/bin/sh
# =============================================================================
# Authelia + Authelia-API Container Entrypoint
#
# Starts both services, monitors their health, and handles graceful shutdown.
# Authelia-API runs through a supervisor loop since it is the secondary service.
# =============================================================================
set -e

# --- Configuration defaults (overridable via env) ---
AUTHELIA_CONFIG="${AUTHELIA_CONFIG:-/config/configuration.yml}"
AUTHELIA_API_LISTEN="${AUTHELIA_API_LISTEN:-0.0.0.0:8080}"
AUTHELIA_API_DB="${AUTHELIA_API_DB:-/data/authelia-api.db}"
AUTHELIA_API_LOG_LEVEL="${AUTHELIA_API_LOG_LEVEL:-info}"
AUTHELIA_PORT="${AUTHELIA_PORT:-9091}"

# --- Colors for logging ---
INFO="[INFO]"
WARN="[WARN]"
ERR="[ERROR]"

echo "${INFO} ================================================"
echo "${INFO}  Authelia + Authelia-API Container"
echo "${INFO}  Authelia port:     ${AUTHELIA_PORT}"
echo "${INFO}  API listen:        ${AUTHELIA_API_LISTEN}"
echo "${INFO}  API database:      ${AUTHELIA_API_DB}"
echo "${INFO}  API log level:     ${AUTHELIA_API_LOG_LEVEL}"
echo "${INFO} ================================================"

# --- Signal handler ---
cleanup() {
    echo "${INFO} Shutting down..."
    kill -TERM "${AUTHELIA_PID}" 2>/dev/null || true
    kill -TERM "${API_PID}" 2>/dev/null || true
    wait "${AUTHELIA_PID}" 2>/dev/null || true
    wait "${API_PID}" 2>/dev/null || true
    echo "${INFO} Shutdown complete"
    exit 0
}
trap cleanup TERM INT

# --- Helper: wait for a TCP port to be reachable ---
wait_for_port() {
    local host="$1" port="$2" max_attempts="${3:-30}" interval="${4:-2}"
    echo "${INFO} Waiting for ${host}:${port} to be ready..."
    i=0
    while [ "${i}" -lt "${max_attempts}" ]; do
        if nc -z "${host}" "${port}" 2>/dev/null; then
            echo "${INFO} ${host}:${port} is ready (attempt $((i + 1)))"
            return 0
        fi
        i=$((i + 1))
        sleep "${interval}"
    done
    echo "${ERR} ${host}:${port} not reachable after ${max_attempts} attempts"
    return 1
}

# =============================================================================
# 1. Bootstrap required files
# =============================================================================

# Create empty users database if missing (Authelia requires it to exist)
if [ ! -f "/config/users_database.yml" ]; then
    echo "${INFO} Creating empty users database at /config/users_database.yml"
    echo 'users: {}' > /config/users_database.yml
fi

# Create empty notifications file if missing
if [ ! -f "/config/notifications.yml" ]; then
    echo "${INFO} Creating empty notifications file at /config/notifications.yml"
    touch /config/notifications.yml
fi

# =============================================================================
# 2. Validate / generate configuration
# =============================================================================
if [ ! -f "${AUTHELIA_CONFIG}" ]; then
    echo "${WARN} No Authelia config found at ${AUTHELIA_CONFIG}"
    echo "${WARN} Provide one via volume mount or set AUTHELIA_CONFIG env var"
    echo "${WARN} Starting with a minimal configuration instead..."

    mkdir -p /tmp/authelia-config
    cat > /tmp/authelia-config/configuration.yml << EOF
########################################
# Authelia minimal config — replace me
########################################
server:
  address: tcp://0.0.0.0:${AUTHELIA_PORT}
log:
  level: info
identity_validation:
  reset_password:
    jwt_secret: changeme_changeme_changeme_changeme_changeme
default_redirection_url: https://auth.example.com
totp:
  issuer: authelia
authentication_backend:
  file:
    path: /config/users_database.yml
access_control:
  default_policy: two_factor
  rules:
    - domain: example.com
      policy: bypass
session:
  name: authelia_session
  secret: changeme_changeme_changeme_changeme_changeme
  expiration: 1h
  inactivity: 5m
  remember_me: 1M
  domain: example.com
regulation:
  max_retries: 5
  find_time: 2m
  ban_time: 5m
storage:
  encryption_key: changeme_changeme_changeme_changeme_changeme
  local:
    path: /config/db.sqlite3
notifier:
  filesystem:
    filename: /config/notifications.yml
EOF
    AUTHELIA_CONFIG="/tmp/authelia-config/configuration.yml"
fi

# =============================================================================
# 3. Start Authelia
# =============================================================================
echo "${INFO} Starting Authelia..."
authelia --config "${AUTHELIA_CONFIG}" &
AUTHELIA_PID=$!
echo "${INFO} Authelia started (PID: ${AUTHELIA_PID})"

wait_for_port "127.0.0.1" "${AUTHELIA_PORT}" 30 2 || {
    echo "${ERR} Authelia failed to start within timeout"
    echo "${ERR} Check logs above for configuration errors."
    kill "${AUTHELIA_PID}" 2>/dev/null || true
    exit 1
}

# =============================================================================
# 4. Start Authelia-API
# =============================================================================
echo "${INFO} Starting Authelia-API..."
authelia-api \
    -config "${AUTHELIA_CONFIG}" \
    -listen "${AUTHELIA_API_LISTEN}" \
    -db "${AUTHELIA_API_DB}" \
    -log-level "${AUTHELIA_API_LOG_LEVEL}" &
API_PID=$!
echo "${INFO} Authelia-API started (PID: ${API_PID})"

echo "${INFO} ================================================"
echo "${INFO}  Both services are running"
echo "${INFO}  Authelia:     http://0.0.0.0:${AUTHELIA_PORT}"
echo "${INFO}  Authelia-API: http://0.0.0.0:${AUTHELIA_API_LISTEN##*:}"
echo "${INFO} ================================================"

# =============================================================================
# 5. Monitor loop — exit if either process dies
# =============================================================================
while true; do
    if ! kill -0 "${AUTHELIA_PID}" 2>/dev/null; then
        echo "${ERR} Authelia (PID ${AUTHELIA_PID}) exited unexpectedly"
        kill "${API_PID}" 2>/dev/null || true
        exit 1
    fi
    if ! kill -0 "${API_PID}" 2>/dev/null; then
        echo "${ERR} Authelia-API (PID ${API_PID}) exited unexpectedly"
        kill "${AUTHELIA_PID}" 2>/dev/null || true
        exit 1
    fi
    sleep 5
done
