#!/bin/zsh
set -u

REPO="/Users/openclaw/.openclaw/workspace"
TMP="$REPO/tmp"
STATE_DIR="$TMP/job-state"
LOG="$TMP/git-push.log"
STATE_FILE="$STATE_DIR/git-push.state"

mkdir -p "$TMP" "$STATE_DIR"

now_epoch() { date +%s; }
now_human() { date '+%Y-%m-%d %H:%M:%S %Z'; }

# defaults
FAIL_COUNT=0
FIRST_FAIL_EPOCH=0
LAST_SUCCESS_EPOCH=0
ALERT_SENT=0
LAST_ERROR=""

if [[ -f "$STATE_FILE" ]]; then
  # shellcheck disable=SC1090
  source "$STATE_FILE"
fi

write_state() {
  cat > "$STATE_FILE" <<EOF
FAIL_COUNT=$FAIL_COUNT
FIRST_FAIL_EPOCH=$FIRST_FAIL_EPOCH
LAST_SUCCESS_EPOCH=$LAST_SUCCESS_EPOCH
ALERT_SENT=$ALERT_SENT
LAST_ERROR=$(printf %q "$LAST_ERROR")
EOF
}

classify_error() {
  local err="$1"
  if [[ "$err" == *"Could not resolve host"* ]]; then
    echo "network"
  elif [[ "$err" == *"could not read Username"* ]] || [[ "$err" == *"Authentication failed"* ]]; then
    echo "auth"
  elif [[ "$err" == *"Permission denied"* ]]; then
    echo "permission"
  else
    echo "tooling"
  fi
}

push_output=""
push_rc=0

# cron-safe env defaults
export HOME="${HOME:-/Users/openclaw}"
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:${PATH:-}"
export GIT_TERMINAL_PROMPT=0

run_push() {
  git push origin main 2>&1
}

run_push_with_gh_token() {
  local token auth
  token="$(gh auth token 2>/dev/null)" || return 1
  [[ -n "$token" ]] || return 1
  auth="$(printf 'x-access-token:%s' "$token" | base64)"
  git -c http.https://github.com/.extraheader="AUTHORIZATION: basic $auth" push origin main 2>&1
}

{
  echo "[$(now_human)] START push"
  cd "$REPO" || exit 98
  git remote get-url origin >/dev/null 2>&1

  push_output="$(run_push)"
  push_rc=$?

  if [[ $push_rc -ne 0 ]] && { [[ "$push_output" == *"could not read Username"* ]] || [[ "$push_output" == *"Authentication failed"* ]]; }; then
    echo "[$(now_human)] RETRY auth using gh token"
    retry_output="$(run_push_with_gh_token)"
    retry_rc=$?
    push_output="$push_output\n---- RETRY WITH GH TOKEN ----\n$retry_output"
    push_rc=$retry_rc
  fi

  if [[ $push_rc -eq 0 ]]; then
    echo "$push_output"
    echo "[$(now_human)] OK push"
  else
    echo "$push_output"
    echo "[$(now_human)] FAIL push rc=$push_rc"
  fi
} >> "$LOG" 2>&1

if [[ $push_rc -eq 0 ]]; then
  prev_fail_count=$FAIL_COUNT
  prev_alert_sent=$ALERT_SENT

  FAIL_COUNT=0
  FIRST_FAIL_EPOCH=0
  LAST_SUCCESS_EPOCH=$(now_epoch)
  LAST_ERROR=""
  ALERT_SENT=0

  if [[ $prev_fail_count -gt 0 ]] || [[ $prev_alert_sent -eq 1 ]]; then
    {
      echo "[$(now_human)] RECOVERED job=git-push previous_failures=$prev_fail_count"
    } >> "$LOG"
  fi

  write_state
  exit 0
fi

# failure path
FAIL_COUNT=$((FAIL_COUNT + 1))
if [[ $FIRST_FAIL_EPOCH -eq 0 ]]; then
  FIRST_FAIL_EPOCH=$(now_epoch)
fi
LAST_ERROR="$push_output"

err_class="$(classify_error "$LAST_ERROR")"

cd "$REPO" || true
ahead_info="$(git rev-list --left-right --count origin/main...main 2>/dev/null || echo "0 0")"
behind_count="${ahead_info%% *}"
ahead_count="${ahead_info##* }"

elapsed=$(( $(now_epoch) - FIRST_FAIL_EPOCH ))
THRESH_FAILS=3
THRESH_SECONDS=7200

{
  echo "[$(now_human)] FAIL_META class=$err_class consecutive=$FAIL_COUNT elapsed_s=$elapsed ahead=$ahead_count behind=$behind_count"
} >> "$LOG"

if [[ $ALERT_SENT -eq 0 ]] && { [[ $FAIL_COUNT -ge $THRESH_FAILS ]] || [[ $elapsed -ge $THRESH_SECONDS ]]; }; then
  {
    echo "[$(now_human)] ALERT job=git-push first_fail_epoch=$FIRST_FAIL_EPOCH consecutive=$FAIL_COUNT class=$err_class ahead=$ahead_count"
    echo "[$(now_human)] ALERT_ERR ${LAST_ERROR//$'\n'/ | }"
    echo "[$(now_human)] PROPOSED_FIX class=$err_class action='re-auth gh / credential helper check / network check'"
  } >> "$LOG"
  ALERT_SENT=1
fi

write_state
exit 1
