#!/usr/bin/env bash
# Validates variables required by docker-compose.prod.yml before compose runs.
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"

ENV_FILE="${ENV_FILE:-$ROOT/.env}"
if [[ ! -f "$ENV_FILE" ]]; then
  printf 'Missing %s\nCopy .env.example to .env and fill in secrets.\n' "$ENV_FILE" >&2
  exit 1
fi

while IFS= read -r line || [[ -n "$line" ]]; do
  line="${line%$'\r'}"
  [[ "$line" =~ ^[[:space:]]*# ]] && continue
  [[ "$line" =~ ^[[:space:]]*$ ]] && continue
  if [[ "$line" =~ ^([A-Za-z_][A-Za-z0-9_]*)=(.*)$ ]]; then
    key="${BASH_REMATCH[1]}"
    val="${BASH_REMATCH[2]}"
    val="${val#"${val%%[![:space:]]*}"}"
    val="${val%"${val##*[![:space:]]}"}"
    export "${key}=${val}"
  fi
done <"$ENV_FILE"

reject_leading_space_after_equals() {
  local key rhs
  while IFS= read -r line || [[ -n "$line" ]]; do
    line="${line%$'\r'}"
    [[ "$line" =~ ^[[:space:]]*# ]] && continue
    [[ "$line" =~ ^[[:space:]]*$ ]] && continue
    if [[ "$line" =~ ^[[:space:]]*(POSTGRES_USER|POSTGRES_PASSWORD|POSTGRES_DB|MINIO_ROOT_USER|MINIO_ROOT_PASSWORD|MINIO_API_PORT|MINIO_CONSOLE_PORT|FE_PORT|PUBLIC_HOST)=(.*)$ ]]; then
      key="${BASH_REMATCH[1]}"
      rhs="${BASH_REMATCH[2]}"
      [[ "$rhs" =~ ^[[:space:]]+ ]] || continue
      printf 'Invalid format in %s: "%s" has a space (or tab) immediately after "=".\n' "$ENV_FILE" "$key" >&2
      printf 'Use KEY=value without a space after the equals sign.\n' >&2
      exit 1
    fi
  done <"$ENV_FILE"
}
reject_leading_space_after_equals
MISSING=()
need() {
  local n="$1"
  local v="${!n-}"
  if [[ -z "${v//[:space:]}" ]]; then
    MISSING+=("$n")
  fi
}

need PUBLIC_HOST
need FE_PORT
need MINIO_API_PORT
need MINIO_CONSOLE_PORT
need MINIO_ROOT_USER
need MINIO_ROOT_PASSWORD
need POSTGRES_USER
need POSTGRES_PASSWORD
need POSTGRES_DB
need JWT_SECRET
need MINIO_API_CORS_ALLOW_ORIGIN

if [[ ${#MISSING[@]} -gt 0 ]]; then
  printf 'Unset or whitespace-only variables in %s:\n  %s\n' "$ENV_FILE" "${MISSING[*]}" >&2
  printf '(Blank values break MinIO: MINIO_BROWSER_REDIRECT_URL would have an empty host.)\n' >&2
  exit 1
fi

if ! [[ "${MINIO_CONSOLE_PORT}" =~ ^[0-9]+$ ]] || ! [[ "${MINIO_API_PORT}" =~ ^[0-9]+$ ]] || ! [[ "${FE_PORT}" =~ ^[0-9]+$ ]]; then
  printf 'Ports must be numeric (FE_PORT, MINIO_*_PORT).\n' >&2
  exit 1
fi

# Postgres role/database names in URLs/scripts: avoid quoting and “role does not exist” churn.
if ! [[ "${POSTGRES_USER}" =~ ^[a-zA-Z_][a-zA-Z0-9_]{0,62}$ ]]; then
  printf 'POSTGRES_USER must be an unquoted SQL identifier (e.g. initiative): letters, digits, underscore; max 63 chars.\n' >&2
  printf 'Avoid special characters like "!". Docker only creates this role when the Postgres data directory is EMPTY.\n' >&2
  printf 'Full guide: docs/deploy-production-docker.md (Postgres).\n' >&2
  exit 1
fi

if ! [[ "${POSTGRES_DB}" =~ ^[a-zA-Z_][a-zA-Z0-9_]{0,62}$ ]]; then
  printf 'POSTGRES_DB must be an unquoted SQL identifier (e.g. initiatives): letters, digits, underscore; max 63 chars.\n' >&2
  printf 'INITIATIVE_DATABASE_URL is built without escaping; exotic names break URLs.\n' >&2
  exit 1
fi

# INITIATIVE_DATABASE_URL is assembled without encoding; :, @, / break the URL if unescaped.
if [[ "${POSTGRES_PASSWORD}" == *"@"* ]] || [[ "${POSTGRES_PASSWORD}" == *":"* ]] || [[ "${POSTGRES_PASSWORD}" == *"/"* ]] || [[ "${POSTGRES_PASSWORD}" == *"%"* ]]; then
  printf 'POSTGRES_PASSWORD contains @, :, / or %%. URL-unsafe for INITIATIVE_DATABASE_URL; use alphanumeric + punctuation like + or = from openssl rand -base64.\n' >&2
  exit 1
fi

if [[ "${MINIO_API_CORS_ALLOW_ORIGIN}" == "*" ]]; then
  printf 'MINIO_API_CORS_ALLOW_ORIGIN must not be * in production — use your SPA origin (e.g. https://www.rcc-ump.com).\n' >&2
  exit 1
fi

if [[ ${#JWT_SECRET} -lt 32 ]]; then
  printf 'JWT_SECRET must be at least 32 characters (generate: openssl rand -base64 48).\n' >&2
  exit 1
fi

preview="http://${PUBLIC_HOST}:${MINIO_CONSOLE_PORT}"

echo "OK — required vars set; MINIO_BROWSER_REDIRECT_URL preview: ${preview}"
echo "   CORS for public UI: http://${PUBLIC_HOST}:${FE_PORT} (+ localhost defaults in be0; optional CORS_ORIGINS_EXTRA in .env)"
if [[ -n "${S3_PUBLIC_ENDPOINT_URL:-}" && "${S3_PUBLIC_ENDPOINT_URL}" == https:* ]]; then
  echo "   HTTPS MinIO (S3_PUBLIC_ENDPOINT_URL): ensure TLS proxy → 127.0.0.1:${MINIO_API_PORT}; see docs/minio-behind-https.md"
fi
if [[ -n "${MINIO_SERVER_URL:-}" && "${MINIO_SERVER_URL}" == https:* && -z "${S3_PUBLIC_ENDPOINT_URL:-}" ]]; then
  echo "   Warn: MINIO_SERVER_URL is https but S3_PUBLIC_ENDPOINT_URL is unset — be0 defaults may still presign HTTP. Set both to match."
fi