#!/usr/bin/env bash
# loop_lock.sh — Atomic race-free loop lock acquisition and marker ownership (O-2)
# Manages .mam/loop-guard-active with atomic hard links and pid+lstart identity validation.

MAM_LOCK_STEAL_RETRIES="${MAM_LOCK_STEAL_RETRIES:-3}"

mam_lstart() {
  local pid="${1:-$$}"
  ps -p "$pid" -o lstart= 2>/dev/null | tr -s ' ' | sed 's/^ *//;s/ *$//'
}

_mam_lock_field() {
  local file="$1" key="$2"
  if [ ! -f "$file" ]; then
    return 1
  fi
  grep "^${key}=" "$file" 2>/dev/null | head -n 1 | cut -d'=' -f2- || true
}

_mam_lock_holder_state() {
  local marker="$1"
  if [ ! -f "$marker" ]; then
    printf 'stale'
    return 0
  fi

  local rec_pid rec_lstart cur_lstart own_lstart
  rec_pid=$(_mam_lock_field "$marker" "pid")
  rec_lstart=$(_mam_lock_field "$marker" "lstart")

  if [ -z "$rec_pid" ] || ! [[ "$rec_pid" =~ ^[0-9]+$ ]]; then
    printf 'stale'
    return 0
  fi

  own_lstart=$(mam_lstart "$$")
  if [ -z "$own_lstart" ]; then
    printf 'unknown'
    return 0
  fi

  cur_lstart=$(mam_lstart "$rec_pid")
  if [ -z "$cur_lstart" ]; then
    printf 'stale'
    return 0
  fi

  if [ -n "$rec_lstart" ]; then
    if [ "$cur_lstart" != "$rec_lstart" ]; then
      printf 'stale'
      return 0
    fi
  fi

  printf 'live'
  return 0
}

_mam_lock_publish() {
  local marker="$1"
  local parent_dir
  parent_dir=$(dirname "$marker")
  mkdir -p "$parent_dir" 2>/dev/null || true

  local tmp_marker="${marker}.tmp.${$}.${RANDOM:-0}"
  local lstart_val
  lstart_val=$(mam_lstart "$$")

  printf 'pid=%s\nlstart=%s\nstarted=%s\n' \
    "$$" "$lstart_val" "$(date -u +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date)" > "$tmp_marker"

  local rc=0
  ln "$tmp_marker" "$marker" 2>/dev/null || rc=$?
  rm -f "$tmp_marker" 2>/dev/null || true
  return $rc
}

mam_acquire_loop_lock() {
  local marker="${1:-}"
  if [ -z "$marker" ]; then
    return 2
  fi

  local steal_lock="${marker}.steal"
  local retries=0

  while [ "$retries" -le "$MAM_LOCK_STEAL_RETRIES" ]; do
    # Upgrade path: clean up legacy directory at steal_lock if present
    if [ -d "$steal_lock" ]; then
      rmdir "$steal_lock" 2>/dev/null || true
    fi

    # Try publishing primary marker
    if _mam_lock_publish "$marker"; then
      return 0
    fi

    # Check primary marker holder state
    local state
    state=$(_mam_lock_holder_state "$marker")
    if [ "$state" = "live" ]; then
      return 3
    fi
    if [ "$state" = "unknown" ]; then
      return 4
    fi

    # Primary marker is stale! Try publishing steal_lock
    if _mam_lock_publish "$steal_lock"; then
      if [ "$(_mam_lock_holder_state "$marker")" = "stale" ]; then
        rm -f "$marker" 2>/dev/null || true
      fi
      rm -f "$steal_lock" 2>/dev/null || true
      if _mam_lock_publish "$marker"; then
        return 0
      fi
    fi

    # Check steal_lock holder state
    local steal_state
    steal_state=$(_mam_lock_holder_state "$steal_lock")
    case "$steal_state" in
      live)
        return 3
        ;;
      unknown)
        return 4
        ;;
      stale)
        rm -f "$steal_lock" 2>/dev/null || true
        retries=$((retries + 1))
        continue
        ;;
    esac

    sleep 1
    retries=$((retries + 1))
  done

  return 3
}

mam_release_loop_lock() {
  local marker="${1:-}"
  if [ -z "$marker" ] || [ ! -f "$marker" ]; then
    return 0
  fi

  local rec_pid rec_lstart cur_lstart
  rec_pid=$(_mam_lock_field "$marker" "pid")
  rec_lstart=$(_mam_lock_field "$marker" "lstart")
  cur_lstart=$(mam_lstart "$$")

  if [ "$rec_pid" = "$$" ] && [ "$rec_lstart" = "$cur_lstart" ]; then
    rm -f "$marker" 2>/dev/null || true
    return 0
  fi

  return 1
}

if [ "${BASH_SOURCE[0]}" = "$0" ]; then
  case "${1:-}" in
    acquire) mam_acquire_loop_lock "${2:-}" ;;
    release) mam_release_loop_lock "${2:-}" ;;
    *) echo "Usage: $0 {acquire|release} <marker-path>" ; exit 1 ;;
  esac
fi
