#!/usr/bin/env bash
#
# onx-panel-update — ONOX panel git pull + composer + npm + migrate
#
# Stdin:  JSON {"branch":"main", "version":null}
#         or   {"branch":"main", "version":"v0.18.5"}
# Stdout: JSON {
#           "old_version": "v0.18.4",
#           "new_version": "v0.18.5",
#           "migrations_run": 3,
#           "success": true
#         }
# Exit:   0=ok  1=invalid_input  3=execution_fail
#
# NOTE: This can take 2-5 minutes. Ensure SYSAPI_TIMEOUT >= 360s.

set -euo pipefail

readonly ONOX_HOME=/opt/onoxsoft

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)

BRANCH=$(echo "$INPUT" | grep -oP '"branch"\s*:\s*"\K[^"]+' 2>/dev/null | head -1 || echo "main")
VERSION=$(echo "$INPUT" | grep -oP '"version"\s*:\s*"\K[^"]+' 2>/dev/null | head -1 || true)
# version may also be null in JSON
echo "$INPUT" | grep -qP '"version"\s*:\s*null' && VERSION=""

# ---------------------------------------------------------------------------
# Progress / detach / rollback (additive — see PushUpdateProgress contract)
# ---------------------------------------------------------------------------
PROGRESS_FILE=$(printf '%s' "$INPUT" | jq -r '.progress_file // empty')
DETACH=$(printf '%s' "$INPUT" | jq -r '.detach // false')
JOB_ID=$(printf '%s' "$INPUT" | jq -r '.job_id // 0')
OLD_VERSION=""; NEW_VERSION=""; UPDATE_ERROR=""
OLD_SHA=""

_progress() {  # pct step [status]
    [[ -z "${PROGRESS_FILE:-}" ]] && return 0
    local pct="$1" step="$2" status="${3:-running}"
    local tmp="${PROGRESS_FILE}.tmp.$$"
    jq -nc --argjson pct "${pct:-0}" --arg step "$step" --arg status "$status" \
        --arg ov "${OLD_VERSION:-}" --arg nv "${NEW_VERSION:-}" --arg err "${UPDATE_ERROR:-}" \
        '{status:$status,percent:$pct,step:$step,message:"",old_version:$ov,new_version:$nv,error:$err}' \
        > "$tmp" 2>/dev/null && mv -f "$tmp" "$PROGRESS_FILE" && chmod 0644 "$PROGRESS_FILE" 2>/dev/null || true
}

# Rollback guard state — flipped to 1 once the panel reaches a consistent state.
SUCCESS=0
LAST_PCT=5

# _rollback_on_failure — EXIT trap (armed AFTER checkout). If the script dies
# (die_exec exit 3, or set -e) before SUCCESS=1, restore the pre-checkout commit
# and best-effort rebuild autoloader+caches so the panel keeps booting. Preserves
# the original exit code so the existing stdout/stderr error contract is intact.
_rollback_on_failure() {
    local rc=$?
    [[ "$SUCCESS" -eq 1 ]] && return 0
    # Restore code to the exact pre-update commit (only if we have an anchor).
    if [[ -n "${OLD_SHA:-}" ]]; then
        git -C "${ONOX_HOME}" reset --hard "$OLD_SHA" >/dev/null 2>&1 || true
    fi
    # Best-effort: rebuild vendor/ + caches against the restored tree.
    composer install --no-dev --optimize-autoloader \
        --working-dir="${ONOX_HOME}" --no-interaction -q >/dev/null 2>&1 || true
    php "${ONOX_HOME}/artisan" config:cache --no-interaction >/dev/null 2>&1 || true
    php "${ONOX_HOME}/artisan" route:cache  --no-interaction >/dev/null 2>&1 || true
    php "${ONOX_HOME}/artisan" view:cache   --no-interaction >/dev/null 2>&1 || true
    [[ -z "${UPDATE_ERROR:-}" ]] && UPDATE_ERROR="guncelleme basarisiz; onceki surume geri alindi"
    _progress "${LAST_PCT:-0}" "geri alindi (hata)" "failed"
    exit "$rc"
}

# Validate branch (no path traversal)
[[ "$BRANCH" =~ ^[a-zA-Z0-9._/-]{1,100}$ ]] || die_input "Gecersiz branch: ${BRANCH}"
[[ "$BRANCH" == *".."* ]] && die_input "Gecersiz branch (path traversal)"

# Validate version tag if provided
if [[ -n "$VERSION" ]]; then
  [[ "$VERSION" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9._-]+)?$ ]] \
    || die_input "Gecersiz versiyon formati: ${VERSION} (beklenen: v1.2.3)"
fi

[[ -d "${ONOX_HOME}/.git" ]] || die_input "Panel git repo bulunamadi: ${ONOX_HOME}"

# ---------------------------------------------------------------------------
# Detach: background self and return within ~1s (non-blocking job runner)
# ---------------------------------------------------------------------------
if [[ "$DETACH" == "true" || "$DETACH" == "1" ]]; then
    relaunch=$(printf '%s' "$INPUT" | jq -c '.detach=false')
    tmp=$(mktemp /tmp/onox-update-relaunch.XXXXXX.json)
    printf '%s' "$relaunch" > "$tmp"
    logf="${PROGRESS_FILE:-/tmp/onox-update}.log"
    setsid bash -c "'$0' < '$tmp'; rm -f '$tmp'" </dev/null >>"$logf" 2>&1 &
    disown 2>/dev/null || true
    printf '{"ok":true,"started":true,"job_id":%s}\n' "${JOB_ID:-0}"
    exit 0
fi

# ---------------------------------------------------------------------------
# Capture old version
# ---------------------------------------------------------------------------
_progress 5 "kod indiriliyor"
OLD_VERSION=$(git -C "${ONOX_HOME}" describe --tags --abbrev=0 2>/dev/null || \
              git -C "${ONOX_HOME}" rev-parse --short HEAD 2>/dev/null || echo "unknown")
# Rollback anchor — exact commit BEFORE checkout/pull (for reset --hard on failure)
OLD_SHA=$(git -C "${ONOX_HOME}" rev-parse HEAD 2>/dev/null || echo "")

# ---------------------------------------------------------------------------
# Git fetch + checkout/pull
# ---------------------------------------------------------------------------
git -C "${ONOX_HOME}" fetch origin 2>&1 \
  || die_exec "$(json_str "git fetch basarisiz")"

if [[ -n "$VERSION" ]]; then
  git -C "${ONOX_HOME}" checkout "tags/${VERSION}" 2>&1 \
    || die_exec "$(json_str "git checkout tags/${VERSION} basarisiz")"
else
  git -C "${ONOX_HOME}" checkout "${BRANCH}" 2>&1 \
    || die_exec "$(json_str "git checkout ${BRANCH} basarisiz")"
  git -C "${ONOX_HOME}" pull origin "${BRANCH}" 2>&1 \
    || die_exec "$(json_str "git pull origin ${BRANCH} basarisiz")"
fi

# Code is now switched — arm rollback for every step from here on.
trap '_rollback_on_failure' EXIT
LAST_PCT=15
_progress 15 "bagimliliklar (composer)"

NEW_VERSION=$(git -C "${ONOX_HOME}" describe --tags --abbrev=0 2>/dev/null || \
              git -C "${ONOX_HOME}" rev-parse --short HEAD 2>/dev/null || echo "unknown")

# ---------------------------------------------------------------------------
# Composer install
# ---------------------------------------------------------------------------
composer install \
  --no-dev \
  --optimize-autoloader \
  --working-dir="${ONOX_HOME}" \
  --no-interaction \
  --quiet 2>&1 \
  || die_exec "$(json_str "composer install basarisiz")"

LAST_PCT=45
_progress 45 "arayuz derleniyor (npm)"

# ---------------------------------------------------------------------------
# npm build
# ---------------------------------------------------------------------------
npm install --prefix "${ONOX_HOME}" --silent 2>&1 \
  || die_exec "$(json_str "npm install basarisiz")"
npm run build --prefix "${ONOX_HOME}" 2>&1 \
  || die_exec "$(json_str "npm run build basarisiz")"

LAST_PCT=75
_progress 75 "veritabani (migrate)"

# ---------------------------------------------------------------------------
# Migrations — count how many ran
# ---------------------------------------------------------------------------
MIGRATE_OUT=$(php "${ONOX_HOME}/artisan" migrate --force --no-interaction 2>&1 || true)
MIGRATIONS_RUN=$(echo "$MIGRATE_OUT" | grep -c '^\s*Migrating:' 2>/dev/null || echo "0")

LAST_PCT=88
_progress 88 "onbellek"

# ---------------------------------------------------------------------------
# Caches
# ---------------------------------------------------------------------------
php "${ONOX_HOME}/artisan" config:cache  --no-interaction 2>&1 || true
php "${ONOX_HOME}/artisan" route:cache   --no-interaction 2>&1 || true
php "${ONOX_HOME}/artisan" view:cache    --no-interaction 2>&1 || true

LAST_PCT=94
_progress 94 "servis yeniden yukleniyor"

# Reload PHP-FPM (graceful)
systemctl reload php82-php-fpm 2>/dev/null || true

# Panel reached a consistent state — disarm rollback before emitting success.
SUCCESS=1
_progress 100 "tamamlandi" "completed"

# ---------------------------------------------------------------------------
# Output
# ---------------------------------------------------------------------------
printf '{"old_version":"%s","new_version":"%s","migrations_run":%s,"success":true}\n' \
  "$(json_str "$OLD_VERSION")" \
  "$(json_str "$NEW_VERSION")" \
  "$MIGRATIONS_RUN"

exit 0
