#!/bin/sh
set -e

# ============================================================================
# Caddy Entrypoint Script
# ============================================================================
# This script:
# 1. Validates required environment variables (HOST, SITE_URL)
# 2. Generates TLS config in Caddyfile based on TLS_MODE (hardcoded, not env vars)
# 3. Ensures self-signed CA certificates are readable by other containers
# ============================================================================

# ============================================================================
# Domain Configuration
# ============================================================================
HOST="${HOST:-tale.local}"

# SITE_URL is required
if [ -z "${SITE_URL:-}" ]; then
  echo "Error: SITE_URL is required. Set it in your .env file." >&2
  exit 1
fi
# Trim leading/trailing whitespace
SITE_URL=$(echo "${SITE_URL}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
export SITE_URL

# Base path for subpath deployments (from .env, e.g., /test or /app)
# Strip trailing slashes, ensure leading slash if non-empty, strip SITE_URL trailing slash
BASE_PATH=$(echo "${BASE_PATH:-}" | sed 's|/\+$||')
if [ -n "$BASE_PATH" ] && [ "${BASE_PATH#/}" = "$BASE_PATH" ]; then
  BASE_PATH="/${BASE_PATH}"
fi
SITE_URL=$(echo "${SITE_URL}" | sed 's|/\+$||')
export BASE_PATH
export SITE_URL

# Docs subdomain origin (https://docs.<HOST> by default; override with DOCS_URL
# in .env when the docs site lives on a different host).
if [ -z "${DOCS_URL:-}" ]; then
  DOCS_URL="https://docs.${HOST}"
fi
DOCS_URL=$(echo "${DOCS_URL}" | sed 's|/\+$||;s|^[[:space:]]*||;s|[[:space:]]*$||')
export DOCS_URL

echo "Domain Configuration:"
echo "  HOST: ${HOST}"
echo "  SITE_URL: ${SITE_URL}"
echo "  DOCS_URL: ${DOCS_URL}"
if [ -n "$BASE_PATH" ]; then
  echo "  BASE_PATH: ${BASE_PATH}"
fi

# Source and destination for Caddyfile
# We copy to /config (writable volume) because /etc/caddy is read-only in the image
CADDYFILE_SRC="/etc/caddy/Caddyfile"
CADDYFILE="/config/Caddyfile"

# ============================================================================
# Generate TLS configuration based on TLS_MODE
# ============================================================================
# We hardcode the TLS config directly into Caddyfile because environment
# variables don't persist through `caddy reload` commands.
echo "TLS Configuration:"
echo "  TLS_MODE: ${TLS_MODE:-selfsigned}"

case "${TLS_MODE:-selfsigned}" in
    external)
      echo "  Mode: External (TLS handled by reverse proxy, Caddy serves HTTP only)"
      TLS_CONFIG=""
      ;;
    letsencrypt)
      echo "  Mode: Let's Encrypt (ACME - trusted certificates)"
      if [ -n "${TLS_EMAIL:-}" ]; then
        echo "  Email: ${TLS_EMAIL}"
        # ACME with email for notifications
        TLS_CONFIG="tls ${TLS_EMAIL}"
      else
        TLS_EMAIL_DEFAULT="tls@${HOST:-tale.local}"
        echo "  Email: ${TLS_EMAIL_DEFAULT} (default, set TLS_EMAIL to override)"
        TLS_CONFIG="tls ${TLS_EMAIL_DEFAULT}"
      fi
      ;;
    selfsigned|*)
      echo "  Mode: Self-signed (internal CA - browser warning expected)"
      echo "  To trust certs on host: docker exec tale-proxy caddy trust"
      # Internal CA for self-signed certificates
      TLS_CONFIG="tls internal"
      ;;
  esac

# HTTPS is required for non-external modes — OAuth providers reject http://
# callbacks and crypto.subtle is unavailable in insecure contexts.
if [ "${TLS_MODE:-selfsigned}" != "external" ] && echo "${SITE_URL}" | grep -qi '^http://'; then
  echo "Error: SITE_URL must use https://. Plain HTTP is not supported." >&2
  echo "  If running behind a TLS-terminating reverse proxy, set TLS_MODE=external." >&2
  exit 1
fi
if [ "${TLS_MODE:-selfsigned}" != "external" ] && echo "${DOCS_URL}" | grep -qi '^http://'; then
  echo "Error: DOCS_URL must use https://. Plain HTTP is not supported." >&2
  echo "  If running behind a TLS-terminating reverse proxy, set TLS_MODE=external." >&2
  exit 1
fi

# Copy Caddyfile to writable location and apply TLS config
cp "$CADDYFILE_SRC" "$CADDYFILE"
sed -i "s|^[[:space:]]*#[[:space:]]*TLS_PLACEHOLDER[[:space:]]*\$|\\t${TLS_CONFIG}|" "$CADDYFILE"

# Replace SITE_ORIGIN in Caddyfile with SITE_URL (no subpath in SITE_URL).
# DOCS_ORIGIN is the parallel host block for the docs site (docs.<HOST>).
sed -i "s|{[\$]SITE_ORIGIN:[^}]*}|${SITE_URL}|" "$CADDYFILE"
sed -i "s|{[\$]DOCS_ORIGIN:[^}]*}|${DOCS_URL}|" "$CADDYFILE"

# Inject base path stripping for subpath deployments
if [ -n "$BASE_PATH" ]; then
  sed -i "s|# BASE_PATH_PLACEHOLDER|uri strip_prefix ${BASE_PATH}|" "$CADDYFILE"
else
  sed -i "/# BASE_PATH_PLACEHOLDER/d" "$CADDYFILE"
fi

# For external mode, force Caddy to listen on HTTP by rewriting the scheme.
# SITE_URL stays as-is for the platform (public URL), but Caddy must not auto-enable TLS.
if [ "${TLS_MODE:-selfsigned}" = "external" ]; then
  CADDY_ADDR=$(echo "${SITE_URL}" | sed -E 's|^https://|http://|; s|:[0-9]+$||')
  sed -i "s|${SITE_URL}|${CADDY_ADDR}|" "$CADDYFILE"
  DOCS_ADDR=$(echo "${DOCS_URL}" | sed -E 's|^https://|http://|; s|:[0-9]+$||')
  sed -i "s|${DOCS_URL}|${DOCS_ADDR}|" "$CADDYFILE"
  echo "  Caddy listen address (site): ${CADDY_ADDR}"
  echo "  Caddy listen address (docs): ${DOCS_ADDR}"
fi

echo "  Caddyfile configured: ${TLS_CONFIG:-none}"

# Function to fix certificate permissions after Caddy generates them
fix_cert_permissions() {
  CA_DIR="/data/caddy/pki/authorities/local"
  PKI_DIR="/data/caddy/pki"
  AUTH_DIR="/data/caddy/pki/authorities"

  if [ -d "$CA_DIR" ]; then
    # Make the directory hierarchy readable by others
    chmod 755 "$PKI_DIR" 2>/dev/null || true
    chmod 755 "$AUTH_DIR" 2>/dev/null || true
    chmod 755 "$CA_DIR" 2>/dev/null || true
    # Make the CA certificates readable by others
    chmod 644 "$CA_DIR"/*.crt 2>/dev/null || true
    echo "Fixed CA certificate permissions in $CA_DIR"
  fi
}

# Start a background process to fix permissions after Caddy generates certs
# (not needed for external mode — no certificates are generated)
if [ "${TLS_MODE:-selfsigned}" != "external" ]; then
  (
    # Wait for Caddy to generate certificates (check every 5 seconds for up to 60 seconds)
    for _ in $(seq 1 12); do
      sleep 5
      if [ -f "/data/caddy/pki/authorities/local/root.crt" ]; then
        fix_cert_permissions
        break
      fi
    done
  ) &
fi

# For Let's Encrypt mode: retry certificate obtention if DNS wasn't ready at startup.
# Caddy's built-in retry uses exponential backoff that gets very slow after failures.
# This loop checks that DNS resolves to our public IP before reloading Caddy,
# covering the common case where DNS is configured hours or days after deployment.
if [ "${TLS_MODE:-selfsigned}" = "letsencrypt" ]; then
  (
    sleep 60
    SERVER_IP=$(wget -qO- -T5 http://ipv4.icanhazip.com 2>/dev/null | tr -d '[:space:]')
    if [ -n "$SERVER_IP" ]; then
      echo "ACME retry: server public IP is ${SERVER_IP}"
    else
      echo "ACME retry: could not determine public IP, will retry every 15 minutes"
    fi

    while true; do
      if find /data/caddy/certificates -name "${HOST}" -type d 2>/dev/null | grep -q .; then
        echo "ACME certificate obtained for ${HOST}"
        break
      fi
      if [ -n "$SERVER_IP" ]; then
        # Verify domain resolves to our IP via external DNS (bypasses Docker DNS,
        # handles wildcard DNS that resolves non-existent subdomains to a fallback IP)
        if nslookup "${HOST}" 1.1.1.1 2>/dev/null | grep -q "${SERVER_IP}"; then
          echo "DNS resolved ${HOST} to ${SERVER_IP}, reloading Caddy..."
          caddy reload --config "$CADDYFILE" --adapter caddyfile 2>/dev/null || true
          sleep 120
        else
          sleep 300
        fi
      else
        # Fallback: safe interval under Let's Encrypt rate limit (5 failures/host/hour)
        caddy reload --config "$CADDYFILE" --adapter caddyfile 2>/dev/null || true
        sleep 900
      fi
    done
  ) &
fi

# Execute the main command (Caddy)
exec "$@"
