#!/usr/bin/env bash
#
# onx-postfix-transport-write — Postfix transport_maps hash file yönetir.
#
# Email routing için per-domain teslimat hedefi:
#   local      → mail bu sunucuda işlenir (default — Dovecot LMTP)
#   remote     → mail başka SMTP sunucuya forward (Google Workspace gibi)
#   backup     → mail backup MX olarak gelir, primary'ye relay
#   auto       → MX kayıtlarına göre otomatik (transport entry yok = default)
#
# Postfix transport_maps `hash:/etc/postfix/onoxsoft-transport` kullanır,
# main.cf'de zincirde olmalı (install.sh otomatik ekler).
#
# Stdin (JSON):
#   {
#     "action": "set" | "remove" | "list",
#     "domain": "example.com",
#     "routing_mode": "local" | "remote" | "backup" | "auto",
#     "remote_smtp_host": "smtp.remote.com",  // mode=remote/backup için
#     "remote_smtp_port": 25                  // default 25
#   }
#
# Stdout (JSON):
#   {
#     "ok": true,
#     "domain": "...",
#     "transport_path": "...",
#     "entries_written": N,
#     "reload_required": true,
#     "postfix_reloaded": bool
#   }
#
# Exit: 0=ok, 1=invalid input, 2=preflight, 3=exec fail

set -uo pipefail

INPUT=$(cat 2>/dev/null || echo '{}')
ACTION=$(echo "$INPUT" | jq -r '.action // "set"')
DOMAIN=$(echo "$INPUT" | jq -r '.domain // ""')
MODE=$(echo "$INPUT" | jq -r '.routing_mode // "local"')
REMOTE_HOST=$(echo "$INPUT" | jq -r '.remote_smtp_host // ""')
REMOTE_PORT=$(echo "$INPUT" | jq -r '.remote_smtp_port // 25')

TRANSPORT_FILE="/etc/postfix/onoxsoft-transport"

# Preflight
if ! command -v postmap >/dev/null 2>&1; then
    echo '{"error":"postmap (postfix) yüklü değil"}' >&2
    exit 2
fi

# Transport dosyası yoksa oluştur
if [[ ! -f "$TRANSPORT_FILE" ]]; then
    touch "$TRANSPORT_FILE"
    chown root:root "$TRANSPORT_FILE"
    chmod 644 "$TRANSPORT_FILE"
fi

reload_postfix() {
    local reloaded="false"
    if systemctl is-active --quiet postfix 2>/dev/null; then
        if systemctl reload postfix 2>/dev/null; then
            reloaded="true"
        fi
    fi
    echo "$reloaded"
}

# Domain validation (RFC 1035 lite)
validate_domain() {
    local d="$1"
    if [[ -z "$d" ]] || [[ ! "$d" =~ ^[a-zA-Z0-9]([a-zA-Z0-9.-]*[a-zA-Z0-9])?\.[a-zA-Z]{2,}$ ]]; then
        return 1
    fi
    return 0
}

case "$ACTION" in
    set)
        if ! validate_domain "$DOMAIN"; then
            jq -nc --arg d "$DOMAIN" '{ok:false,error:"geçersiz domain",domain:$d}' >&2
            exit 1
        fi

        # Mode validation
        if [[ ! "$MODE" =~ ^(local|remote|backup|auto)$ ]]; then
            jq -nc --arg m "$MODE" '{ok:false,error:"geçersiz routing_mode (local|remote|backup|auto)",mode:$m}' >&2
            exit 1
        fi

        # Build transport entry'si
        # Postfix transport format:
        #   domain    transport:nexthop[:port]
        TRANSPORT_LINE=""
        case "$MODE" in
            local)
                # Bu sunucuda işle — Dovecot LMTP (virtual_transport zaten lmtp:)
                # Açık olarak yazıp diğer transport rules'ı override etmek için
                TRANSPORT_LINE="${DOMAIN}    local:"
                ;;
            remote|backup)
                if [[ -z "$REMOTE_HOST" ]]; then
                    jq -nc --arg m "$MODE" '{ok:false,error:"remote_smtp_host zorunlu (mode=remote|backup)",mode:$m}' >&2
                    exit 1
                fi
                # Domain validate remote_host
                if ! validate_domain "$REMOTE_HOST" && [[ ! "$REMOTE_HOST" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
                    jq -nc --arg h "$REMOTE_HOST" '{ok:false,error:"geçersiz remote_smtp_host",host:$h}' >&2
                    exit 1
                fi
                # Port range
                if [[ ! "$REMOTE_PORT" =~ ^[0-9]+$ ]] || [[ "$REMOTE_PORT" -lt 1 ]] || [[ "$REMOTE_PORT" -gt 65535 ]]; then
                    REMOTE_PORT=25
                fi
                # SMTP relay format: smtp:[host]:port  (bracket = no MX lookup)
                TRANSPORT_LINE="${DOMAIN}    smtp:[${REMOTE_HOST}]:${REMOTE_PORT}"
                ;;
            auto)
                # Auto = transport entry'si KOYMA (Postfix MX lookup yapsın)
                # Eğer önceden entry varsa kaldır
                TRANSPORT_LINE=""
                ;;
        esac

        # Mevcut entry'yi sil (sed — idempotent)
        DOMAIN_ESC=$(echo "$DOMAIN" | sed 's/[]\/$*.^[]/\\&/g')
        sed -i "/^${DOMAIN_ESC}[[:space:]]/d" "$TRANSPORT_FILE"

        # Yeni satırı ekle (auto modunda yok)
        if [[ -n "$TRANSPORT_LINE" ]]; then
            echo "$TRANSPORT_LINE" >> "$TRANSPORT_FILE"
        fi

        # Postmap hash db üret
        if ! postmap "$TRANSPORT_FILE" 2>/dev/null; then
            jq -nc --arg f "$TRANSPORT_FILE" '{ok:false,error:"postmap fail",transport_path:$f}' >&2
            exit 3
        fi

        ENTRIES=$(wc -l < "$TRANSPORT_FILE" | tr -d ' ')
        RELOADED=$(reload_postfix)

        jq -nc \
            --arg domain "$DOMAIN" \
            --arg mode "$MODE" \
            --arg f "$TRANSPORT_FILE" \
            --argjson entries "$ENTRIES" \
            --argjson reloaded "$RELOADED" \
            '{ok:true, action:"set", domain:$domain, routing_mode:$mode, transport_path:$f, entries_written:$entries, reload_required:true, postfix_reloaded:$reloaded}'
        ;;

    remove)
        if ! validate_domain "$DOMAIN"; then
            jq -nc --arg d "$DOMAIN" '{ok:false,error:"geçersiz domain",domain:$d}' >&2
            exit 1
        fi

        DOMAIN_ESC=$(echo "$DOMAIN" | sed 's/[]\/$*.^[]/\\&/g')
        sed -i "/^${DOMAIN_ESC}[[:space:]]/d" "$TRANSPORT_FILE"

        if ! postmap "$TRANSPORT_FILE" 2>/dev/null; then
            jq -nc --arg f "$TRANSPORT_FILE" '{ok:false,error:"postmap fail after remove",transport_path:$f}' >&2
            exit 3
        fi

        ENTRIES=$(wc -l < "$TRANSPORT_FILE" | tr -d ' ')
        RELOADED=$(reload_postfix)

        jq -nc \
            --arg domain "$DOMAIN" \
            --arg f "$TRANSPORT_FILE" \
            --argjson entries "$ENTRIES" \
            --argjson reloaded "$RELOADED" \
            '{ok:true, action:"remove", domain:$domain, transport_path:$f, entries_written:$entries, postfix_reloaded:$reloaded}'
        ;;

    list)
        ENTRIES_JSON="["
        FIRST=1
        while IFS= read -r line; do
            [[ -z "$line" ]] && continue
            [[ "$line" =~ ^# ]] && continue
            D=$(echo "$line" | awk '{print $1}')
            T=$(echo "$line" | awk '{$1=""; print $0}' | sed 's/^[[:space:]]*//')
            [[ -z "$D" ]] && continue
            [[ $FIRST -eq 0 ]] && ENTRIES_JSON+=","
            FIRST=0
            ENTRIES_JSON+=$(jq -nc --arg d "$D" --arg t "$T" '{domain:$d,transport:$t}')
        done < "$TRANSPORT_FILE"
        ENTRIES_JSON+="]"

        ENTRIES=$(wc -l < "$TRANSPORT_FILE" | tr -d ' ')
        jq -nc --arg f "$TRANSPORT_FILE" --argjson entries "$ENTRIES" --argjson list "$ENTRIES_JSON" \
            '{ok:true, action:"list", transport_path:$f, entries:$entries, list:$list}'
        ;;

    *)
        jq -nc --arg a "$ACTION" '{ok:false,error:"bilinmeyen action — set|remove|list",action:$a}' >&2
        exit 1
        ;;
esac

exit 0
