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

SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# shellcheck source=/dev/null
source "$SCRIPT_DIR/libenv.sh"

ENV_FILE=$(limristem_mail_resolve_main_env_file)

declare -A LIMIT_ENV_MAP=(
  [postfix-client-connection-rate-limit]=LIMRISTEM_MAIL_POSTFIX_CLIENT_CONNECTION_RATE_LIMIT
  [postfix-client-message-rate-limit]=LIMRISTEM_MAIL_POSTFIX_CLIENT_MESSAGE_RATE_LIMIT
  [postfix-rate-time-unit]=LIMRISTEM_MAIL_POSTFIX_RATE_TIME_UNIT
  [message-size-limit]=LIMRISTEM_MAIL_MESSAGE_SIZE_LIMIT
  [smtp-recipient-limit]=LIMRISTEM_MAIL_SMTP_RECIPIENT_LIMIT
  [smtp-client-connection-count-limit]=LIMRISTEM_MAIL_SMTP_CLIENT_CONNECTION_COUNT_LIMIT
  [api-auth-fail-limit]=LIMRISTEM_MAIL_API_AUTH_FAIL_LIMIT
  [api-auth-window-seconds]=LIMRISTEM_MAIL_API_AUTH_WINDOW_SECONDS
  [api-auth-block-seconds]=LIMRISTEM_MAIL_API_AUTH_BLOCK_SECONDS
  [send-rate-burst]=LIMRISTEM_MAIL_SEND_RATE_BURST
  [send-rate-per-minute]=LIMRISTEM_MAIL_SEND_RATE_PER_MINUTE
  [send-rate-per-hour]=LIMRISTEM_MAIL_SEND_RATE_PER_HOUR
  [send-rate-per-day]=LIMRISTEM_MAIL_SEND_RATE_PER_DAY
  [send-rate-per-week]=LIMRISTEM_MAIL_SEND_RATE_PER_WEEK
  [send-rate-per-month]=LIMRISTEM_MAIL_SEND_RATE_PER_MONTH
  [rspamd-action-greylist]=LIMRISTEM_MAIL_RSPAMD_ACTION_GREYLIST
  [rspamd-action-add-header]=LIMRISTEM_MAIL_RSPAMD_ACTION_ADD_HEADER
  [rspamd-action-reject]=LIMRISTEM_MAIL_RSPAMD_ACTION_REJECT
  [rspamd-greylist-delay]=LIMRISTEM_MAIL_RSPAMD_GREYLIST_DELAY
  [rspamd-greylist-expire]=LIMRISTEM_MAIL_RSPAMD_GREYLIST_EXPIRE
  [dkim-rotation-interval-days]=LIMRISTEM_MAIL_DKIM_ROTATION_INTERVAL_DAYS
  [dkim-overlap-days]=LIMRISTEM_MAIL_DKIM_OVERLAP_DAYS
  [dkim-auto-rotate-default]=LIMRISTEM_MAIL_DKIM_AUTO_ROTATE
  # fail2ban: DEFAULT section
  [fail2ban-default-maxretry]=LIMRISTEM_MAIL_FAIL2BAN_DEFAULT_MAXRETRY
  [fail2ban-default-findtime]=LIMRISTEM_MAIL_FAIL2BAN_DEFAULT_FINDTIME
  [fail2ban-default-bantime]=LIMRISTEM_MAIL_FAIL2BAN_DEFAULT_BANTIME
  # fail2ban: per-jail overrides
  [fail2ban-sshd-maxretry]=LIMRISTEM_MAIL_FAIL2BAN_SSHD_MAXRETRY
  [fail2ban-sshd-findtime]=LIMRISTEM_MAIL_FAIL2BAN_SSHD_FINDTIME
  [fail2ban-sshd-bantime]=LIMRISTEM_MAIL_FAIL2BAN_SSHD_BANTIME
  [fail2ban-dovecot-maxretry]=LIMRISTEM_MAIL_FAIL2BAN_DOVECOT_MAXRETRY
  [fail2ban-dovecot-findtime]=LIMRISTEM_MAIL_FAIL2BAN_DOVECOT_FINDTIME
  [fail2ban-dovecot-bantime]=LIMRISTEM_MAIL_FAIL2BAN_DOVECOT_BANTIME
  [fail2ban-postfix-maxretry]=LIMRISTEM_MAIL_FAIL2BAN_POSTFIX_MAXRETRY
  [fail2ban-postfix-findtime]=LIMRISTEM_MAIL_FAIL2BAN_POSTFIX_FINDTIME
  [fail2ban-postfix-bantime]=LIMRISTEM_MAIL_FAIL2BAN_POSTFIX_BANTIME
  [fail2ban-postfix-sasl-maxretry]=LIMRISTEM_MAIL_FAIL2BAN_POSTFIX_SASL_MAXRETRY
  [fail2ban-postfix-sasl-findtime]=LIMRISTEM_MAIL_FAIL2BAN_POSTFIX_SASL_FINDTIME
  [fail2ban-postfix-sasl-bantime]=LIMRISTEM_MAIL_FAIL2BAN_POSTFIX_SASL_BANTIME
  [fail2ban-nginx-http-auth-maxretry]=LIMRISTEM_MAIL_FAIL2BAN_NGINX_HTTP_AUTH_MAXRETRY
  [fail2ban-nginx-http-auth-findtime]=LIMRISTEM_MAIL_FAIL2BAN_NGINX_HTTP_AUTH_FINDTIME
  [fail2ban-nginx-http-auth-bantime]=LIMRISTEM_MAIL_FAIL2BAN_NGINX_HTTP_AUTH_BANTIME
  [fail2ban-nginx-botsearch-maxretry]=LIMRISTEM_MAIL_FAIL2BAN_NGINX_BOTSEARCH_MAXRETRY
  [fail2ban-nginx-botsearch-findtime]=LIMRISTEM_MAIL_FAIL2BAN_NGINX_BOTSEARCH_FINDTIME
  [fail2ban-nginx-botsearch-bantime]=LIMRISTEM_MAIL_FAIL2BAN_NGINX_BOTSEARCH_BANTIME
  [fail2ban-limristem-mail-auth-maxretry]=LIMRISTEM_MAIL_FAIL2BAN_LIMRISTEM_MAIL_AUTH_MAXRETRY
  [fail2ban-limristem-mail-auth-findtime]=LIMRISTEM_MAIL_FAIL2BAN_LIMRISTEM_MAIL_AUTH_FINDTIME
  [fail2ban-limristem-mail-auth-bantime]=LIMRISTEM_MAIL_FAIL2BAN_LIMRISTEM_MAIL_AUTH_BANTIME
  [fail2ban-recidive-maxretry]=LIMRISTEM_MAIL_FAIL2BAN_RECIDIVE_MAXRETRY
  [fail2ban-recidive-findtime]=LIMRISTEM_MAIL_FAIL2BAN_RECIDIVE_FINDTIME
  [fail2ban-recidive-bantime]=LIMRISTEM_MAIL_FAIL2BAN_RECIDIVE_BANTIME
)

declare -A LIMIT_DEFAULT_MAP=(
  [postfix-client-connection-rate-limit]=30
  [postfix-client-message-rate-limit]=100
  [postfix-rate-time-unit]=60s
  [message-size-limit]=52428800
  [smtp-recipient-limit]=100
  [smtp-client-connection-count-limit]=50
  [api-auth-fail-limit]=5
  [api-auth-window-seconds]=300
  [api-auth-block-seconds]=900
  [send-rate-burst]=20
  [send-rate-per-minute]=10
  [send-rate-per-hour]=100
  [send-rate-per-day]=500
  [send-rate-per-week]=2000
  [send-rate-per-month]=5000
  [rspamd-action-greylist]=4
  [rspamd-action-add-header]=6
  [rspamd-action-reject]=15
  [rspamd-greylist-delay]=5m
  [rspamd-greylist-expire]=35d
  [dkim-rotation-interval-days]=90
  [dkim-overlap-days]=14
  [dkim-auto-rotate-default]=no
  [fail2ban-default-maxretry]=5
  [fail2ban-default-findtime]=10m
  [fail2ban-default-bantime]=1h
  [fail2ban-sshd-maxretry]=5
  [fail2ban-sshd-findtime]=10m
  [fail2ban-sshd-bantime]=1h
  [fail2ban-dovecot-maxretry]=8
  [fail2ban-dovecot-findtime]=15m
  [fail2ban-dovecot-bantime]=1h
  [fail2ban-postfix-maxretry]=8
  [fail2ban-postfix-findtime]=10m
  [fail2ban-postfix-bantime]=1h
  [fail2ban-postfix-sasl-maxretry]=5
  [fail2ban-postfix-sasl-findtime]=10m
  [fail2ban-postfix-sasl-bantime]=1h
  [fail2ban-nginx-http-auth-maxretry]=5
  [fail2ban-nginx-http-auth-findtime]=10m
  [fail2ban-nginx-http-auth-bantime]=1h
  [fail2ban-nginx-botsearch-maxretry]=10
  [fail2ban-nginx-botsearch-findtime]=10m
  [fail2ban-nginx-botsearch-bantime]=1h
  [fail2ban-limristem-mail-auth-maxretry]=8
  [fail2ban-limristem-mail-auth-findtime]=15m
  [fail2ban-limristem-mail-auth-bantime]=2h
  [fail2ban-recidive-maxretry]=3
  [fail2ban-recidive-findtime]=1d
  [fail2ban-recidive-bantime]=1w
)

# Preferred display order for panel/API consumers.
LIMIT_KEY_ORDER=(
  api-auth-fail-limit
  api-auth-window-seconds
  api-auth-block-seconds
  message-size-limit
  smtp-recipient-limit
  smtp-client-connection-count-limit
  postfix-client-connection-rate-limit
  postfix-client-message-rate-limit
  postfix-rate-time-unit
  send-rate-burst
  send-rate-per-minute
  send-rate-per-hour
  send-rate-per-day
  send-rate-per-week
  send-rate-per-month
  rspamd-action-greylist
  rspamd-action-add-header
  rspamd-action-reject
  rspamd-greylist-delay
  rspamd-greylist-expire
  dkim-rotation-interval-days
  dkim-overlap-days
  dkim-auto-rotate-default
  fail2ban-default-maxretry
  fail2ban-default-findtime
  fail2ban-default-bantime
  fail2ban-sshd-maxretry
  fail2ban-sshd-findtime
  fail2ban-sshd-bantime
  fail2ban-dovecot-maxretry
  fail2ban-dovecot-findtime
  fail2ban-dovecot-bantime
  fail2ban-postfix-maxretry
  fail2ban-postfix-findtime
  fail2ban-postfix-bantime
  fail2ban-postfix-sasl-maxretry
  fail2ban-postfix-sasl-findtime
  fail2ban-postfix-sasl-bantime
  fail2ban-nginx-http-auth-maxretry
  fail2ban-nginx-http-auth-findtime
  fail2ban-nginx-http-auth-bantime
  fail2ban-nginx-botsearch-maxretry
  fail2ban-nginx-botsearch-findtime
  fail2ban-nginx-botsearch-bantime
  fail2ban-limristem-mail-auth-maxretry
  fail2ban-limristem-mail-auth-findtime
  fail2ban-limristem-mail-auth-bantime
  fail2ban-recidive-maxretry
  fail2ban-recidive-findtime
  fail2ban-recidive-bantime
)

usage() {
  cat <<'EOF'
Usage:
  manage-limits.sh show [--json]
  manage-limits.sh set <key> <value>
  manage-limits.sh set-many <key> <value> [<key> <value> ...]
  manage-limits.sh apply

Supported keys:
  api-auth-fail-limit / api-auth-window-seconds / api-auth-block-seconds
  message-size-limit / smtp-recipient-limit / smtp-client-connection-count-limit
  postfix-client-connection-rate-limit / postfix-client-message-rate-limit / postfix-rate-time-unit
  send-rate-burst / send-rate-per-minute / send-rate-per-hour / send-rate-per-day / send-rate-per-week / send-rate-per-month
  rspamd-action-greylist / rspamd-action-add-header / rspamd-action-reject
  rspamd-greylist-delay / rspamd-greylist-expire
  dkim-rotation-interval-days / dkim-overlap-days / dkim-auto-rotate-default
  fail2ban-default-maxretry / fail2ban-default-findtime / fail2ban-default-bantime
  fail2ban-sshd-{maxretry,findtime,bantime}
  fail2ban-dovecot-{maxretry,findtime,bantime}
  fail2ban-postfix-{maxretry,findtime,bantime}
  fail2ban-postfix-sasl-{maxretry,findtime,bantime}
  fail2ban-nginx-http-auth-{maxretry,findtime,bantime}
  fail2ban-nginx-botsearch-{maxretry,findtime,bantime}
  fail2ban-limristem-mail-auth-{maxretry,findtime,bantime}
  fail2ban-recidive-{maxretry,findtime,bantime}
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"
}

set_env_value() {
  local key=$1
  local value=$2
  limristem_mail_upsert_env_value "$ENV_FILE" "$key" "$value"
}

limit_value() {
  local key=$1
  local env_key=${LIMIT_ENV_MAP[$key]}
  local default=${LIMIT_DEFAULT_MAP[$key]}
  printf '%s\n' "${!env_key:-$default}"
}

validate_limit_value() {
  local key=$1
  local value=$2
  case "$key" in
    api-auth-fail-limit|api-auth-window-seconds|api-auth-block-seconds|message-size-limit|smtp-recipient-limit|smtp-client-connection-count-limit|postfix-client-connection-rate-limit|postfix-client-message-rate-limit|send-rate-burst|send-rate-per-minute|send-rate-per-hour|send-rate-per-day|send-rate-per-week|send-rate-per-month|dkim-rotation-interval-days|dkim-overlap-days|rspamd-action-greylist|rspamd-action-add-header|rspamd-action-reject|fail2ban-*-maxretry)
      if [[ ! "$value" =~ ^[0-9]+$ ]] || (( value < 0 )); then
        echo "Invalid numeric value for $key: $value" >&2
        exit 1
      fi
      ;;
    postfix-rate-time-unit|rspamd-greylist-delay|rspamd-greylist-expire|fail2ban-*-findtime|fail2ban-*-bantime)
      # fail2ban durations: N, Ns, Nm, Nh, Nd, Nw
      if [[ ! "$value" =~ ^[0-9]+[smhdw]?$ ]]; then
        echo "Invalid duration value for $key: $value (use e.g. 10m, 1h, 1d, 1w)" >&2
        exit 1
      fi
      ;;
    dkim-auto-rotate-default)
      case "${value,,}" in
        yes|no|true|false|1|0|on|off) ;;
        *)
          echo "Invalid boolean value for $key: $value (use yes/no)" >&2
          exit 1
          ;;
      esac
      ;;
  esac
}

show_limits() {
  local as_json=${1:-no}
  local key env_key value
  if [[ "$as_json" == "yes" ]]; then
    printf '{'
    local first=yes
    for key in "${LIMIT_KEY_ORDER[@]}"; do
      env_key=${LIMIT_ENV_MAP[$key]}
      value=${!env_key:-${LIMIT_DEFAULT_MAP[$key]}}
      if [[ "$first" == "yes" ]]; then
        first=no
      else
        printf ','
      fi
      python3 - "$key" "$value" <<'PY'
import json
import sys
print(json.dumps(sys.argv[1]) + ":" + json.dumps(sys.argv[2]), end="")
PY
    done
    printf '}\n'
    return 0
  fi
  for key in "${LIMIT_KEY_ORDER[@]}"; do
    env_key=${LIMIT_ENV_MAP[$key]}
    value=${!env_key:-${LIMIT_DEFAULT_MAP[$key]}}
    printf '%s=%s\n' "$key" "$value"
  done
}

detect_rspamd_user() {
  if id _rspamd >/dev/null 2>&1; then
    printf '_rspamd\n'
  elif id rspamd >/dev/null 2>&1; then
    printf 'rspamd\n'
  fi
}

write_rspamd_limits() {
  local rspamd_service_user
  local burst=${LIMRISTEM_MAIL_SEND_RATE_BURST:-20}
  local per_min=${LIMRISTEM_MAIL_SEND_RATE_PER_MINUTE:-10}
  local per_hour=${LIMRISTEM_MAIL_SEND_RATE_PER_HOUR:-100}
  local per_day=${LIMRISTEM_MAIL_SEND_RATE_PER_DAY:-500}
  local per_week=${LIMRISTEM_MAIL_SEND_RATE_PER_WEEK:-2000}
  local per_month=${LIMRISTEM_MAIL_SEND_RATE_PER_MONTH:-5000}
  mkdir -p /etc/rspamd/local.d
  cat > /etc/rspamd/local.d/actions.conf <<EOF
reject = ${LIMRISTEM_MAIL_RSPAMD_ACTION_REJECT:-15};
add_header = ${LIMRISTEM_MAIL_RSPAMD_ACTION_ADD_HEADER:-6};
greylist = ${LIMRISTEM_MAIL_RSPAMD_ACTION_GREYLIST:-4};
EOF
  cat > /etc/rspamd/local.d/greylist.conf <<EOF
enabled = ${LIMRISTEM_MAIL_RSPAMD_GREYLIST_ENABLED:-true};
timeout = ${LIMRISTEM_MAIL_RSPAMD_GREYLIST_DELAY:-5m};
expire = ${LIMRISTEM_MAIL_RSPAMD_GREYLIST_EXPIRE:-35d};
key_prefix = "grey";
EOF
  # Per-authenticated-user outbound rate limits (anti-spam / abuse).
  cat > /etc/rspamd/local.d/ratelimit.conf <<EOF
# Generated by Limristem eMail manage-limits.sh
# Limits apply to authenticated SMTP users (selector = user).
rates {
  send_mail = {
    selector = "user";
    bucket = [
      {
        burst = ${burst};
        rate = "${per_min} / 1m";
      },
      {
        burst = ${burst};
        rate = "${per_hour} / 1h";
      },
      {
        burst = ${burst};
        rate = "${per_day} / 1d";
      },
      {
        burst = ${burst};
        rate = "${per_week} / 7d";
      },
      {
        burst = ${burst};
        rate = "${per_month} / 30d";
      }
    ];
  }
}
EOF
  rspamd_service_user=$(detect_rspamd_user || true)
  if [[ -n "$rspamd_service_user" ]]; then
    chown root:"$rspamd_service_user" \
      /etc/rspamd/local.d/actions.conf \
      /etc/rspamd/local.d/greylist.conf \
      /etc/rspamd/local.d/ratelimit.conf
    chmod 640 \
      /etc/rspamd/local.d/actions.conf \
      /etc/rspamd/local.d/greylist.conf \
      /etc/rspamd/local.d/ratelimit.conf
  fi
}

write_fail2ban_limits() {
  local jail_dir=/etc/fail2ban/jail.d
  local jail_file=$jail_dir/limristem-mail.local
  local d_maxretry d_findtime d_bantime
  local sshd_maxretry sshd_findtime sshd_bantime
  local dovecot_maxretry dovecot_findtime dovecot_bantime
  local postfix_maxretry postfix_findtime postfix_bantime
  local postfix_sasl_maxretry postfix_sasl_findtime postfix_sasl_bantime
  local nginx_http_maxretry nginx_http_findtime nginx_http_bantime
  local nginx_bot_maxretry nginx_bot_findtime nginx_bot_bantime
  local mail_auth_maxretry mail_auth_findtime mail_auth_bantime
  local recidive_maxretry recidive_findtime recidive_bantime

  d_maxretry=$(limit_value fail2ban-default-maxretry)
  d_findtime=$(limit_value fail2ban-default-findtime)
  d_bantime=$(limit_value fail2ban-default-bantime)
  sshd_maxretry=$(limit_value fail2ban-sshd-maxretry)
  sshd_findtime=$(limit_value fail2ban-sshd-findtime)
  sshd_bantime=$(limit_value fail2ban-sshd-bantime)
  dovecot_maxretry=$(limit_value fail2ban-dovecot-maxretry)
  dovecot_findtime=$(limit_value fail2ban-dovecot-findtime)
  dovecot_bantime=$(limit_value fail2ban-dovecot-bantime)
  postfix_maxretry=$(limit_value fail2ban-postfix-maxretry)
  postfix_findtime=$(limit_value fail2ban-postfix-findtime)
  postfix_bantime=$(limit_value fail2ban-postfix-bantime)
  postfix_sasl_maxretry=$(limit_value fail2ban-postfix-sasl-maxretry)
  postfix_sasl_findtime=$(limit_value fail2ban-postfix-sasl-findtime)
  postfix_sasl_bantime=$(limit_value fail2ban-postfix-sasl-bantime)
  nginx_http_maxretry=$(limit_value fail2ban-nginx-http-auth-maxretry)
  nginx_http_findtime=$(limit_value fail2ban-nginx-http-auth-findtime)
  nginx_http_bantime=$(limit_value fail2ban-nginx-http-auth-bantime)
  nginx_bot_maxretry=$(limit_value fail2ban-nginx-botsearch-maxretry)
  nginx_bot_findtime=$(limit_value fail2ban-nginx-botsearch-findtime)
  nginx_bot_bantime=$(limit_value fail2ban-nginx-botsearch-bantime)
  mail_auth_maxretry=$(limit_value fail2ban-limristem-mail-auth-maxretry)
  mail_auth_findtime=$(limit_value fail2ban-limristem-mail-auth-findtime)
  mail_auth_bantime=$(limit_value fail2ban-limristem-mail-auth-bantime)
  recidive_maxretry=$(limit_value fail2ban-recidive-maxretry)
  recidive_findtime=$(limit_value fail2ban-recidive-findtime)
  recidive_bantime=$(limit_value fail2ban-recidive-bantime)

  mkdir -p "$jail_dir"
  cat > "$jail_file" <<EOF
# Limristem eMail fail2ban jails (generated by manage-limits.sh).
# Do not edit by hand; change via: limristem-mail limits set fail2ban-...
# Installed as /etc/fail2ban/jail.d/limristem-mail.local

[DEFAULT]
banaction = nftables-multiport
backend = systemd
findtime = ${d_findtime}
bantime = ${d_bantime}
maxretry = ${d_maxretry}

[sshd]
enabled = true
backend = systemd
port = ssh
filter = sshd
journalmatch = _SYSTEMD_UNIT=ssh.service + _COMM=sshd
maxretry = ${sshd_maxretry}
findtime = ${sshd_findtime}
bantime = ${sshd_bantime}

# Dovecot IMAP/POP auth failures
[dovecot]
enabled = true
backend = systemd
filter = dovecot
port = pop3,pop3s,imap,imaps,submission,465,sieve
journalmatch = _SYSTEMD_UNIT=dovecot.service + _COMM=dovecot
maxretry = ${dovecot_maxretry}
findtime = ${dovecot_findtime}
bantime = ${dovecot_bantime}

# Postfix SMTP (generic)
[postfix]
enabled = true
backend = systemd
filter = postfix[mode=more]
port = smtp,ssmtp,submission,465
journalmatch = _SYSTEMD_UNIT=postfix.service + _COMM=smtpd
maxretry = ${postfix_maxretry}
findtime = ${postfix_findtime}
bantime = ${postfix_bantime}

# Postfix SASL auth failures (submission)
[postfix-sasl]
enabled = true
backend = systemd
filter = postfix[mode=auth]
port = smtp,ssmtp,submission,465
journalmatch = _SYSTEMD_UNIT=postfix.service + _COMM=smtpd
maxretry = ${postfix_sasl_maxretry}
findtime = ${postfix_sasl_findtime}
bantime = ${postfix_sasl_bantime}

# Nginx basic auth / bot probes
[nginx-http-auth]
enabled = true
backend = systemd
port = http,https
filter = nginx-http-auth
journalmatch = _SYSTEMD_UNIT=nginx.service + _COMM=nginx
maxretry = ${nginx_http_maxretry}
findtime = ${nginx_http_findtime}
bantime = ${nginx_http_bantime}

[nginx-botsearch]
enabled = true
backend = systemd
port = http,https
filter = nginx-botsearch
journalmatch = _SYSTEMD_UNIT=nginx.service + _COMM=nginx
maxretry = ${nginx_bot_maxretry}
findtime = ${nginx_bot_findtime}
bantime = ${nginx_bot_bantime}

# Limristem panel/API auth (custom filter)
[limristem-mail-auth]
enabled = true
backend = systemd
port = http,https
filter = limristem-mail-auth
journalmatch = _SYSTEMD_UNIT=limristem-mail.service
maxretry = ${mail_auth_maxretry}
findtime = ${mail_auth_findtime}
bantime = ${mail_auth_bantime}

# Repeat offenders
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
backend = auto
maxretry = ${recidive_maxretry}
findtime = ${recidive_findtime}
bantime = ${recidive_bantime}
EOF
  chmod 644 "$jail_file"

  if command -v fail2ban-client >/dev/null 2>&1; then
    if fail2ban-client -t >/dev/null 2>&1; then
      systemctl reload fail2ban >/dev/null 2>&1 \
        || systemctl restart fail2ban >/dev/null 2>&1 \
        || true
    else
      echo "Warning: fail2ban config test failed after writing $jail_file" >&2
    fi
  fi
}

apply_limits() {
  if command -v postconf >/dev/null 2>&1; then
    postconf -e "anvil_rate_time_unit = ${LIMRISTEM_MAIL_POSTFIX_RATE_TIME_UNIT:-60s}"
    postconf -e "smtpd_client_connection_rate_limit = ${LIMRISTEM_MAIL_POSTFIX_CLIENT_CONNECTION_RATE_LIMIT:-30}"
    postconf -e "smtpd_client_message_rate_limit = ${LIMRISTEM_MAIL_POSTFIX_CLIENT_MESSAGE_RATE_LIMIT:-100}"
    postconf -e "message_size_limit = ${LIMRISTEM_MAIL_MESSAGE_SIZE_LIMIT:-52428800}"
    postconf -e "mailbox_size_limit = 0"
    postconf -e "smtpd_recipient_limit = ${LIMRISTEM_MAIL_SMTP_RECIPIENT_LIMIT:-100}"
    postconf -e "smtpd_client_connection_count_limit = ${LIMRISTEM_MAIL_SMTP_CLIENT_CONNECTION_COUNT_LIMIT:-50}"
    systemctl reload postfix >/dev/null 2>&1 || systemctl restart postfix >/dev/null 2>&1 || true
  fi

  if [[ "${LIMRISTEM_MAIL_ENABLE_RSPAMD:-yes}" == "yes" ]]; then
    write_rspamd_limits
    systemctl restart rspamd >/dev/null 2>&1 || true
  fi

  write_fail2ban_limits

  # Rebuild per-mailbox Redis profiles so overrides re-merge against new globals.
  if [[ -x "${LIMRISTEM_MAIL_BASE_DIR:-/opt/limristem-mail}/limristem-mail" ]]; then
    sudo -u limristem-mail -n "${LIMRISTEM_MAIL_BASE_DIR:-/opt/limristem-mail}/limristem-mail" accounts sync-send-limits --json >/dev/null 2>&1 \
      || "${LIMRISTEM_MAIL_BASE_DIR:-/opt/limristem-mail}/limristem-mail" accounts sync-send-limits --json >/dev/null 2>&1 \
      || true
  fi

  systemctl restart --no-block limristem-mail >/dev/null 2>&1 || true
}

set_limit() {
  local key=$1
  local value=$2
  local env_key=${LIMIT_ENV_MAP[$key]:-}
  if [[ -z "$env_key" ]]; then
    echo "Unknown limit key: $key" >&2
    exit 1
  fi
  validate_limit_value "$key" "$value"
  set_env_value "$env_key" "$value"
  load_env
  apply_limits
}

set_limits_batch() {
  if (( $# == 0 || $# % 2 != 0 )); then
    echo "set-many requires <key> <value> pairs" >&2
    exit 1
  fi
  local key value env_key
  while (( $# > 0 )); do
    key=$1
    value=$2
    env_key=${LIMIT_ENV_MAP[$key]:-}
    if [[ -z "$env_key" ]]; then
      echo "Unknown limit key: $key" >&2
      exit 1
    fi
    validate_limit_value "$key" "$value"
    set_env_value "$env_key" "$value"
    shift 2
  done
  load_env
  apply_limits
}

require_root
load_env

# Write commands mutate /etc (rspamd, postfix, fail2ban) and must escape the app's
# read-only mount namespace when invoked from the panel/API (see libenv.sh).
case "${1:-}" in
  set|set-many|apply)
    limristem_mail_escape_write_namespace LIMRISTEM_MAIL_LIMITS_WORKER limristem-mail-limits "$@"
    ;;
esac

command=${1:-}
case "$command" in
  show)
    if [[ ${2:-} == "--json" ]]; then
      show_limits yes
    else
      show_limits no
    fi
    ;;
  set)
    set_limit "${2:?key required}" "${3:?value required}"
    ;;
  set-many)
    shift
    set_limits_batch "$@"
    ;;
  apply)
    apply_limits
    echo "Limits applied (postfix, rspamd, fail2ban)."
    ;;
  *)
    usage >&2
    exit 1
    ;;
esac
