#!/usr/bin/env bash
#
# onx-system-update — dnf package update runner
#
# Stdin:  JSON {
#           "packages": ["httpd","mariadb-server"],  // empty = update all
#           "security_only": true|false
#         }
# Stdout: JSON {
#           "updated_count": N,
#           "packages_updated": ["name-version",...],
#           "reboot_required": true|false,
#           "output_tail": "..."
#         }
# Exit:   0=ok  1=invalid_input  3=execution_fail
#
# NOTE: dnf can take several minutes. SYSAPI_TIMEOUT should be >= 600s for full updates.

set -euo pipefail

die_input() { printf '{"error":"%s","code":1}\n' "$*" >&2; exit 1; }
die_exec()  { printf '{"error":"%s","code":3}\n' "$*" >&2; exit 3; }
json_str()  { printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'; }

# ---------------------------------------------------------------------------
# Parse stdin
# ---------------------------------------------------------------------------
INPUT=$(cat)

SECURITY_ONLY=$(echo "$INPUT" | grep -oP '"security_only"\s*:\s*\K(true|false)' 2>/dev/null | head -1 || echo "false")

# Parse package list — simple extraction assuming no special chars
PACKAGES_RAW=$(echo "$INPUT" | grep -oP '"packages"\s*:\s*\[\K[^\]]*' 2>/dev/null || true)
PACKAGES=()
while IFS= read -r pkg; do
  pkg=$(echo "$pkg" | tr -d '"' | tr -d ' ')
  [[ -z "$pkg" ]] && continue
  # Whitelist: only alphanumeric, hyphen, dot, underscore
  [[ "$pkg" =~ ^[a-zA-Z0-9._-]+$ ]] || die_input "Gecersiz paket adi: ${pkg}"
  PACKAGES+=("$pkg")
done < <(echo "$PACKAGES_RAW" | tr ',' '\n')

# ---------------------------------------------------------------------------
# Build dnf command
# ---------------------------------------------------------------------------
DNF_CMD=(dnf upgrade -y --assumeyes)

if [[ "$SECURITY_ONLY" == "true" ]]; then
  DNF_CMD+=(--security)
fi

if [[ "${#PACKAGES[@]}" -gt 0 ]]; then
  DNF_CMD+=("${PACKAGES[@]}")
fi

# ---------------------------------------------------------------------------
# Run update, capture output
# ---------------------------------------------------------------------------
TMPOUT=$(mktemp /tmp/onx-system-update-XXXXXX.log)
trap 'rm -f "$TMPOUT"' EXIT

EXIT_CODE=0
"${DNF_CMD[@]}" 2>&1 | tee "$TMPOUT" || EXIT_CODE=$?

if [[ "$EXIT_CODE" -ne 0 && "$EXIT_CODE" -ne 100 ]]; then
  # dnf exits 100 when "nothing to do" — treat as ok
  TAIL=$(tail -5 "$TMPOUT" | tr '\n' ' ')
  die_exec "$(json_str "dnf basarisiz (exit ${EXIT_CODE}): ${TAIL}")"
fi

# ---------------------------------------------------------------------------
# Parse updated packages from dnf output
# ---------------------------------------------------------------------------
UPDATED_LIST=()
while IFS= read -r line; do
  # Lines like: "  httpd.x86_64  2.4.63-1.el9  AppStream"
  # or "Upgraded: httpd-2.4.63-1.el9.x86_64"
  if echo "$line" | grep -qP '^\s+\S+\s+\S+-\S+\s+\S+'; then
    PKG_NAME=$(echo "$line" | awk '{print $1}' | sed 's/\..*//')
    PKG_VER=$(echo "$line" | awk '{print $2}')
    [[ -n "$PKG_NAME" ]] && UPDATED_LIST+=("${PKG_NAME}-${PKG_VER}")
  fi
done < <(grep -P '^\s+\S+\s+\S+\s+\S+' "$TMPOUT" 2>/dev/null | head -100 || true)

COUNT=${#UPDATED_LIST[@]}

# Fallback: count "Upgraded" lines
if [[ "$COUNT" -eq 0 ]]; then
  COUNT=$(grep -c '^Upgraded:' "$TMPOUT" 2>/dev/null || echo "0")
fi

# ---------------------------------------------------------------------------
# Reboot required? (kernel, glibc, systemd updates)
# ---------------------------------------------------------------------------
REBOOT_REQUIRED=false
if grep -qiP 'kernel|glibc|systemd|dbus' "$TMPOUT" 2>/dev/null; then
  # Only flag reboot if one of those was actually updated
  if grep -qiP '^Upgraded:.*kernel|^Upgraded:.*glibc|^Upgraded:.*systemd' "$TMPOUT" 2>/dev/null; then
    REBOOT_REQUIRED=true
  fi
  # Also check /run/reboot-required (debian style, sometimes present via plugins)
  [[ -f /run/reboot-required ]] && REBOOT_REQUIRED=true
fi

# Build JSON array for packages_updated
PKG_JSON="["
FIRST=1
for p in "${UPDATED_LIST[@]:0:50}"; do  # cap at 50 entries
  [[ "$FIRST" -eq 0 ]] && PKG_JSON="${PKG_JSON},"
  PKG_JSON="${PKG_JSON}\"$(json_str "$p")\""
  FIRST=0
done
PKG_JSON="${PKG_JSON}]"

# Last 3 lines of dnf output for context
OUTPUT_TAIL=$(tail -3 "$TMPOUT" | tr '\n' ' ' | sed 's/  */ /g')

printf '{"updated_count":%s,"packages_updated":%s,"reboot_required":%s,"output_tail":"%s"}\n' \
  "$COUNT" \
  "$PKG_JSON" \
  "$REBOOT_REQUIRED" \
  "$(json_str "$OUTPUT_TAIL")"

exit 0
