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

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

load_env() {
  limristem_mail_load_env_file "$LIMRISTEM_MAIL_CONFIG_DIR/limristem-mail.env"
}

mysql_client_cmd() {
  if command -v mariadb >/dev/null 2>&1; then
    printf 'mariadb\n'
  elif command -v mysql >/dev/null 2>&1; then
    printf 'mysql\n'
  else
    return 1
  fi
}

normalize_domain() {
  python3 - "$1" <<'PY'
import re
import sys

candidate = sys.argv[1].strip().rstrip(".").lower()
try:
    candidate = candidate.encode("idna").decode("ascii")
except UnicodeError:
    raise SystemExit("Invalid domain name")
pattern = re.compile(r"^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$")
if not pattern.fullmatch(candidate):
    raise SystemExit("Invalid domain name")
print(candidate)
PY
}

fetch_dkim_record() {
  if [[ -z ${LIMRISTEM_MAIL_DB_HOST:-} || -z ${LIMRISTEM_MAIL_DB_PORT:-} || -z ${LIMRISTEM_MAIL_DB_USER:-} || -z ${LIMRISTEM_MAIL_DB_PASS:-} || -z ${LIMRISTEM_MAIL_DB_NAME:-} ]]; then
    return 0
  fi
  local domain=$1
  local mysql_cmd
  mysql_cmd=$(mysql_client_cmd) || return 0
  MYSQL_PWD="${LIMRISTEM_MAIL_DB_PASS}" "$mysql_cmd" -Nse "SELECT dkim_public_key FROM domains WHERE name='${domain}' LIMIT 1;" \
    -h "${LIMRISTEM_MAIL_DB_HOST}" \
    -P "${LIMRISTEM_MAIL_DB_PORT}" \
    -u"${LIMRISTEM_MAIL_DB_USER}" \
    "${LIMRISTEM_MAIL_DB_NAME}" 2>/dev/null || true
}

load_env

zone_owner() {
  local owner=$1
  local safe_domain=${DOMAIN%.}
  local safe_owner=${owner%.}
  if [[ "$safe_owner" == "$safe_domain" ]]; then
    printf '@'
  elif [[ "$safe_owner" == *".${safe_domain}" ]]; then
    printf '%s' "${safe_owner:0:${#safe_owner}-${#safe_domain}-1}"
  else
    printf '%s.' "$safe_owner"
  fi
}

DOMAIN=${1:-${LIMRISTEM_MAIL_PRIMARY_DOMAIN:-}}
MAIL_HOST=${2:-${LIMRISTEM_MAIL_HOSTNAME:-}}
SELECTOR=${3:-default}
MTA_STS_HOST=${4:-${LIMRISTEM_MAIL_MTA_STS_HOST:-mta-sts.${DOMAIN}}}
TLS_RPT_MAILBOX=${LIMRISTEM_MAIL_TLS_RPT_MAILBOX:-postmaster@${DOMAIN}}
DKIM_VALUE=${5:-$(fetch_dkim_record "$DOMAIN")}
PUBLIC_IP=${6:-${LIMRISTEM_MAIL_PUBLIC_IP:-}}
PUBLIC_IPV6=${7:-${LIMRISTEM_MAIL_PUBLIC_IPV6:-}}
DOMAIN=$(normalize_domain "$DOMAIN")
MAIL_HOST=$(normalize_domain "$MAIL_HOST")
MTA_STS_HOST=$(normalize_domain "$MTA_STS_HOST")
if [[ ! "$SELECTOR" =~ ^[A-Za-z0-9_-]{1,63}$ ]]; then
  echo "Invalid DKIM selector" >&2
  exit 1
fi
MTA_STS_ID=${LIMRISTEM_MAIL_MTA_STS_ID:-$(date -u +%Y%m%d%H%M%S)}
ENABLE_SRS=${LIMRISTEM_MAIL_ENABLE_SRS:-no}
SRS_DOMAIN=${LIMRISTEM_MAIL_SRS_DOMAIN:-}

if [[ -z "$DOMAIN" || -z "$MAIL_HOST" ]]; then
  echo "Usage: generate-dns-plan.sh <domain> [mail-host] [selector] [mta-sts-host] [dkim-value] [public-ip] [public-ipv6]" >&2
  exit 1
fi

printf '; DNS plan for %s\n' "$DOMAIN"
printf '; Publish A/AAAA for %s to your public mail IP(s)\n' "$MAIL_HOST"
if [[ -n "$PUBLIC_IP" ]]; then
  printf '%s IN A %s\n' "$(zone_owner "$MAIL_HOST")" "$PUBLIC_IP"
fi
if [[ -n "$PUBLIC_IPV6" ]]; then
  printf '%s IN AAAA %s\n' "$(zone_owner "$MAIL_HOST")" "$PUBLIC_IPV6"
fi
if [[ -n "$PUBLIC_IP" || -n "$PUBLIC_IPV6" ]]; then
  if [[ "$MTA_STS_HOST" != "$MAIL_HOST" ]]; then
    [[ -n "$PUBLIC_IP" ]] && printf '%s IN A %s\n' "$(zone_owner "$MTA_STS_HOST")" "$PUBLIC_IP"
    [[ -n "$PUBLIC_IPV6" ]] && printf '%s IN AAAA %s\n' "$(zone_owner "$MTA_STS_HOST")" "$PUBLIC_IPV6"
  fi
  printf '\n'
fi
if [[ -n "$PUBLIC_IP" ]]; then
  printf '; Ask your provider to set PTR/rDNS of %s to %s.\n' "$PUBLIC_IP" "$MAIL_HOST"
else
  printf '; Ask your provider to set PTR/rDNS of the public mail IP to %s.\n' "$MAIL_HOST"
fi
if [[ -n "$PUBLIC_IPV6" ]]; then
  printf '; Ask your provider to set IPv6 PTR/rDNS of %s to %s.\n' "$PUBLIC_IPV6" "$MAIL_HOST"
fi
printf '\n'

printf '%s IN MX 10 %s.\n' "$(zone_owner "$DOMAIN")" "$MAIL_HOST"
printf '%s IN TXT "v=spf1 mx a:%s -all"\n' "$(zone_owner "$DOMAIN")" "$MAIL_HOST"
if [[ "$ENABLE_SRS" == "yes" && -n "$SRS_DOMAIN" && "$SRS_DOMAIN" != "$DOMAIN" ]]; then
  printf '%s IN TXT "v=spf1 mx a:%s -all"\n' "$(zone_owner "$SRS_DOMAIN")" "$MAIL_HOST"
fi
printf '%s IN TXT "v=DMARC1; p=reject; adkim=s; aspf=s; pct=100; rua=mailto:postmaster@%s"\n' "$(zone_owner "_dmarc.${DOMAIN}")" "$DOMAIN"
if [[ "${LIMRISTEM_MAIL_SSL_MODE:-}" == "letsencrypt" ]]; then
  printf '%s IN CAA 0 issue "letsencrypt.org"\n' "$(zone_owner "$DOMAIN")"
fi

if [[ -n "$DKIM_VALUE" ]]; then
  printf '%s IN TXT "%s"\n' "$(zone_owner "${SELECTOR}._domainkey.${DOMAIN}")" "$DKIM_VALUE"
else
  printf '; Missing DKIM public key in DB for %s / selector %s\n' "$DOMAIN" "$SELECTOR"
fi

if [[ "${LIMRISTEM_MAIL_ENABLE_MTA_STS:-yes}" == "yes" ]]; then
  printf '%s IN TXT "v=STSv1; id=%s"\n' "$(zone_owner "_mta-sts.${DOMAIN}")" "$MTA_STS_ID"
  printf '; Serve https://%s/.well-known/mta-sts.txt with:\n' "$MTA_STS_HOST"
  printf '; version: STSv1\n'
  printf '; mode: %s\n' "${LIMRISTEM_MAIL_MTA_STS_MODE:-enforce}"
  printf '; mx: %s\n' "$MAIL_HOST"
  printf '; max_age: %s\n' "${LIMRISTEM_MAIL_MTA_STS_MAX_AGE:-604800}"
fi

if [[ "${LIMRISTEM_MAIL_ENABLE_TLS_RPT:-yes}" == "yes" ]]; then
  printf '%s IN TXT "v=TLSRPTv1; rua=mailto:%s"\n' "$(zone_owner "_smtp._tls.${DOMAIN}")" "$TLS_RPT_MAILBOX"
fi
