#!/usr/bin/env bash
# =============================================================================
# onx-git-deploy — Pull + run deploy hook script
#
# Input:
#   {
#     "username":     "onx_xxxx",
#     "path":         "/home/<user>/repos/foo",
#     "target_path":  "/home/<user>/public_html"  // optional rsync target
#     "deploy_script": "composer install --no-dev && php artisan migrate --force"
#   }
#
# Behaviour:
#   1. git pull --ff-only
#   2. Optional: rsync repo → target_path (excluding .git)
#   3. Optional: execute deploy_script in the working dir (target_path if set,
#      else the repo path). Script runs under su <username> via bash -lc.
#
# Output:
#   {
#     "deployed": true,
#     "last_commit_sha":"...", "last_commit_message":"...",
#     "files_changed": N,
#     "script_output": "tail-of-stdout",
#     "duration_seconds": 12
#   }
#
# Exit codes: 0=ok 1=invalid-input 2=preflight-fail 3=execution-fail
# =============================================================================

set -euo pipefail
START=$(date +%s)

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

require_cmd jq
require_cmd git

INPUT=$(cat)
onx_require_json "${INPUT}"

USERNAME=$(onx_json_get   "${INPUT}" "username")
DEST=$(onx_json_get       "${INPUT}" "path")
TARGET=$(onx_json_get     "${INPUT}" "target_path" "")
SCRIPT=$(echo "${INPUT}" | jq -r '.deploy_script // ""')

onx_validate_username "${USERNAME}"
id "${USERNAME}" &>/dev/null || onx_die 2 "Linux user does not exist: ${USERNAME}"
[[ -n "${DEST}" ]] || onx_die 1 "path is required"
case "${DEST}" in
    "/home/${USERNAME}"|"/home/${USERNAME}/"*) : ;;
    *) onx_die 1 "path must live under /home/${USERNAME}" ;;
esac
[[ "${DEST}" == *..* ]] && onx_die 1 "path may not contain '..'"
[[ -d "${DEST}/.git" ]] || onx_die 2 "not a git repo: ${DEST}"

if [[ -n "${TARGET}" ]]; then
    case "${TARGET}" in
        "/home/${USERNAME}"|"/home/${USERNAME}/"*) : ;;
        *) onx_die 1 "target_path must live under /home/${USERNAME}" ;;
    esac
    [[ "${TARGET}" == *..* ]] && onx_die 1 "target_path may not contain '..'"
fi

# ── git pull ────────────────────────────────────────────────────────────────
OLD_SHA=$(su -s /bin/bash "${USERNAME}" -c "git -C '${DEST}' rev-parse HEAD 2>/dev/null" || echo "")

su -s /bin/bash "${USERNAME}" -c \
    "git -C '${DEST}' fetch --all --prune && git -C '${DEST}' pull --ff-only" \
    >/dev/null 2>&1 || onx_die 3 "git pull failed in ${DEST}"

NEW_SHA=$(su -s /bin/bash "${USERNAME}" -c "git -C '${DEST}' rev-parse HEAD 2>/dev/null" || echo "")
MSG=$(su -s /bin/bash "${USERNAME}" -c "git -C '${DEST}' log -1 --pretty=%s 2>/dev/null" || echo "")

FILES_CHANGED=0
if [[ -n "${OLD_SHA}" && -n "${NEW_SHA}" && "${OLD_SHA}" != "${NEW_SHA}" ]]; then
    FILES_CHANGED=$(su -s /bin/bash "${USERNAME}" -c \
        "git -C '${DEST}' diff --name-only ${OLD_SHA} ${NEW_SHA} 2>/dev/null | wc -l" || echo 0)
fi

# ── optional rsync ──────────────────────────────────────────────────────────
if [[ -n "${TARGET}" ]] && command -v rsync >/dev/null 2>&1; then
    su -s /bin/bash "${USERNAME}" -c \
        "mkdir -p '${TARGET}' && rsync -a --delete --exclude '.git/' '${DEST}/' '${TARGET}/'" \
        >/dev/null 2>&1 || onx_die 3 "rsync to ${TARGET} failed"
fi

# ── optional script ─────────────────────────────────────────────────────────
SCRIPT_OUT=""
if [[ -n "${SCRIPT}" ]]; then
    WD="${TARGET:-${DEST}}"
    TMPLOG=$(mktemp -t onx-git-deploy.XXXXXX)
    chown "${USERNAME}:${USERNAME}" "${TMPLOG}"
    trap 'rm -f "${TMPLOG}" 2>/dev/null || true' EXIT

    if ! su -s /bin/bash "${USERNAME}" -lc \
        "cd '${WD}' && ${SCRIPT}" \
        >"${TMPLOG}" 2>&1; then
        SCRIPT_OUT=$(tail -n 50 "${TMPLOG}" 2>/dev/null || true)
        OUT_J=$(printf '%s' "${SCRIPT_OUT}" | jq -Rs '.')
        onx_die 3 "deploy_script failed (tail: ${OUT_J})"
    fi
    SCRIPT_OUT=$(tail -n 50 "${TMPLOG}" 2>/dev/null || true)
fi

DURATION=$(( $(date +%s) - START ))
MSG_J=$(printf '%s' "${MSG}"        | jq -Rs '.')
OUT_J=$(printf '%s' "${SCRIPT_OUT}" | jq -Rs '.')

onx_log "git-deploy: ${DEST} -> ${TARGET:-in-place} sha=${NEW_SHA:0:7} files=${FILES_CHANGED} dur=${DURATION}s"

printf '{"deployed":true,"last_commit_sha":"%s","last_commit_message":%s,"files_changed":%s,"script_output":%s,"duration_seconds":%s}\n' \
    "${NEW_SHA}" "${MSG_J}" "${FILES_CHANGED}" "${OUT_J}" "${DURATION}"
