#!/usr/bin/env bash
# Install/update Apache vhost + API proxy port for calendar.gventure.info.
#
# Production file: /etc/apache2/sites-available/calendar.gventure.info-le-ssl.conf
# Default: patch -le-ssl.conf in place — sync Define CALENDAR_API to node/.env PORT.
# Full replace from template: CALENDAR_APACHE_FULL_INSTALL=1
#
# Requires root. Called automatically from deploy.sh when sudo is available.
set -euo pipefail

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
# shellcheck source=lib/curl-check.sh
source "$ROOT/scripts/lib/curl-check.sh"
# shellcheck source=lib/node-env-port.sh
source "$ROOT/scripts/lib/node-env-port.sh"
VHOST_SRC="$ROOT/deploy/apache-calendar.gventure.info.conf"
# Certbot live vhost — this is the file Apache actually loads in production
VHOST_DEST="${CALENDAR_APACHE_VHOST:-/etc/apache2/sites-available/calendar.gventure.info-le-ssl.conf}"
CALENDAR_ROOT="${CALENDAR_APACHE_ROOT:-$ROOT/angular/dist}"
SITE_NAME="${CALENDAR_APACHE_SITE:-calendar.gventure.info-le-ssl.conf}"
LEGACY_SITE_NAME="calendar.gventure.info.conf"

if [[ "$(id -u)" -ne 0 ]]; then
  echo "Error: configure-apache.sh must run as root (use sudo)." >&2
  exit 1
fi

CALENDAR_API_PORT="$(node_env_port "$ROOT")"
printf 'API port (from node/.env PORT): %s\n' "$CALENDAR_API_PORT"

if [[ ! -f "$VHOST_SRC" ]]; then
  echo "Error: missing $VHOST_SRC" >&2
  exit 1
fi

for mod in proxy proxy_http rewrite headers ssl; do
  a2enmod "$mod" >/dev/null 2>&1 || true
done

mkdir -p "$(dirname "$VHOST_DEST")"

install_vhost_from_template() {
  sed \
    -e "s|__CALENDAR_ROOT__|${CALENDAR_ROOT}|g" \
    -e "s|__CALENDAR_API_PORT__|${CALENDAR_API_PORT}|g" \
    "$VHOST_SRC"
}

API_BASE="http://127.0.0.1:${CALENDAR_API_PORT}"
FULL_INSTALL="${CALENDAR_APACHE_FULL_INSTALL:-0}"

# Patch -le-ssl.conf: sync Define CALENDAR_API + inline ProxyPass URL (required for Apache to proxy)
patch_vhost_api_proxy() {
  local file="$1"
  [[ -f "$file" ]] || return 1

  cp "$file" "${file}.bak.configure-apache"

  if grep -qE 'Define CALENDAR_API' "$file"; then
    sed -i "s|Define CALENDAR_API http://127\\.0\\.0\\.1:[0-9]\\{1,5\\}|Define CALENDAR_API ${API_BASE}|g" "$file"
  elif grep -qE 'Define CALENDAR_ROOT' "$file"; then
    sed -i "/Define CALENDAR_ROOT/a\\    Define CALENDAR_API ${API_BASE}" "$file"
  else
    sed -i "/ServerName calendar\\.gventure\\.info/a\\    Define CALENDAR_API ${API_BASE}" "$file"
  fi

  # ${CALENDAR_API} in ProxyPass does NOT expand on many Apache builds → use literal URL
  sed -i "s|\${CALENDAR_API}|${API_BASE}|g" "$file"
  sed -i \
    -e "s|\(ProxyPass[[:space:]]\\+/api/v1/[[:space:]]\\+\\)http://127\\.0\\.0\\.1:[0-9]\\{1,5\\}/v1/|\\1${API_BASE}/v1/|g" \
    -e "s|\(ProxyPassReverse[[:space:]]\\+/api/v1/[[:space:]]\\+\\)http://127\\.0\\.0\\.1:[0-9]\\{1,5\\}/v1/|\\1${API_BASE}/v1/|g" \
    -e "s|\(ProxyPass[[:space:]]\\+/embed/loader\\.js[[:space:]]\\+\\)http://127\\.0\\.0\\.1:[0-9]\\{1,5\\}/embed/loader\\.js|\\1${API_BASE}/embed/loader.js|g" \
    -e "s|\(ProxyPassReverse[[:space:]]\\+/embed/loader\\.js[[:space:]]\\+\\)http://127\\.0\\.0\\.1:[0-9]\\{1,5\\}/embed/loader\\.js|\\1${API_BASE}/embed/loader.js|g" \
    "$file"

  # Remove accidental "ProxyPass … !" exclusions (trailing ! means DO NOT proxy → public /api 404).
  sed -i \
    -e '/ProxyPass[[:space:]]\+\/api\/v1\/[[:space:]]\+!/d' \
    -e '/ProxyPass[[:space:]]\+\/embed\/loader\.js[[:space:]]\+!/d' \
    "$file"

  if ! grep -q 'ProxyRequests Off' "$file"; then
    sed -i "/ProxyPass[[:space:]]\\+\\/api\\/v1\\//i\\
    ProxyRequests Off\\
    ProxyPreserveHost On\\
    ProxyTimeout 60" "$file"
  fi

  if ! grep -q 'RewriteCond %{REQUEST_URI} !^/api/' "$file"; then
    sed -i '/RewriteRule \^ index\.html \[L\]/i\        RewriteCond %{REQUEST_URI} !^/api/' "$file"
    printf 'Added SPA rewrite exclusion for /api/ in %s\n' "$file"
  fi

  if ! grep -qE "ProxyPass[[:space:]]+/api/v1/[[:space:]]+http://127\\.0\\.0\\.1:${CALENDAR_API_PORT}/v1/" "$file"; then
    sed -i "/Define CALENDAR_API/a\\
    ProxyRequests Off\\
    ProxyPreserveHost On\\
    ProxyTimeout 60\\
    ProxyPass        /api/v1/ ${API_BASE}/v1/ connectiontimeout=5 timeout=60 retry=0\\
    ProxyPassReverse /api/v1/ ${API_BASE}/v1/\\
    ProxyPass        /embed/loader.js ${API_BASE}/embed/loader.js connectiontimeout=5 timeout=60 retry=0\\
    ProxyPassReverse /embed/loader.js ${API_BASE}/embed/loader.js" "$file"
    printf 'Added API ProxyPass block to %s\n' "$file"
  fi

  # HTTPS front door for n8n webhooks (Sarvam requires https://)
  if ! grep -qE 'ProxyPass[[:space:]]+/n8n-webhook/' "$file"; then
    sed -i "/ProxyPassReverse[[:space:]]\\+\\/embed\\/loader\\.js/a\\
    ProxyPass        /n8n-webhook/ http://127.0.0.1:5678/webhook/ connectiontimeout=5 timeout=60 retry=0\\
    ProxyPassReverse /n8n-webhook/ http://127.0.0.1:5678/webhook/" "$file"
    printf 'Added n8n webhook ProxyPass to %s\n' "$file"
  fi
}

apply_vhost_config() {
  local dest="$1"
  if [[ -f "$dest" && "$FULL_INSTALL" != "1" ]]; then
    patch_vhost_api_proxy "$dest"
    printf 'Patched %s → Define CALENDAR_API %s\n' "$dest" "$API_BASE"
  else
    install_vhost_from_template > "$dest"
    printf 'Installed vhost: %s (CALENDAR_ROOT=%s, API port=%s)\n' \
      "$dest" "$CALENDAR_ROOT" "$CALENDAR_API_PORT"
  fi
}

apply_vhost_config "$VHOST_DEST"

VHOST_ENABLED="/etc/apache2/sites-enabled/$(basename "$VHOST_DEST")"
if [[ -f "$VHOST_DEST" ]]; then
  if [[ -L "$VHOST_ENABLED" ]] || [[ ! -e "$VHOST_ENABLED" ]]; then
    ln -sf "$VHOST_DEST" "$VHOST_ENABLED" 2>/dev/null || cp "$VHOST_DEST" "$VHOST_ENABLED"
    [[ -e "$VHOST_ENABLED" ]] && printf 'Enabled vhost: %s\n' "$VHOST_ENABLED"
  elif [[ -f "$VHOST_ENABLED" ]]; then
    cp "$VHOST_DEST" "$VHOST_ENABLED"
    printf 'Synced sites-enabled copy: %s\n' "$VHOST_ENABLED"
  fi
fi

purge_stale_global_api_proxy() {
  # Remove duplicate global /api ProxyPass from conf-enabled (vhost Define CALENDAR_API is authoritative)
  local expected_port="$1"
  local changed=0
  [[ -d /etc/apache2 ]] || return 0

  local vhost_base
  vhost_base="$(basename "$VHOST_DEST")"

  while IFS= read -r conf; do
    [[ -z "$conf" ]] && continue
    [[ "$(basename "$conf")" == "$vhost_base" ]] && continue

    if grep -qE 'ProxyPass.*/api/v1/|ProxyPassReverse.*/api/v1/' "$conf" 2>/dev/null; then
      printf 'Removing stale global API ProxyPass from %s\n' "$conf" >&2
      sed -i \
        -e '/ProxyPass[[:space:]]\+\/api\/v1\//d' \
        -e '/ProxyPassReverse[[:space:]]\+\/api\/v1\//d' \
        -e '/ProxyPass[[:space:]]\+\/embed\/loader\.js/d' \
        -e '/ProxyPassReverse[[:space:]]\+\/embed\/loader\.js/d' \
        "$conf"
      changed=1
    fi

    if grep -qE '127\.0\.0\.1:[0-9]+' "$conf" 2>/dev/null \
      && grep -qE 'ProxyPass.*/api|/v1/' "$conf" 2>/dev/null \
      && ! grep -qE "127\\.0\\.0\\.1:${expected_port}" "$conf" 2>/dev/null; then
      printf 'WARNING: %s may still reference a stale API port — review manually\n' "$conf" >&2
    fi
  done < <(find /etc/apache2/conf-enabled /etc/apache2/conf-available -name '*.conf' 2>/dev/null || true)

  if [[ "$changed" -eq 1 ]]; then
    printf 'Purged stale global API proxy rules from conf-enabled\n'
  fi
}

purge_stale_global_api_proxy "$CALENDAR_API_PORT"

# www-data must traverse path and read static files (fixes 403)
fix_path_traversal() {
  local path="$1"
  while [[ "$path" != "/" && -n "$path" ]]; do
    if [[ -d "$path" ]]; then
      chmod o+x "$path" 2>/dev/null || true
    fi
    path="$(dirname "$path")"
  done
}

fix_static_permissions() {
  local dir="$1"
  [[ -d "$dir" ]] || return 0
  find "$dir" -type d -exec chmod 755 {} \;
  find "$dir" -type f -exec chmod 644 {} \;
}

for app in host-dashboard public-booking embed-widget; do
  fix_path_traversal "${CALENDAR_ROOT}/${app}/browser"
  fix_static_permissions "${CALENDAR_ROOT}/${app}/browser"
done
printf 'Fixed static file permissions under %s\n' "$CALENDAR_ROOT"

# Global conf not used — Define CALENDAR_API lives in the -le-ssl vhost only
a2disconf calendar-api-port >/dev/null 2>&1 || true

# Only the -le-ssl vhost is used in production; disable legacy duplicate if present
a2dissite "$LEGACY_SITE_NAME" >/dev/null 2>&1 || true
a2ensite "$SITE_NAME" >/dev/null 2>&1 || true
if [[ ! -L "/etc/apache2/sites-enabled/$(basename "$VHOST_DEST")" ]] \
  && [[ ! -f "/etc/apache2/sites-enabled/$(basename "$VHOST_DEST")" ]]; then
  printf 'WARNING: %s is not enabled — run: a2ensite %s\n' "$SITE_NAME" "$SITE_NAME" >&2
fi

# SELinux: Apache must be allowed to connect to Node on 127.0.0.1 (common 503 cause)
if command -v getenforce >/dev/null 2>&1; then
  se_state="$(getenforce 2>/dev/null || echo Disabled)"
  if [[ "$se_state" == "Enforcing" ]]; then
    if command -v setsebool >/dev/null 2>&1; then
      setsebool -P httpd_can_network_connect 1 2>/dev/null || true
      printf 'SELinux: enabled httpd_can_network_connect (required for API proxy)\n'
    else
      printf 'WARNING: SELinux is Enforcing — run: setsebool -P httpd_can_network_connect 1\n' >&2
    fi
  fi
fi

apachectl configtest
systemctl reload apache2
printf 'Apache reloaded successfully.\n'

scan_stale_api_proxies() {
  local expected_port="$1"
  local found=0
  if [[ ! -d /etc/apache2 ]]; then
    return 0
  fi
  while IFS= read -r line; do
    [[ -z "$line" ]] && continue
    if echo "$line" | grep -qE 'ProxyPass.*/api|127\.0\.0\.1:[0-9]+/v1'; then
      if echo "$line" | grep -qE 'ProxyPass[[:space:]]+/api/v1/[[:space:]]+!'; then
        continue
      fi
      if ! echo "$line" | grep -qE "127\\.0\\.0\\.1:${expected_port}(/|\"|$)"; then
        printf 'WARNING: stale API proxy (expected port %s): %s\n' "$expected_port" "$line" >&2
        found=1
      fi
    fi
  done < <(grep -rE 'ProxyPass.*/api|127\.0\.0\.1:[0-9]+/v1' /etc/apache2/ 2>/dev/null || true)
  return "$found"
}

scan_stale_api_proxies "$CALENDAR_API_PORT" || true

APACHE_SERVER_NAME="${CALENDAR_APACHE_SERVER_NAME:-calendar.gventure.info}"

# Quick checks
if command -v curl >/dev/null 2>&1; then
  local_code="$(curl -sS -o /dev/null -w '%{http_code}' --connect-timeout 3 \
    "http://127.0.0.1:${CALENDAR_API_PORT}/v1/health" 2>/dev/null || echo 000)"
  printf 'Local API health: HTTP %s (port %s)\n' "$local_code" "$CALENDAR_API_PORT"

  proxy_code="$(curl_vhost_https "${APACHE_SERVER_NAME}" "/api/v1/health" 5)"
  printf 'Apache proxy test:  HTTP %s (--resolve %s:443:127.0.0.1 /api/v1/health)\n' \
    "$proxy_code" "$APACHE_SERVER_NAME"
  if [[ "$proxy_code" != "200" ]]; then
    printf 'Proxy failed after reload — trying full Apache restart...\n' >&2
    systemctl restart apache2
    sleep 2
    proxy_code="$(curl_vhost_https "${APACHE_SERVER_NAME}" "/api/v1/health" 8)"
    printf 'Apache proxy test:  HTTP %s (after restart)\n' "$proxy_code"
  fi
  if [[ "$proxy_code" != "200" ]]; then
    printf '\nProxy still failing. Diagnostics:\n' >&2
    grep -E 'Define CALENDAR_API|ProxyPass.*/api/v1/' "$VHOST_DEST" >&2 || true
    if [[ -e "$VHOST_ENABLED" ]]; then
      printf 'sites-enabled proxy lines:\n' >&2
      grep -E 'ProxyPass.*/api/v1/' "$VHOST_ENABLED" >&2 || true
    fi
    if command -v apache2ctl >/dev/null 2>&1; then
      printf 'Apache vhost map:\n' >&2
      apache2ctl -S 2>/dev/null | grep -i calendar >&2 || true
    fi
    printf 'All /api ProxyPass rules:\n' >&2
    grep -rnE 'ProxyPass.*/api' /etc/apache2/ 2>/dev/null | head -20 >&2 || true
    if id www-data >/dev/null 2>&1; then
      www_code="$(sudo -u www-data curl -sS -o /dev/null -w '%{http_code}' --connect-timeout 3 \
        "http://127.0.0.1:${CALENDAR_API_PORT}/v1/health" 2>/dev/null || echo 000)"
      printf '  www-data → API: HTTP %s' "$www_code" >&2
      if [[ "$www_code" != "200" && "$(getenforce 2>/dev/null || echo Disabled)" == "Enforcing" ]]; then
        printf ' (SELinux likely blocking — run: setsebool -P httpd_can_network_connect 1)' >&2
      fi
      printf '\n' >&2
    fi
    if [[ -f /var/log/apache2/calendar-error.log ]]; then
      printf '  Recent Apache errors:\n' >&2
      tail -5 /var/log/apache2/calendar-error.log >&2 || true
    fi
    printf '  Run: bash scripts/diagnose-apache-api-proxy.sh\n' >&2
  fi
fi
