#!/usr/bin/env bash
#
# onx-mail-alias-set — Postfix virtual_alias_maps hash file yönetir.
#
# Mailing list ve generic email alias için kullanılır. Format:
#   <address> <comma_separated_destinations>
#
# Postfix `hash:/etc/postfix/onoxsoft-mailing-lists` map'i okur ve gelen mail'i
# o adrese yönlendirir. main.cf'de virtual_alias_maps zincirine eklenmiş olmalı:
#   virtual_alias_maps = mysql:..., hash:/etc/postfix/onoxsoft-mailing-lists
#
# Stdin (JSON):
#   {"action":"set","address":"team@example.com","destinations":["a@x.com","b@y.com"]}
#   {"action":"remove","address":"team@example.com"}
#   {"action":"list"}
#
# Stdout (JSON):
#   {"ok":true,"map_file":"...","entries":N,"postfix_reloaded":bool}
#
# Exit codes: 0=ok, 1=invalid input, 2=preflight fail, 3=exec fail

set -uo pipefail

INPUT=$(cat 2>/dev/null || echo '{}')
ACTION=$(echo "$INPUT" | jq -r '.action // ""')

MAP_FILE="/etc/postfix/onoxsoft-mailing-lists"
MAP_DB="${MAP_FILE}.db"

if [[ -z "$ACTION" ]]; then
    echo '{"error":"action zorunlu (set|remove|list)"}' >&2
    exit 1
fi

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

# Map dosyası yoksa boş oluştur (Postfix hash:NULL hatasını önle)
if [[ ! -f "$MAP_FILE" ]]; then
    touch "$MAP_FILE"
    chown root:root "$MAP_FILE"
    chmod 644 "$MAP_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"
}

case "$ACTION" in
    set)
        ADDR=$(echo "$INPUT" | jq -r '.address // ""')
        if [[ -z "$ADDR" ]] || [[ ! "$ADDR" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
            jq -nc --arg a "$ADDR" '{ok:false,error:"geçersiz address",address:$a}' >&2
            exit 1
        fi

        # Destinations validate
        DEST_COUNT=$(echo "$INPUT" | jq -r '.destinations | length' 2>/dev/null || echo 0)
        if [[ "$DEST_COUNT" -eq 0 ]]; then
            jq -nc '{ok:false,error:"destinations array boş — en az 1 alıcı gerekli"}' >&2
            exit 1
        fi

        # Her destination email regex check + virgülle birleştir
        DESTINATIONS=""
        while IFS= read -r dest; do
            [[ -z "$dest" ]] && continue
            if [[ ! "$dest" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
                jq -nc --arg d "$dest" '{ok:false,error:"geçersiz destination email",destination:$d}' >&2
                exit 1
            fi
            [[ -n "$DESTINATIONS" ]] && DESTINATIONS+=","
            DESTINATIONS+="$dest"
        done < <(echo "$INPUT" | jq -r '.destinations[]?')

        if [[ -z "$DESTINATIONS" ]]; then
            jq -nc '{ok:false,error:"valid destination yok"}' >&2
            exit 1
        fi

        # Mevcut entry'yi sil (idempotent), yeni satırı ekle
        # ADDR'yi regex-safe escape et (sed için)
        ADDR_ESC=$(echo "$ADDR" | sed 's/[]\/$*.^[]/\\&/g')
        sed -i "/^${ADDR_ESC}[[:space:]]/d" "$MAP_FILE"
        echo "${ADDR} ${DESTINATIONS}" >> "$MAP_FILE"

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

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

        jq -nc --arg addr "$ADDR" --arg dest "$DESTINATIONS" --arg f "$MAP_FILE" \
            --argjson entries "$ENTRIES" --argjson reloaded "$RELOADED" \
            '{ok:true, action:"set", address:$addr, destinations:$dest, map_file:$f, entries:$entries, postfix_reloaded:$reloaded}'
        ;;

    remove)
        ADDR=$(echo "$INPUT" | jq -r '.address // ""')
        if [[ -z "$ADDR" ]]; then
            jq -nc '{ok:false,error:"address zorunlu"}' >&2
            exit 1
        fi

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

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

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

        jq -nc --arg addr "$ADDR" --arg f "$MAP_FILE" \
            --argjson entries "$ENTRIES" --argjson reloaded "$RELOADED" \
            '{ok:true, action:"remove", address:$addr, map_file:$f, entries:$entries, postfix_reloaded:$reloaded}'
        ;;

    list)
        # Tüm map içeriğini JSON array olarak dön
        ENTRIES_JSON="["
        FIRST=1
        while IFS= read -r line; do
            [[ -z "$line" ]] && continue
            [[ "$line" =~ ^# ]] && continue
            ADDR=$(echo "$line" | awk '{print $1}')
            DEST=$(echo "$line" | awk '{$1=""; print $0}' | sed 's/^[[:space:]]*//')
            [[ -z "$ADDR" ]] && continue
            [[ $FIRST -eq 0 ]] && ENTRIES_JSON+=","
            FIRST=0
            ENTRIES_JSON+=$(jq -nc --arg a "$ADDR" --arg d "$DEST" '{address:$a,destinations:$d}')
        done < "$MAP_FILE"
        ENTRIES_JSON+="]"

        ENTRIES=$(wc -l < "$MAP_FILE" | tr -d ' ')
        jq -nc --arg f "$MAP_FILE" --argjson entries "$ENTRIES" --argjson list "$ENTRIES_JSON" \
            '{ok:true, action:"list", map_file:$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
