#!/usr/bin/env bash
#
# onx-webserver-fpm-pool-prepare — PHP-FPM pool config'ini multi-webserver
# uyumlu hale getir.
#
# Strateji:
#   1. 'webserver' grubu yarat (yoksa)
#   2. Mevcut web server user'larını (apache, nginx, www-data) bu gruba ekle
#   3. Tüm onoxsoft FPM pool config'lerinde listen.group=webserver, listen.mode=0660
#   4. FPM reload → socket'ler yeni permission'larla recreate edilir
#
# Input: (yok, parametre almıyor — tüm pool'ları tarar)
# Output: {"ok":true,"group_created":bool,"users_added":["apache","nginx"],"pools_updated":N}
#
# v71.1: kusursuz switch için kritik — Apache↔Nginx↔OLS↔Caddy hepsi
# aynı socket'e erişebilmeli.

set -uo pipefail

# 1. webserver group yarat
group_created="false"
if ! getent group webserver >/dev/null 2>&1; then
    groupadd webserver 2>/dev/null && group_created="true"
fi

# 2. Web server user'larını gruba ekle
users_added='[]'
declare -a added_users=()
for user in apache nginx www-data lsws caddy; do
    if id "$user" >/dev/null 2>&1; then
        # Zaten üye mi?
        if ! id -nG "$user" | grep -qw webserver; then
            usermod -a -G webserver "$user" 2>/dev/null && added_users+=("$user")
        fi
    fi
done
users_added=$(printf '%s\n' "${added_users[@]}" | jq -R . | jq -sc .)

# 3. Tüm onoxsoft FPM pool config'lerini bul + update
# Remi: /etc/opt/remi/php82/php-fpm.d/*.conf
# RHEL: /etc/php-fpm.d/*.conf
# Debian: /etc/php/*/fpm/pool.d/*.conf
pools_updated=0
declare -a pool_dirs=(
    /etc/opt/remi/php82/php-fpm.d
    /etc/opt/remi/php81/php-fpm.d
    /etc/opt/remi/php83/php-fpm.d
    /etc/opt/remi/php74/php-fpm.d
    /etc/php-fpm.d
    /etc/php/8.2/fpm/pool.d
    /etc/php/8.1/fpm/pool.d
)

for dir in "${pool_dirs[@]}"; do
    [[ -d "$dir" ]] || continue
    # v73.7: Glob expansion bug fix — panel pool'ları `onx_*` formatında, eski
    # `onoxsoft*` glob match etmiyordu → pools_updated=0 sessizce → switch sonrası
    # 502 (socket apache:onoxsoft-users 0660, nginx erişemez).
    for conf in "$dir"/onoxsoft*.conf "$dir"/onx_*.conf "$dir"/www.conf; do
        [[ -f "$conf" ]] || continue
        # Backup
        cp -a "$conf" "${conf}.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null || true

        # listen.group = webserver
        if grep -qE '^[[:space:]]*listen\.group[[:space:]]*=' "$conf"; then
            sed -i -E 's|^[[:space:]]*listen\.group[[:space:]]*=.*|listen.group = webserver|' "$conf"
        else
            # listen.owner satırından sonra ekle, yoksa sona
            if grep -qE '^[[:space:]]*listen\.owner[[:space:]]*=' "$conf"; then
                sed -i -E '/^[[:space:]]*listen\.owner[[:space:]]*=/a listen.group = webserver' "$conf"
            else
                echo "listen.group = webserver" >> "$conf"
            fi
        fi

        # listen.mode = 0660 (group erişimli)
        if grep -qE '^[[:space:]]*listen\.mode[[:space:]]*=' "$conf"; then
            sed -i -E 's|^[[:space:]]*listen\.mode[[:space:]]*=.*|listen.mode = 0660|' "$conf"
        else
            if grep -qE '^[[:space:]]*listen\.group[[:space:]]*=' "$conf"; then
                sed -i -E '/^[[:space:]]*listen\.group[[:space:]]*=/a listen.mode = 0660' "$conf"
            else
                echo "listen.mode = 0660" >> "$conf"
            fi
        fi

        pools_updated=$((pools_updated + 1))
    done
done

# 4. PHP-FPM service'leri reload — yeni socket permission'larla recreate
# Hangi FPM servisleri kurulu?
declare -a fpm_services=()
for svc in php-fpm php82-php-fpm php83-php-fpm php81-php-fpm php74-php-fpm php8.2-fpm php8.1-fpm; do
    if systemctl list-unit-files "${svc}.service" --no-legend 2>/dev/null | grep -q "$svc"; then
        if systemctl is-active --quiet "$svc"; then
            systemctl reload "$svc" 2>/dev/null || systemctl restart "$svc" 2>/dev/null || true
            fpm_services+=("$svc")
        fi
    fi
done
fpm_reloaded=$(printf '%s\n' "${fpm_services[@]}" | jq -R . | jq -sc .)

# 5. v73.8: Tüm kullanıcı doc_root'larını da multi-webserver erişimine aç.
# Eski Apache-only deployment'tan kalma `apache:apache 750` permission'ları
# nginx user'a 403 verir. `webserver` group + g+rX ile tüm web server'lar
# (apache, nginx, lsws, caddy) erişebilir.
docroots_chgrp=0
for home_parent in /home/users /home; do
    [[ -d "$home_parent" ]] || continue
    for udir in "$home_parent"/*/public_html; do
        [[ -d "$udir" ]] || continue
        # Sadece onoxsoft pattern user'lar (onx_* veya onoxsoft user prefix)
        username=$(basename "$(dirname "$udir")")
        case "$username" in
            onx_*|onoxsoft*)
                chgrp -R webserver "$udir" 2>/dev/null || continue
                # Group'a okuma+geçiş (dir için X, file için r); user/other dokunma
                find "$udir" -type d -exec chmod g+rx {} \; 2>/dev/null
                find "$udir" -type f -exec chmod g+r {} \; 2>/dev/null
                docroots_chgrp=$((docroots_chgrp + 1))
                ;;
        esac
    done
done

# 6. v77.3: Caddy setcap + systemd drop-in + cert permission consolidation.
# Caddy non-root user iken 1024-altı port'a bind edemez → setcap.
# Caddy systemd ProtectHome=true ile /root erişimi engelli → drop-in override.
# acme.sh + letsencrypt cert dosyaları webserver group + 0640 + path traversal yetki.
caddy_setcap_done="false"
caddy_dropin_created="false"
certs_chgrp=0

if command -v caddy >/dev/null 2>&1; then
    # 6a. setcap binary'ye CAP_NET_BIND_SERVICE
    CADDY_BIN=$(command -v caddy)
    if [[ -x "$CADDY_BIN" ]]; then
        current_caps=$(getcap "$CADDY_BIN" 2>/dev/null)
        if [[ "$current_caps" != *"cap_net_bind_service"* ]]; then
            setcap 'cap_net_bind_service=+ep' "$CADDY_BIN" 2>/dev/null && caddy_setcap_done="true"
        else
            caddy_setcap_done="already"
        fi
    fi

    # 6b. systemd drop-in (ProtectHome=no, ReadWritePaths)
    DROPIN_DIR="/etc/systemd/system/caddy.service.d"
    DROPIN_FILE="${DROPIN_DIR}/onoxsoft-permission.conf"
    if [[ ! -f "$DROPIN_FILE" ]]; then
        mkdir -p "$DROPIN_DIR"
        cat > "$DROPIN_FILE" <<'DROPIN_EOF'
# Onoxsoft v77.3 — multi-webserver permission stack for Caddy
# CAP_NET_BIND_SERVICE: 1024-altı port bind (zaten setcap ile binary'de var, defensive)
# ProtectHome=no: /root/.acme.sh cert dosyalarına erişim için (acme.sh default location)
# ReadWritePaths: explicit allow list (security)
[Service]
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_DAC_OVERRIDE CAP_CHOWN CAP_FOWNER CAP_SETUID CAP_SETGID
NoNewPrivileges=false
ProtectHome=no
ProtectSystem=false
ReadWritePaths=/root/.acme.sh /etc/letsencrypt /etc/onoxsoft/ssl /etc/caddy /var/log/caddy /home
DROPIN_EOF
        systemctl daemon-reload 2>/dev/null
        caddy_dropin_created="true"
    fi
fi

# 6c. acme.sh + letsencrypt cert dosyaları webserver group + 0640
if [[ -d "/root/.acme.sh" ]]; then
    # Parent dizinlere traversal yetki (sadece o+x, listing değil)
    chmod o+x /root 2>/dev/null
    chmod o+x /root/.acme.sh 2>/dev/null
    chmod o+x /root/.acme.sh/*/ 2>/dev/null

    # Cert + key dosyaları webserver group + 0640
    for f in /root/.acme.sh/*/fullchain.cer /root/.acme.sh/*/*.key /root/.acme.sh/*/*.csr; do
        [[ -f "$f" ]] || continue
        chgrp webserver "$f" 2>/dev/null && chmod 0640 "$f" 2>/dev/null && certs_chgrp=$((certs_chgrp + 1))
    done
fi

if [[ -d "/etc/letsencrypt" ]]; then
    chmod o+x /etc/letsencrypt 2>/dev/null
    chgrp -R webserver /etc/letsencrypt/live /etc/letsencrypt/archive 2>/dev/null
    chmod g+rx /etc/letsencrypt/live /etc/letsencrypt/archive 2>/dev/null
    find /etc/letsencrypt/live -mindepth 1 -maxdepth 1 -type d -exec chmod g+rx {} \; 2>/dev/null
    find /etc/letsencrypt/archive -mindepth 1 -maxdepth 1 -type d -exec chmod g+rx {} \; 2>/dev/null
    for f in /etc/letsencrypt/live/*/fullchain.pem /etc/letsencrypt/live/*/privkey.pem; do
        [[ -L "$f" || -f "$f" ]] || continue
        chmod 0640 "$f" 2>/dev/null && certs_chgrp=$((certs_chgrp + 1))
    done
    find /etc/letsencrypt/archive -type f \( -name "*.pem" \) -exec chmod 0640 {} \; 2>/dev/null
fi

# Panel cert (/etc/onoxsoft/ssl) — caddy SSL listener için
if [[ -d "/etc/onoxsoft/ssl" ]]; then
    chmod o+x /etc/onoxsoft /etc/onoxsoft/ssl 2>/dev/null
    chgrp -R webserver /etc/onoxsoft/ssl 2>/dev/null
    find /etc/onoxsoft/ssl -type f \( -name "*.fullchain" -o -name "*.key" -o -name "*.pem" \) -exec chmod 0640 {} \; 2>/dev/null
fi

jq -nc \
    --argjson group_created "$group_created" \
    --argjson users_added "$users_added" \
    --argjson pools_updated "$pools_updated" \
    --argjson fpm_reloaded "$fpm_reloaded" \
    --argjson docroots_chgrp "$docroots_chgrp" \
    --arg     caddy_setcap "$caddy_setcap_done" \
    --arg     caddy_dropin "$caddy_dropin_created" \
    --argjson certs_chgrp "$certs_chgrp" \
    '{ok:true,
      group_created:$group_created,
      users_added:$users_added,
      pools_updated:$pools_updated,
      fpm_reloaded:$fpm_reloaded,
      docroots_chgrp:$docroots_chgrp,
      caddy_setcap:$caddy_setcap,
      caddy_dropin:$caddy_dropin,
      certs_chgrp:$certs_chgrp,
      message:"PHP-FPM pool'\''ları multi-webserver uyumlu (v77.3): webserver group + 0660 socket + doc_root chgrp + Caddy setcap/dropin + cert webserver group."}'
