#!/bin/bash
#
# bot.sh - pengaturan perlindungan bot dan pembatas vhost per domain
# Untuk server cPanel/WHM dengan LiteSpeed Enterprise.
#
# Versi ini menggantikan skrip lama yang hanya menulis LsRecaptcha.
# Perubahan utama dibanding versi lama:
#   1. Nama akun cPanel dicari otomatis dari domain, tidak perlu diketik dua kali
#   2. Pembatas vhost memakai direktif yang benar-benar dikenal LiteSpeed
#   3. Pilihan profil cepat, atau kustom bila perlu angka sendiri
#   4. Berkas lama dicadangkan sebelum ditimpa
#   5. Bisa dijalankan non-interaktif untuk otomasi
#   6. Ada mode uji coba yang tidak menyentuh konfigurasi
#
# Lisensi: bebas dipakai dan diubah.
# Diuji pada: cPanel 11.138, LiteSpeed Enterprise 6.3.1, CloudLinux 9
#
set -uo pipefail

VERSI="2.0"

# Direktori dasar, bisa diarahkan ke tempat lain untuk pengujian.
BASE_DIR="${BOT_SH_BASE:-/usr/local/apache/conf/userdata}"
REBUILD_SCRIPT="/scripts/ensure_vhost_includes"
LOG_FILE="${BOT_SH_LOG:-/var/log/bot-sh.log}"

# Berkas sementara untuk menyusun konfigurasi. Dideklarasikan lebih awal agar
# trap pembersih aman dipanggil kapan saja, termasuk saat bantuan ditampilkan.
TMP_CONF=""

# ---------------------------------------------------------------------------
# Tampilan
# ---------------------------------------------------------------------------
if [ -t 1 ]; then
    C_HIJAU=$'\e[32m'; C_KUNING=$'\e[33m'; C_MERAH=$'\e[31m'
    C_BIRU=$'\e[36m'; C_TEBAL=$'\e[1m'; C_NORMAL=$'\e[0m'
else
    C_HIJAU=''; C_KUNING=''; C_MERAH=''; C_BIRU=''; C_TEBAL=''; C_NORMAL=''
fi

info()  { printf '  %s\n' "$*"; }
ok()    { printf '  %s[v]%s %s\n' "$C_HIJAU" "$C_NORMAL" "$*"; }
warn()  { printf '  %s[!]%s %s\n' "$C_KUNING" "$C_NORMAL" "$*"; }
err()   { printf '  %s[x]%s %s\n' "$C_MERAH" "$C_NORMAL" "$*"; }
judul() { printf '\n  %s%s%s\n  %s\n' "$C_TEBAL" "$*" "$C_NORMAL" "$(printf '%.0s-' $(seq 1 ${#1}))"; }
catat() { printf '%s  %s %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$SCRIPT_VERSION_LOG" "$*" >>"$LOG_FILE" 2>/dev/null; }

bersihkan() {
    rm -f "$TMP_CONF" 2>/dev/null
}
trap bersihkan EXIT

# ---------------------------------------------------------------------------
# Pemeriksaan awal
# ---------------------------------------------------------------------------
periksa_lingkungan() {
    if [ "$(id -u)" -ne 0 ]; then
        err "Skrip ini harus dijalankan sebagai root."
        exit 1
    fi

    # BOT_SH_SERVER memaksa jenis server, dipakai untuk pengujian.
    if [ -n "${BOT_SH_SERVER:-}" ]; then
        JENIS_SERVER="$BOT_SH_SERVER"
        VERSI_SERVER="(dipaksa)"
    elif [ -d /usr/local/lsws ]; then
        JENIS_SERVER="litespeed"
        VERSI_SERVER="$(cat /usr/local/lsws/VERSION 2>/dev/null || echo 'tidak diketahui')"
    elif command -v httpd >/dev/null 2>&1; then
        JENIS_SERVER="apache"
        VERSI_SERVER="$(httpd -v 2>/dev/null | head -1 | cut -d: -f2- | sed 's/^ //')"
    else
        err "Tidak menemukan LiteSpeed maupun Apache di server ini."
        err "Bila ini keliru, jalankan dengan BOT_SH_SERVER=litespeed."
        exit 1
    fi

    if [ ! -d "$BASE_DIR" ] && [ -z "${BOT_SH_BASE:-}" ]; then
        err "Direktori konfigurasi tidak ditemukan: $BASE_DIR"
        err "Server ini mungkin bukan cPanel, atau belum pernah menjalankan ensure_vhost_includes."
        exit 1
    fi
}

# ---------------------------------------------------------------------------
# Utilitas domain
# ---------------------------------------------------------------------------
cari_akun() {
    # Memakai /etc/userdomains, jauh lebih cepat daripada whmapi1.
    local d="$1"
    awk -v d="$d" -F': ' '$1 == d { print $2; exit }' /etc/userdomains 2>/dev/null
}

normalkan_domain() {
    local d="$1"
    d="${d#http://}"; d="${d#https://}"; d="${d%%/*}"
    d="${d#www.}"
    printf '%s' "$d" | tr 'A-Z' 'a-z'
}

domain_terdaftar() {
    # Dianggap terdaftar bila muncul di /etc/userdomains atau punya direktorat vhost.
    local d="$1"
    [ -n "$(cari_akun "$d")" ] && return 0
    ls -d "$BASE_DIR"/std/2_4/*/"$d" >/dev/null 2>&1 && return 0
    return 1
}

# ---------------------------------------------------------------------------
# Penyusunan konfigurasi
# ---------------------------------------------------------------------------
# Nilai bawaan tiap profil. Semuanya memakai direktif yang sah.
# Ringan  : situs ramai, pembatas hanya sebagai jaring pengaman
# Sedang  : bawaan, aman untuk sebagian besar situs
# Kuat    : dipakai saat sedang terjadi serangan
profil_ringan()   { RECAPTCHA=0;   DYN=30; STATIC=100; KONEKSI=40; }
profil_sedang()   { RECAPTCHA=50;  DYN=15; STATIC=60;  KONEKSI=25; }
profil_kuat()     { RECAPTCHA=100; DYN=8;  STATIC=30;  KONEKSI=15; }

susun_konfigurasi() {
    local akun="$1" domain="$2"
    local tulis=""

    if [ "$AKTIF" -eq 0 ]; then
        # Mode mati: hanya menuliskan penanda agar mudah dikenali kembali.
        cat <<EOF
# Dikelola oleh bot.sh v${VERSI} - perlindungan bot DINONAKTIFKAN
# Domain: ${domain} | Akun: ${akun} | Diperbarui: $(date '+%Y-%m-%d %H:%M')
# Ubah berkas ini melalui bot.sh, jangan disunting manual.
<IfModule LiteSpeed>
    LsRecaptcha 0
</IfModule>
EOF
        return
    fi

    cat <<EOF
# Dikelola oleh bot.sh v${VERSI}
# Domain: ${domain} | Akun: ${akun} | Profil: ${PROFIL_NAMA}
# Diperbarui: $(date '+%Y-%m-%d %H:%M')
# Ubah berkas ini melalui bot.sh, jangan disunting manual.
EOF

    if [ "$JENIS_SERVER" = "litespeed" ]; then
        cat <<EOF

<IfModule LiteSpeed>
    # Tantangan reCAPTCHA. 0 mati, 100 untuk setiap permintaan.
    LsRecaptcha ${RECAPTCHA}

    # Pembatas vhost per alamat IP.
    # DynReqPerSec   : batas permintaan dinamis (PHP) per detik per IP
    # StaticReqPerSec: batas permintaan berkas statis per detik per IP
    # MaxConnPerClient: batas koneksi serentak per IP
    DynReqPerSec ${DYN}
    StaticReqPerSec ${STATIC}
    MaxConnPerClient ${KONEKSI}
EOF
        tulis="<IfModule LiteSpeed>"
    else
        tulis="<IfModule mod_rewrite.c>"
    fi

    # --- Bagian rewrite ---
    cat <<EOF

    # --- Rewrite: mulai ---
    RewriteEngine On
EOF

    if [ "$BLOK_QUERY" -eq 1 ]; then
        cat <<'EOF'

    # Hentikan permintaan dengan query acak, pola khas flood.
    RewriteCond %{QUERY_STRING} ^[A-Za-z0-9]{8,20}=[A-Za-z0-9]{4,20}$
    RewriteCond %{QUERY_STRING} [A-Z]
    RewriteCond %{QUERY_STRING} [a-z]
    RewriteCond %{QUERY_STRING} [0-9]
    RewriteRule ^/?$ - [F,L]
EOF
    fi

    if [ "$BLOK_CF" -eq 1 ]; then
        cat <<'EOF'

    # Hentikan token tantangan Cloudflare yang diputar ulang.
    RewriteCond %{QUERY_STRING} __cf_chl_rt_tk [NC]
    RewriteRule ^ - [F,L]
EOF
    fi

    if [ "$BLOK_UA" -eq 1 ]; then
        cat <<'EOF'

    # Hentikan perayap yang agresif. Mesin pencari utama sengaja tidak
    # dimasukkan, agar peringkat situs tidak rusak.
    RewriteCond %{HTTP_USER_AGENT} (SemrushBot|AhrefsBot|MJ12bot|DotBot|PetalBot|Bytespider|DataForSeoBot|SerpstatBot|BLEXBot) [NC]
    RewriteRule ^ - [F,L]
EOF
    fi

    if [ "$BLOK_REFERER" -eq 1 ]; then
        cat <<'EOF'

    # Hentikan referer yang memakai templat tak wajar.
    RewriteCond %{HTTP_REFERER} %RAND% [NC]
    RewriteRule ^ - [F,L]
EOF
    fi

    cat <<EOF

    # --- Rewrite: selesai ---
EOF

    if [ "$JENIS_SERVER" = "litespeed" ]; then
        printf '</IfModule>\n'
    else
        printf '</IfModule>\n'
    fi
}

# ---------------------------------------------------------------------------
# Penulisan
# ---------------------------------------------------------------------------
tulis_konfigurasi() {
    local akun="$1" domain="$2"
    local ada_perubahan=0

    for tipe in std ssl; do
        local dir="${BASE_DIR}/${tipe}/2_4/${akun}/${domain}"
        local berkas="${dir}/custom.conf"

        if [ "$UJI_COBA" -eq 1 ]; then
            info "[uji coba] akan menulis: ${berkas}"
            continue
        fi

        mkdir -p "$dir" || { err "Gagal membuat direktori ${dir}"; return 1; }

        if [ -f "$berkas" ]; then
            if diff -q "$berkas" "$TMP_CONF" >/dev/null 2>&1; then
                info "Tidak berubah: ${berkas}"
                continue
            fi
            local cadangan="${berkas}.bak.$(date '+%Y%m%d%H%M%S')"
            cp -p "$berkas" "$cadangan" && info "Dicadangkan: ${cadangan}"
        fi

        install -m 0644 "$TMP_CONF" "$berkas" || { err "Gagal menulis ${berkas}"; return 1; }
        ok "Ditulis: ${berkas}"
        ada_perubahan=1
    done

    return $((1 - ada_perubahan))
}

terapkan() {
    if [ "$UJI_COBA" -eq 1 ]; then
        warn "Mode uji coba, tidak menjalankan pembangunan ulang konfigurasi."
        return 0
    fi

    if [ "$TANPA_RESTART" -eq 1 ]; then
        warn "Penerapan dilewati atas permintaan (--tanpa-restart)."
        info "Jalankan sendiri saat siap:"
        info "  /scripts/rebuildhttpdconf"
        info "  /scripts/ensure_vhost_includes --all-users"
        if [ "$JENIS_SERVER" = "litespeed" ]; then
            info "  /usr/local/lsws/bin/lswsctrl restart"
        else
            info "  systemctl restart httpd"
        fi
        return 0
    fi

    # 1. Bangun ulang httpd.conf dari data cPanel.
    if [ -x /scripts/rebuildhttpdconf ]; then
        info "Membangun ulang httpd.conf..."
        if /scripts/rebuildhttpdconf >/dev/null 2>&1; then
            ok "httpd.conf dibangun ulang."
        else
            warn "rebuildhttpdconf selesai dengan peringatan."
        fi
    else
        warn "/scripts/rebuildhttpdconf tidak ditemukan, dilewati."
    fi

    # 2. Sisipkan include userdata ke tiap vhost. Ini yang membuat custom.conf
    #    benar-benar terbaca pada vhost domain tersebut.
    if [ -x "$REBUILD_SCRIPT" ]; then
        info "Menyisipkan include ke konfigurasi virtual host..."
        if "$REBUILD_SCRIPT" --all-users >/dev/null 2>&1; then
            ok "Include virtual host diperbarui."
        else
            warn "ensure_vhost_includes selesai dengan peringatan."
        fi
    else
        warn "Skrip ${REBUILD_SCRIPT} tidak ditemukan, lewati penyisipan include."
    fi

    # 3. Muat ulang server web. Restart LiteSpeed bersifat graceful, sehingga
    #    koneksi yang sedang berjalan tidak terputus.
    if [ "$JENIS_SERVER" = "litespeed" ]; then
        if [ -x /usr/local/lsws/bin/lswsctrl ]; then
            info "Memuat ulang LiteSpeed..."
            /usr/local/lsws/bin/lswsctrl restart >/dev/null 2>&1
            sleep 2
            if /usr/local/lsws/bin/lswsctrl status 2>/dev/null | grep -qi running; then
                ok "LiteSpeed berjalan normal."
            else
                err "LiteSpeed tidak melaporkan status berjalan."
                err "Periksa konfigurasi dengan: /usr/local/lsws/bin/lshttpd -t"
            fi
        else
            warn "lswsctrl tidak ditemukan. Muat ulang manual: systemctl restart lshttpd"
        fi
    else
        info "Memuat ulang Apache..."
        if systemctl restart httpd >/dev/null 2>&1; then
            ok "Apache dimuat ulang."
        elif [ -x /scripts/restartsrv_httpd ]; then
            /scripts/restartsrv_httpd >/dev/null 2>&1 && ok "Apache dimuat ulang." \
                || err "Gagal memuat ulang Apache."
        else
            err "Gagal memuat ulang Apache."
        fi
    fi
}

status_domain() {
    local akun="$1" domain="$2"
    for tipe in std ssl; do
        local berkas="${BASE_DIR}/${tipe}/2_4/${akun}/${domain}/custom.conf"
        if [ -f "$berkas" ]; then
            local r d s k
            r=$(grep -m1 -oP 'LsRecaptcha\s+\K[0-9]+' "$berkas" 2>/dev/null)
            d=$(grep -m1 -oP 'DynReqPerSec\s+\K[0-9]+' "$berkas" 2>/dev/null)
            s=$(grep -m1 -oP 'StaticReqPerSec\s+\K[0-9]+' "$berkas" 2>/dev/null)
            k=$(grep -m1 -oP 'MaxConnPerClient\s+\K[0-9]+' "$berkas" 2>/dev/null)
            info "${tipe} : reCAPTCHA ${r:-tidak ada}, dinamis ${d:-tidak ada}/detik, statis ${s:-tidak ada}/detik, koneksi ${k:-tidak ada}"
        else
            info "${tipe} : belum ada berkas custom.conf"
        fi
    done
}

# ---------------------------------------------------------------------------
# Alur interaktif
# ---------------------------------------------------------------------------
tanya_angka() {
    local pesan="$1" bawaan="$2" maks="$3" jawab
    while :; do
        # Prompt dikirim ke stderr agar tidak ikut tertangkap command substitution.
        printf '  %s [%s]: ' "$pesan" "$bawaan" >&2
        read -r jawab
        jawab="${jawab:-$bawaan}"
        if [[ "$jawab" =~ ^[0-9]+$ ]] && [ "$jawab" -le "$maks" ]; then
            printf '%s' "$jawab"
            return
        fi
        warn "Masukkan angka antara 0 dan ${maks}."
    done
}

tanya_ya() {
    local pesan="$1" bawaan="${2:-y}" jawab
    printf '  %s (y/t) [%s]: ' "$pesan" "$bawaan"
    read -r jawab
    jawab="${jawab:-$bawaan}"
    [[ "${jawab,,}" =~ ^y ]]
}

pilih_profil() {
    judul "Profil perlindungan"
    cat <<'EOF'
    1) Ringan   situs ramai, pembatas hanya jaring pengaman
    2) Sedang   bawaan, aman untuk sebagian besar situs
    3) Kuat     dipakai saat situs sedang diserang
    4) Kustom   atur semua angka sendiri
    5) Matikan  hanya reCAPTCHA 0, tanpa pembatas vhost
EOF
    printf '  Pilihan [1-5]: '
    read -r p

    case "${p:-2}" in
        1) PROFIL_NAMA="ringan"; profil_ringan; AKTIF=1 ;;
        2|"") PROFIL_NAMA="sedang"; profil_sedang; AKTIF=1 ;;
        3) PROFIL_NAMA="kuat"; profil_kuat; AKTIF=1 ;;
        4)
            PROFIL_NAMA="kustom"
            AKTIF=1
            info "Nilai reCAPTCHA: 0 mematikan, 100 untuk setiap permintaan."
            RECAPTCHA=$(tanya_angka "Tingkat reCAPTCHA" 50 100)
            info "Pembatas dinamis membatasi permintaan PHP per detik per alamat IP."
            info "Nilai kecil membuat situs terasa lambat bila pengunjung ramai."
            DYN=$(tanya_angka "DynReqPerSec (permintaan dinamis per detik)" 15 500)
            STATIC=$(tanya_angka "StaticReqPerSec (permintaan statis per detik)" 60 1000)
            KONEKSI=$(tanya_angka "MaxConnPerClient (koneksi serentak per IP)" 25 500)
            ;;
        5) PROFIL_NAMA="mati"; AKTIF=0; RECAPTCHA=0; DYN=0; STATIC=0; KONEKSI=0 ;;
        *) warn "Pilihan tidak dikenali, memakai profil sedang."; PROFIL_NAMA="sedang"; profil_sedang; AKTIF=1 ;;
    esac
}

pilih_aturan_tambahan() {
    BLOK_QUERY=0; BLOK_CF=0; BLOK_UA=0; BLOK_REFERER=0

    [ "$AKTIF" -eq 0 ] && return

    # Pada mode non-interaktif, aturan tambahan dipakai dengan nilai bawaan.
    if [ "$LEWATI_TAMBAHAN" -eq 1 ]; then
        BLOK_QUERY=1; BLOK_CF=1; BLOK_UA=1; BLOK_REFERER=0
        return
    fi

    judul "Aturan tambahan"
    tanya_ya "Hentikan permintaan dengan query acak (pola flood)" y && BLOK_QUERY=1
    tanya_ya "Hentikan token tantangan Cloudflare yang diputar ulang" y && BLOK_CF=1
    tanya_ya "Hentikan perayap agresif (Semrush, Ahrefs, dan sejenisnya)" y && BLOK_UA=1
    tanya_ya "Hentikan referer bertemplat tak wajar" t && BLOK_REFERER=1
}

bantuan() {
    cat <<EOF
bot.sh v${VERSI} - perlindungan bot dan pembatas vhost untuk cPanel/LiteSpeed

Pemakaian:
  bot.sh                              menu interaktif
  bot.sh --domain example.com         langsung memproses satu domain
  bot.sh --domain example.com --profil kuat
  bot.sh --domain example.com --mati
  bot.sh --domain example.com --status
  bot.sh --domain example.com --uji   uji coba, tidak menulis berkas
  bot.sh --domain example.com --tanpa-restart
                                      tulis berkas, tanpa rebuild dan restart
  bot.sh --bantuan

Profil tersedia: ringan, sedang, kuat, mati
Penyesuaian angka: --recaptcha N --dinamis N --statis N --koneksi N
EOF
}

# ---------------------------------------------------------------------------
# Argumen
# ---------------------------------------------------------------------------
DOMAIN=""; PROFIL=""; AKTIF=1; UJI_COBA=0; MODE=""
TANPA_RESTART=0
LEWATI_TAMBAHAN=0
RECAPTCHA=""; DYN=""; STATIC=""; KONEKSI=""
SCRIPT_VERSION_LOG="bot.sh"

while [ $# -gt 0 ]; do
    case "$1" in
        --domain) DOMAIN="${2:-}"; shift 2 ;;
        --profil) PROFIL="${2:-}"; shift 2 ;;
        --status) MODE="status"; shift ;;
        --mati) MODE="mati"; shift ;;
        --uji|--dry-run) UJI_COBA=1; shift ;;
        --tanpa-restart|--no-restart) TANPA_RESTART=1; shift ;;
        --recaptcha) RECAPTCHA="${2:-}"; shift 2 ;;
        --dinamis) DYN="${2:-}"; shift 2 ;;
        --statis) STATIC="${2:-}"; shift 2 ;;
        --koneksi) KONEKSI="${2:-}"; shift 2 ;;
        --bantuan|-h|--help) bantuan; exit 0 ;;
        *) err "Argumen tidak dikenali: $1"; bantuan; exit 1 ;;
    esac
done

# ---------------------------------------------------------------------------
# Jalan
# ---------------------------------------------------------------------------
main() {
    periksa_lingkungan

    TMP_CONF="$(mktemp /tmp/botsh.XXXXXX)" || { err "Gagal membuat berkas sementara."; exit 1; }

    judul "Perlindungan bot dan pembatas vhost  v${VERSI}"
    info "Server   : ${JENIS_SERVER} ${VERSI_SERVER}"
    info "Direktori: ${BASE_DIR}"

    # --- Domain ---
    if [ -z "$DOMAIN" ]; then
        printf '\n  Masukkan domain (contoh: contoh.com): '
        read -r DOMAIN
    fi
    DOMAIN="$(normalkan_domain "$DOMAIN")"

    if [ -z "$DOMAIN" ]; then
        err "Domain tidak boleh kosong."
        exit 1
    fi

    AKUN="$(cari_akun "$DOMAIN")"
    if [ -z "$AKUN" ]; then
        if domain_terdaftar "$DOMAIN"; then
            AKUN="$(basename "$(dirname "$(ls -d "$BASE_DIR"/std/2_4/*/"$DOMAIN" 2>/dev/null | head -1)")")"
            warn "Akun tidak ada di /etc/userdomains, memakai hasil deteksi direktori: ${AKUN}"
        else
            err "Domain '${DOMAIN}' tidak ditemukan pada server ini."
            err "Periksa penulisan domain, atau pastikan domain memang terdaftar di akun cPanel."
            exit 1
        fi
    fi
    satpam=$(printf '%s' "$AKUN" | tr -d 'A-Za-z0-9._-')
    if [ -n "$satpam" ]; then
        err "Nama akun hasil deteksi tidak wajar, proses dihentikan."
        exit 1
    fi
    ok "Domain ${DOMAIN} dimiliki akun ${AKUN}"

    # --- Mode status ---
    if [ "$MODE" = "status" ]; then
        judul "Status konfigurasi ${DOMAIN}"
        status_domain "$AKUN" "$DOMAIN"
        return
    fi

    # --- Tentukan parameter ---
    # Argumen eksplisit disimpan lebih dulu, karena penetapan profil menimpa
    # variabel yang sama.
    ARG_RECAPTCHA="$RECAPTCHA"; ARG_DYN="$DYN"
    ARG_STATIC="$STATIC"; ARG_KONEKSI="$KONEKSI"

    if [ "$MODE" = "mati" ]; then
        PROFIL_NAMA="mati"; AKTIF=0
        RECAPTCHA=0; DYN=0; STATIC=0; KONEKSI=0
        LEWATI_TAMBAHAN=1
    elif [ -n "$PROFIL" ] || [ -n "$ARG_RECAPTCHA$ARG_DYN$ARG_STATIC$ARG_KONEKSI" ]; then
        case "${PROFIL:-sedang}" in
            ringan) PROFIL_NAMA="ringan"; profil_ringan ;;
            sedang) PROFIL_NAMA="sedang"; profil_sedang ;;
            kuat)   PROFIL_NAMA="kuat";   profil_kuat ;;
            mati)   PROFIL_NAMA="mati";   AKTIF=0; RECAPTCHA=0; DYN=0; STATIC=0; KONEKSI=0 ;;
            *)      err "Profil '${PROFIL}' tidak dikenali (ringan, sedang, kuat, mati)."; exit 1 ;;
        esac

        # Nilai eksplisit menimpa nilai profil.
        if [ -n "$ARG_RECAPTCHA$ARG_DYN$ARG_STATIC$ARG_KONEKSI" ]; then
            PROFIL_NAMA="kustom"
            for n in "$ARG_RECAPTCHA" "$ARG_DYN" "$ARG_STATIC" "$ARG_KONEKSI"; do
                if [ -n "$n" ] && ! [[ "$n" =~ ^[0-9]+$ ]]; then
                    err "Nilai '${n}' bukan angka."
                    exit 1
                fi
            done
            [ -n "$ARG_RECAPTCHA" ] && RECAPTCHA="$ARG_RECAPTCHA"
            [ -n "$ARG_DYN" ] && DYN="$ARG_DYN"
            [ -n "$ARG_STATIC" ] && STATIC="$ARG_STATIC"
            [ -n "$ARG_KONEKSI" ] && KONEKSI="$ARG_KONEKSI"
        fi
        LEWATI_TAMBAHAN=1
    else
        pilih_profil
        pilih_aturan_tambahan
    fi

    # Pada jalur non-interaktif, aturan tambahan ditetapkan dengan nilai bawaan.
    [ "$LEWATI_TAMBAHAN" -eq 1 ] && pilih_aturan_tambahan

    # --- Pratinjau ---
    susun_konfigurasi "$AKUN" "$DOMAIN" >"$TMP_CONF"

    judul "Pratinjau konfigurasi"
    sed 's/^/    /' "$TMP_CONF"

    if [ "$UJI_COBA" -eq 0 ]; then
        if ! tanya_ya "Tulis konfigurasi ini" y; then
            warn "Dibatalkan, tidak ada berkas yang diubah."
            return
        fi
    fi

    judul "Penulisan"
    tulis_konfigurasi "$AKUN" "$DOMAIN"
    terapkan

    judul "Ringkasan"
    ok "Domain    : ${DOMAIN}"
    ok "Akun      : ${AKUN}"
    ok "Profil    : ${PROFIL_NAMA}"
    [ "$AKTIF" -eq 1 ] && ok "Parameter : reCAPTCHA ${RECAPTCHA}, dinamis ${DYN}/detik, statis ${STATIC}/detik, koneksi ${KONEKSI}" \
                       || warn "Perlindungan dinonaktifkan untuk domain ini."

    catat "domain=${DOMAIN} akun=${AKUN} profil=${PROFIL_NAMA} recaptcha=${RECAPTCHA} dinamis=${DYN} statis=${STATIC} koneksi=${KONEKSI}"
    info ""
    info "Catatan penting:"
    info "- Direktif LSRequestPerSec, LSRequestBurst, dan LsRecaptchaMode tidak dikenal"
    info "  LiteSpeed, sehingga tidak dipakai. Penggantinya DynReqPerSec,"
    info "  StaticReqPerSec, dan MaxConnPerClient."
    info "- Googlebot dan Bingbot tidak diblokir, agar peringkat situs tetap aman."
    info "- Berkas lama dicadangkan dengan akhiran .bak.TANGGALWAKTU."
}

main "$@"
