#!/usr/bin/env bash
#
# onx-hostname-set — Sunucu hostname'ini kalıcı + transient + pretty olarak değiştirir.
#
# Mail (Postfix HELO/myhostname), SSL CSR Common Name, syslog facility, ve
# sunucu kimliği için kritik. hostnamectl 3 değeri set eder (--static --transient --pretty),
# ek olarak Postfix myhostname güncellenir ve gerekli servisler reload edilir.
#
# Stdin (JSON):
#   {"hostname": "mail.onoxsoft.com.tr", "pretty": "ONOXSOFT Panel"}
#
# Stdout (JSON):
#   {
#     "ok": true,
#     "old_hostname": "...",
#     "new_hostname": "...",
#     "postfix_reloaded": true,
#     "rsyslog_reloaded": true,
#     "warnings": []
#   }
#
# Exit codes:
#   0 = ok
#   1 = invalid input (regex fail / hostname yok)
#   2 = preflight (hostnamectl yok / yetki yok)
#   3 = execution fail (hostnamectl set-hostname FAILED)

set -uo pipefail

INPUT=$(cat 2>/dev/null || echo '{}')
NEW_HOSTNAME=$(echo "$INPUT" | jq -r '.hostname // ""' 2>/dev/null)
NEW_PRETTY=$(echo "$INPUT" | jq -r '.pretty // ""' 2>/dev/null)

# Validation — RFC 1123 lite (FQDN gerekiyor, en az 1 nokta)
if [[ -z "$NEW_HOSTNAME" ]]; then
    jq -nc '{ok:false,error:"hostname zorunlu"}' >&2
    exit 1
fi

# Karakter whitelist: a-z 0-9 . -, başlangıç/bitiş alfanumerik, max 253 char
if [[ ${#NEW_HOSTNAME} -gt 253 ]]; then
    jq -nc '{ok:false,error:"hostname 253 karakterden uzun olamaz"}' >&2
    exit 1
fi

if [[ ! "$NEW_HOSTNAME" =~ ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ ]]; then
    jq -nc --arg h "$NEW_HOSTNAME" '{ok:false,error:"geçersiz hostname format (sadece a-z 0-9 . -)",hostname:$h}' >&2
    exit 1
fi

# FQDN check (en az 1 nokta — server1.example.com gibi)
if [[ "$NEW_HOSTNAME" != *.* ]]; then
    jq -nc '{ok:false,error:"FQDN gerekli (en az 1 nokta — örn: server.example.com)"}' >&2
    exit 1
fi

# Pretty validation (opsiyonel — UTF-8 izinli, kontrol karakteri yasak)
if [[ -n "$NEW_PRETTY" ]]; then
    if [[ "$NEW_PRETTY" =~ [[:cntrl:]] ]]; then
        jq -nc '{ok:false,error:"pretty_hostname içinde kontrol karakteri olamaz"}' >&2
        exit 1
    fi
    if [[ ${#NEW_PRETTY} -gt 64 ]]; then
        jq -nc '{ok:false,error:"pretty_hostname 64 karakterden uzun olamaz"}' >&2
        exit 1
    fi
fi

# Preflight
if ! command -v hostnamectl >/dev/null 2>&1; then
    jq -nc '{ok:false,error:"hostnamectl yok (systemd gerekli)"}' >&2
    exit 2
fi

OLD_HOSTNAME=$(hostnamectl --static 2>/dev/null || cat /etc/hostname 2>/dev/null || echo "unknown")

# Idempotent — aynıysa çık
if [[ "$OLD_HOSTNAME" == "$NEW_HOSTNAME" && -z "$NEW_PRETTY" ]]; then
    jq -nc \
        --arg h "$NEW_HOSTNAME" \
        '{ok:true, old_hostname:$h, new_hostname:$h, postfix_reloaded:false, rsyslog_reloaded:false, warnings:["hostname zaten aynı"]}'
    exit 0
fi

WARNINGS_JSON="[]"
add_warning() {
    WARNINGS_JSON=$(echo "$WARNINGS_JSON" | jq -c --arg w "$1" '. += [$w]')
}

# === 1. hostnamectl ile static + transient set
if ! hostnamectl set-hostname "$NEW_HOSTNAME" 2>/dev/null; then
    jq -nc --arg h "$NEW_HOSTNAME" '{ok:false,error:"hostnamectl set-hostname FAILED",hostname:$h}' >&2
    exit 3
fi

# Pretty (opsiyonel)
if [[ -n "$NEW_PRETTY" ]]; then
    hostnamectl set-hostname "$NEW_PRETTY" --pretty 2>/dev/null || add_warning "pretty hostname set edilemedi"
fi

# === 2. /etc/hosts güncelleme — eski hostname'i değiştir (yoksa ekle)
if [[ -w /etc/hosts ]]; then
    # 127.0.0.1 satırında eski hostname varsa replace, yoksa append
    if grep -qE "^127\.0\.1\.1\b" /etc/hosts 2>/dev/null; then
        # Debian-style 127.0.1.1 satırı varsa hostname'i değiştir
        sed -i -E "s/^(127\.0\.1\.1[[:space:]]+).*$/\1${NEW_HOSTNAME} ${NEW_HOSTNAME%%.*}/" /etc/hosts
    elif grep -qE "^127\.0\.0\.1\b" /etc/hosts 2>/dev/null; then
        # Eski hostname satırın sonunda varsa kaldır, yeni hostname ekle
        SHORT_NAME="${NEW_HOSTNAME%%.*}"
        # Eski FQDN ve short formları kaldır (idempotent)
        OLD_SHORT="${OLD_HOSTNAME%%.*}"
        if [[ -n "$OLD_HOSTNAME" && "$OLD_HOSTNAME" != "unknown" ]]; then
            sed -i -E "s/[[:space:]]+${OLD_HOSTNAME}\b//g; s/[[:space:]]+${OLD_SHORT}\b//g" /etc/hosts 2>/dev/null || true
        fi
        # 127.0.0.1 satırına yeni hostname'i ekle (zaten yoksa)
        if ! grep -qE "^127\.0\.0\.1.*${NEW_HOSTNAME}\b" /etc/hosts; then
            sed -i -E "s/^(127\.0\.0\.1[[:space:]]+localhost.*)$/\1 ${NEW_HOSTNAME} ${SHORT_NAME}/" /etc/hosts
        fi
    else
        echo "127.0.0.1 localhost ${NEW_HOSTNAME} ${NEW_HOSTNAME%%.*}" >> /etc/hosts
    fi
else
    add_warning "/etc/hosts yazılamadı"
fi

# === 3. Postfix myhostname update
POSTFIX_RELOADED="false"
if command -v postconf >/dev/null 2>&1 && [[ -f /etc/postfix/main.cf ]]; then
    postconf -e "myhostname=${NEW_HOSTNAME}" 2>/dev/null || add_warning "postconf myhostname FAIL"
    # myorigin = $myhostname pattern'iyse zaten otomatik update
    if systemctl is-active --quiet postfix 2>/dev/null; then
        if systemctl reload postfix 2>/dev/null; then
            POSTFIX_RELOADED="true"
        else
            add_warning "postfix reload FAIL"
        fi
    fi
fi

# === 4. Rsyslog reload (host alanı change yansıması)
RSYSLOG_RELOADED="false"
if systemctl is-active --quiet rsyslog 2>/dev/null; then
    if systemctl reload rsyslog 2>/dev/null || systemctl restart rsyslog 2>/dev/null; then
        RSYSLOG_RELOADED="true"
    fi
fi

# === 5. Apache reload — vhost FQDN yanlış olabilir ama panel sertifikası
# değişmediği için reload yeter (graceful — bağlantıları drop etmez)
APACHE_RELOADED="false"
if systemctl is-active --quiet httpd 2>/dev/null; then
    if systemctl reload httpd 2>/dev/null; then
        APACHE_RELOADED="true"
    fi
fi

# === Final output
jq -nc \
    --arg old "$OLD_HOSTNAME" \
    --arg new "$NEW_HOSTNAME" \
    --arg pretty "$NEW_PRETTY" \
    --argjson postfix $([ "$POSTFIX_RELOADED" = "true" ] && echo true || echo false) \
    --argjson rsyslog $([ "$RSYSLOG_RELOADED" = "true" ] && echo true || echo false) \
    --argjson apache $([ "$APACHE_RELOADED" = "true" ] && echo true || echo false) \
    --argjson warnings "$WARNINGS_JSON" \
    '{ok:true, old_hostname:$old, new_hostname:$new, pretty_hostname:$pretty, postfix_reloaded:$postfix, rsyslog_reloaded:$rsyslog, apache_reloaded:$apache, warnings:$warnings}'

exit 0
