#!/usr/bin/env bash
set -euo pipefail

log() { printf '%s\n' "$*"; }
warn() { printf 'WARN: %s\n' "$*" >&2; }

ensure_network() {
  local name=$1
  if docker network inspect "$name" >/dev/null 2>&1; then
    log "network exists: $name"
  else
    log "creating overlay network: $name"
    docker network create --driver overlay --attachable "$name"
  fi
}

secret_exists() { docker secret inspect "$1" >/dev/null 2>&1; }

create_secret_from_value() {
  local name=$1; local value=$2
  printf '%s' "$value" | docker secret create "$name" - >/dev/null 2>&1 && log "secret created: $name" || log "secret exists: $name"
}

create_secret_from_file() {
  local name=$1; local path=$2
  docker secret create "$name" "$path" >/dev/null 2>&1 && log "secret created: $name (from $path)" || log "secret exists: $name"
}

rand_b64() { openssl rand -base64 32 2>/dev/null || head -c 24 /dev/urandom | base64; }

get_from_env_or_file_or_default() {
  local name=$1 envvar=$2 default_gen=$3
  local file="stacks/secrets/${name}.txt"
  local val=""
  if [[ -n "${!envvar-}" ]]; then
    val="${!envvar}"
  elif [[ -f "$file" ]]; then
    val=$(cat "$file")
  elif [[ "$default_gen" == "gen" ]]; then
    val=$(rand_b64)
    warn "no env or file for $name; generating random"
  else
    val=""
  fi
  printf '%s' "$val"
}

main() {
  # Networks
  ensure_network traefik-public
  ensure_network database-network
  ensure_network monitoring-network

  # Secrets map: name envvar gen-policy
  declare -a items=(
    "pg_root_password PG_ROOT_PASSWORD gen"
    "mariadb_root_password MARIADB_ROOT_PASSWORD gen"
    "gitea_db_password GITEA_DB_PASSWORD gen"
    "nextcloud_db_password NEXTCLOUD_DB_PASSWORD gen"
    "smtp_user SMTP_USER plain"
    "smtp_pass SMTP_PASS gen"
    "appflowy_db_url APPFLOWY_DB_URL plain"
    "minio_access_key MINIO_ACCESS_KEY gen"
    "minio_secret_key MINIO_SECRET_KEY gen"
  )

  for entry in "${items[@]}"; do
    set -- $entry
    name=$1; envvar=$2; policy=$3
    if secret_exists "$name"; then
      log "secret exists: $name"
      continue
    fi
    val=$(get_from_env_or_file_or_default "$name" "$envvar" "$policy")
    if [[ -z "$val" ]]; then
      warn "secret $name missing (env $envvar or stacks/secrets/${name}.txt). Creating placeholder; update ASAP."
      case "$name" in
        smtp_user) val="noreply@example.local" ;;
        appflowy_db_url) val="postgres://user:pass@postgresql_primary:5432/appflowy" ;;
        *) val=$(rand_b64) ;;
      esac
    fi
    create_secret_from_value "$name" "$val"
  done

  log "bootstrap complete"
}

main "$@"
