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

SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
if [[ -x "$SCRIPT_DIR/../limristem-mail" ]]; then
  BASE_DIR=$(cd "$SCRIPT_DIR/.." && pwd)
elif [[ -x "${LIMRISTEM_MAIL_BASE_DIR:-/opt/limristem-mail}/limristem-mail" ]]; then
  BASE_DIR="${LIMRISTEM_MAIL_BASE_DIR:-/opt/limristem-mail}"
else
  BASE_DIR=$(cd "$SCRIPT_DIR/.." && pwd)
fi
# shellcheck source=/dev/null
source "$SCRIPT_DIR/libenv.sh"

ENV_FILE=$(limristem_mail_resolve_main_env_file)

usage() {
  cat <<'EOF'
Usage:
  manage-topology.sh show [--json]
  manage-topology.sh apply-mode <standalone|routed|cluster> [options]
  manage-topology.sh refresh-transport [--json]

Options:
  --server-id ID
  --routed-db shared|synced
  --storage nfs|ceph|s3
  --storage-path PATH
  --s3-cache-ttl SECONDS
  --s3-cache-max-mb MB
  --internode-token TOKEN

Modes:
  standalone  Single-node classic install
  routed      Routed Mesh (split-domain multi-backend)
  cluster     Storage Cluster (shared NFS/Ceph/S3 mail storage)
EOF
}

require_root() {
  if [[ $EUID -ne 0 ]]; then
    echo "Run as root." >&2
    exit 1
  fi
}

load_env() {
  limristem_mail_load_env_file "$ENV_FILE"
}

show() {
  load_env
  local mode=${LIMRISTEM_MAIL_TOPOLOGY_MODE:-standalone}
  local sid=${LIMRISTEM_MAIL_SERVER_ID:-}
  local strategy=${LIMRISTEM_MAIL_ROUTED_DB_STRATEGY:-shared}
  local storage=${LIMRISTEM_MAIL_CLUSTER_STORAGE:-nfs}
  if [[ ${1:-} == "--json" ]]; then
    python3 - "$mode" "$sid" "$strategy" "$storage" <<'PY'
import json, sys
print(json.dumps({
  "mode": sys.argv[1],
  "server_id": sys.argv[2] or None,
  "routed_db_strategy": sys.argv[3],
  "cluster_storage": sys.argv[4],
}))
PY
    return
  fi
  printf 'mode=%s\n' "$mode"
  printf 'server_id=%s\n' "$sid"
  printf 'routed_db_strategy=%s\n' "$strategy"
  printf 'cluster_storage=%s\n' "$storage"
}

write_transport_stub() {
  # Postfix transport map for routed mode (filled by sync-transport-maps).
  local mapf=/etc/postfix/limristem-transport
  if [[ ! -f "$mapf" ]]; then
    printf '# limristem routed transport map\n' > "$mapf"
    postmap "$mapf" 2>/dev/null || true
  fi
  if command -v postconf >/dev/null 2>&1; then
    if [[ "${LIMRISTEM_MAIL_TOPOLOGY_MODE:-standalone}" == "routed" ]]; then
      postconf -e 'transport_maps = hash:/etc/postfix/limristem-transport'
    else
      postconf -X transport_maps 2>/dev/null || true
    fi
    systemctl reload postfix >/dev/null 2>&1 || true
  fi
}

apply_mode() {
  local mode=$1
  shift
  local server_id="" routed_db="shared" storage="nfs" storage_path="" s3_ttl="3600" s3_max="10240" token=""
  while (( $# > 0 )); do
    case "$1" in
      --server-id) server_id=$2; shift 2 ;;
      --routed-db) routed_db=$2; shift 2 ;;
      --storage) storage=$2; shift 2 ;;
      --storage-path) storage_path=$2; shift 2 ;;
      --s3-cache-ttl) s3_ttl=$2; shift 2 ;;
      --s3-cache-max-mb) s3_max=$2; shift 2 ;;
      --internode-token) token=$2; shift 2 ;;
      *) echo "Unknown option: $1" >&2; exit 1 ;;
    esac
  done
  case "$mode" in
    standalone|routed|cluster) ;;
    *) echo "Invalid mode: $mode" >&2; exit 1 ;;
  esac
  case "$routed_db" in
    shared|synced) ;;
    *) echo "Invalid routed-db: $routed_db" >&2; exit 1 ;;
  esac
  case "$storage" in
    nfs|ceph|s3) ;;
    *) echo "Invalid storage: $storage" >&2; exit 1 ;;
  esac
  [[ "$s3_ttl" =~ ^[0-9]+$ ]] || { echo "Invalid s3-cache-ttl: $s3_ttl" >&2; exit 1; }
  [[ "$s3_max" =~ ^[0-9]+$ ]] || { echo "Invalid s3-cache-max-mb: $s3_max" >&2; exit 1; }
  if [[ -n "$server_id" ]]; then
    [[ "$server_id" =~ ^[a-z0-9][a-z0-9_.-]{0,63}$ ]] || { echo "Invalid server-id: $server_id" >&2; exit 1; }
  fi
  limristem_mail_upsert_env_value "$ENV_FILE" LIMRISTEM_MAIL_TOPOLOGY_MODE "$mode"
  if [[ -n "$server_id" ]]; then
    limristem_mail_upsert_env_value "$ENV_FILE" LIMRISTEM_MAIL_SERVER_ID "$server_id"
  fi
  if [[ "$mode" == "routed" ]]; then
    limristem_mail_upsert_env_value "$ENV_FILE" LIMRISTEM_MAIL_ROUTED_DB_STRATEGY "$routed_db"
  fi
  if [[ "$mode" == "cluster" ]]; then
    limristem_mail_upsert_env_value "$ENV_FILE" LIMRISTEM_MAIL_CLUSTER_STORAGE "$storage"
    [[ -n "$storage_path" ]] && limristem_mail_upsert_env_value "$ENV_FILE" LIMRISTEM_MAIL_CLUSTER_STORAGE_PATH "$storage_path"
    limristem_mail_upsert_env_value "$ENV_FILE" LIMRISTEM_MAIL_S3_CACHE_TTL_SECONDS "$s3_ttl"
    limristem_mail_upsert_env_value "$ENV_FILE" LIMRISTEM_MAIL_S3_CACHE_MAX_MB "$s3_max"
  fi
  if [[ -n "$token" ]]; then
    # No chmod here: limristem_mail_upsert_env_value already installs the file 0640
    # root:limristem-mail. Forcing 0600 would break every in-process read of the env
    # by the service account (settings show, version, update checks) with EACCES.
    limristem_mail_upsert_env_value "$ENV_FILE" LIMRISTEM_MAIL_INTERNODE_TOKEN "$token"
  fi
  load_env
  write_transport_stub
  systemctl restart --no-block limristem-mail >/dev/null 2>&1 || true
  show --json
}

require_root

# apply-mode and refresh-transport mutate /etc (postfix transport, service configs) and must escape
# the app's read-only mount namespace when invoked from the panel/API.
case "${1:-}" in
  apply-mode|refresh-transport)
    limristem_mail_escape_write_namespace LIMRISTEM_MAIL_TOPOLOGY_WORKER limristem-mail-topology "$@"
    ;;
esac

cmd=${1:-}
case "$cmd" in
  show) shift; show "${1:-}" ;;
  apply-mode)
    shift
    mode=${1:?mode required}
    shift
    apply_mode "$mode" "$@"
    ;;
  refresh-transport)
    shift || true
    exec "$BASE_DIR/limristem-mail" topology refresh-transport "$@"
    ;;
  *) usage >&2; exit 1 ;;
esac
