#!/usr/bin/env bash
# onx-php-override-write — Write per-domain PHP-FPM override conf.
#
# cPanel "MultiPHP INI Editor" muadili. Her domain için ayrı bir override
# dosyası oluşturur ve FPM'i reload eder.
#
# Input (stdin JSON):
#   username      string  Linux username (onx_xxx)
#   domain        string  Domain adı (example.com)
#   php_version   string  "8.1", "8.2", "8.3", etc.
#   overrides     object  {"memory_limit": "256M", "max_execution_time": "300", ...}
#
# Output (stdout JSON):
#   {"file":..., "applied":true, "directives_count":N}
#
# Exit codes: 0=ok 1=invalid-input 2=preflight-fail 3=exec-fail 4=rolled-back
#
# Deployed to: /usr/local/onoxsoft/bin/onx-php-override-write

set -euo pipefail

SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
# shellcheck source=_lib/common.sh
source "${SCRIPT_DIR}/_lib/common.sh"

# ── Allowed directives whitelist (security boundary) ────────────────────────
# Only these directives may be written to the override file.
ALLOWED_DIRECTIVES=(
    memory_limit
    max_execution_time
    max_input_time
    max_input_vars
    post_max_size
    upload_max_filesize
    max_file_uploads
    allow_url_fopen
    display_errors
    log_errors
    error_reporting
    default_charset
    expose_php
    "session.gc_maxlifetime"
    "session.cookie_httponly"
    "date.timezone"
    "opcache.enable"
    "opcache.memory_consumption"
)

is_allowed_directive() {
    local needle="$1"
    local d
    for d in "${ALLOWED_DIRECTIVES[@]}"; do
        [[ "$d" == "$needle" ]] && return 0
    done
    return 1
}

# ── Read & parse stdin ───────────────────────────────────────────────────────
INPUT=$(cat)
onx_require_json "${INPUT}"

USERNAME=$(onx_json_get "${INPUT}" "username")
DOMAIN=$(onx_json_get "${INPUT}" "domain")
PHP_VERSION=$(onx_json_get "${INPUT}" "php_version")
OVERRIDES_JSON=$(printf '%s' "${INPUT}" | jq -r '.overrides // {} | tostring')

# ── Input validation ─────────────────────────────────────────────────────────
onx_validate_username "${USERNAME}"
onx_validate_domain "${DOMAIN}"

[[ -z "${PHP_VERSION}" ]] && onx_die 1 "php_version is required"
[[ "${PHP_VERSION}" =~ ^[0-9]\.[0-9]$ ]] || onx_die 1 "php_version must be x.y format, got: ${PHP_VERSION}"

# php_version "8.2" → "82"
PHP_VERSION_NODOT="${PHP_VERSION//./}"

# ── Path setup ───────────────────────────────────────────────────────────────
# Store domain override in the same FPM pool directory, as a separate .ini file
# loaded by the pool's php_admin_value includes mechanism.
POOL_DIR="/etc/opt/remi/php${PHP_VERSION_NODOT}/php-fpm.d"
OVERRIDE_FILE="${POOL_DIR}/${USERNAME}-${DOMAIN}.override.conf"
FPM_SERVICE="php${PHP_VERSION_NODOT}-php-fpm"

# ── Preflight ────────────────────────────────────────────────────────────────
[[ -d "${POOL_DIR}" ]] || onx_die 2 "FPM pool dir not found: ${POOL_DIR} (is php${PHP_VERSION_NODOT} installed?)"
command -v systemctl >/dev/null 2>&1 || onx_die 2 "systemctl not found"

# ── Build override conf ──────────────────────────────────────────────────────
TMP_CONF=$(mktemp /tmp/onx-php-override-XXXXXX.conf)
trap 'rm -f "${TMP_CONF}"' EXIT

{
    printf '; onx-php-override-write — auto-generated, DO NOT EDIT manually\n'
    printf '; Account: %s  Domain: %s  PHP: %s\n' "${USERNAME}" "${DOMAIN}" "${PHP_VERSION}"
    printf '; Generated: %s\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
    printf '[%s-%s]\n' "${USERNAME}" "${DOMAIN}"
} >> "${TMP_CONF}"

# Iterate over overrides JSON object
DIRECTIVES_COUNT=0
while IFS= read -r line; do
    DIRECTIVE=$(printf '%s' "${line}" | jq -r '.key')
    VALUE=$(printf '%s' "${line}" | jq -r '.value')

    # Security: skip directives not in whitelist
    if ! is_allowed_directive "${DIRECTIVE}"; then
        onx_log "WARN: skipping non-whitelisted directive: ${DIRECTIVE}"
        continue
    fi

    # Security: reject newlines/semicolons in value
    if [[ "${VALUE}" =~ $'\n' ]] || [[ "${VALUE}" =~ ';' ]]; then
        onx_log "WARN: skipping directive with unsafe chars: ${DIRECTIVE}"
        continue
    fi

    printf 'php_admin_value[%s] = %s\n' "${DIRECTIVE}" "${VALUE}" >> "${TMP_CONF}"
    DIRECTIVES_COUNT=$(( DIRECTIVES_COUNT + 1 ))
done < <(printf '%s' "${OVERRIDES_JSON}" | jq -c 'to_entries[] | {key: .key, value: (.value | tostring)}')

# ── Back up existing file ────────────────────────────────────────────────────
BACKUP_PATH="${OVERRIDE_FILE}.bak.$$"
[[ -f "${OVERRIDE_FILE}" ]] && cp "${OVERRIDE_FILE}" "${BACKUP_PATH}"

install -m 0640 -o root -g root "${TMP_CONF}" "${OVERRIDE_FILE}"

# ── Reload FPM ───────────────────────────────────────────────────────────────
if ! systemctl reload "${FPM_SERVICE}" 2>/dev/null; then
    onx_log "reload failed — trying restart for ${FPM_SERVICE}"
    if ! systemctl restart "${FPM_SERVICE}"; then
        # Rollback
        if [[ -f "${BACKUP_PATH}" ]]; then
            mv "${BACKUP_PATH}" "${OVERRIDE_FILE}"
        else
            rm -f "${OVERRIDE_FILE}"
        fi
        onx_die 4 "FPM service ${FPM_SERVICE} failed to reload/restart; override rolled back"
    fi
fi

rm -f "${BACKUP_PATH}"

# ── Success ──────────────────────────────────────────────────────────────────
onx_json_out \
    "file"             "${OVERRIDE_FILE}" \
    "applied"          "true" \
    "directives_count" "${DIRECTIVES_COUNT}" \
    "php_version"      "${PHP_VERSION}" \
    "domain"           "${DOMAIN}"
