#!/usr/bin/env bash
# test_watchdog_retry_loop.sh — 와치독 재위임 폭주 수정 스모크테스트
set -euo pipefail

PASS=0
FAIL=0
TOTAL=0

assert_eq() {
    local desc="$1" expected="$2" actual="$3"
    TOTAL=$((TOTAL + 1))
    if [[ "$expected" == "$actual" ]]; then
        echo "✅ PASS: $desc"
        PASS=$((PASS + 1))
    else
        echo "❌ FAIL: $desc (expected=$expected, actual=$actual)"
        FAIL=$((FAIL + 1))
    fi
}

# 테스트용 임시 환경 구축
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT

EVENTS_DIR="$TMPDIR/events"
TIMERS_FILE="$TMPDIR/task-timers.json"
mkdir -p "$EVENTS_DIR"

# === 시나리오 1: base task에 .done이 있는 상태에서 +N task → 스킵 ===
echo '--- 시나리오 1: 형제 작업 .done 감지 ---'

# base task .done 생성
echo '{"task_id":"task-1869_2.2+1","status":"done"}' > "$EVENTS_DIR/task-1869_2.2+1.done"

# 검증: +2 task에 대해 base task의 .done glob이 매치되는지
TASK_ID="task-1869_2.2+2"
BASE_TASK_ID=$(echo "$TASK_ID" | sed 's/+[0-9]*$//')

SIBLING_DONE=false
for DONE_CHECK in "${EVENTS_DIR}/${BASE_TASK_ID}"*.done "${EVENTS_DIR}/${BASE_TASK_ID}"*.done.acked "${EVENTS_DIR}/${BASE_TASK_ID}"*.done.clear; do
    if [[ -f "$DONE_CHECK" ]]; then
        SIBLING_DONE=true
        break
    fi
done
assert_eq "시나리오1: +1 .done 존재 시 +2가 형제 완료 감지" "true" "$SIBLING_DONE"

# base task 자체는 형제 체크 안 함 (자기 자신은 기존 로직에서 처리)
TASK_ID_SELF="task-1869_2.2+1"
BASE_SELF=$(echo "$TASK_ID_SELF" | sed 's/+[0-9]*$//')
if [[ "$BASE_SELF" != "$TASK_ID_SELF" ]]; then
    SELF_CHECK="different"
else
    SELF_CHECK="same"
fi
assert_eq "시나리오1: +N은 BASE와 다름 → 형제 체크 진입" "different" "$SELF_CHECK"

# base task (접미사 없음) 자체는 형제 체크 스킵
TASK_ID_BASE="task-1869_2.2"
BASE_BASE=$(echo "$TASK_ID_BASE" | sed 's/+[0-9]*$//')
if [[ "$BASE_BASE" != "$TASK_ID_BASE" ]]; then
    BASE_CHECK="different"
else
    BASE_CHECK="same"
fi
assert_eq "시나리오1: base task 자체는 형제 체크 스킵" "same" "$BASE_CHECK"


# === 시나리오 2: 글로벌 retry 합산 상한(3) 도달 → 거부 ===
echo '--- 시나리오 2: 글로벌 재시도 상한 ---'

cat > "$TIMERS_FILE" << 'TIMEREOF'
{
  "tasks": {
    "task-1869_2.2": {"status":"done","retry_count":1,"end_time":"2026-04-16T10:00:00"},
    "task-1869_2.2+1": {"status":"done","retry_count":1,"end_time":"2026-04-16T10:30:00"},
    "task-1869_2.2+2": {"status":"done","retry_count":1,"end_time":"2026-04-16T11:00:00"},
    "task-1869_2.2+3": {"status":"running","retry_count":0}
  }
}
TIMEREOF

TASK_ID="task-1869_2.2+3"
BASE_TASK_ID_FOR_RETRY=$(echo "$TASK_ID" | sed 's/+[0-9]*$//')
GLOBAL_RETRY_COUNT=0
while IFS= read -r SIBLING_TID; do
    [[ -z "$SIBLING_TID" ]] && continue
    S_RC=$(jq -r --arg tid "$SIBLING_TID" '.tasks[$tid].retry_count // 0' "$TIMERS_FILE" 2>/dev/null)
    if [[ "$S_RC" =~ ^[0-9]+$ ]]; then
        GLOBAL_RETRY_COUNT=$((GLOBAL_RETRY_COUNT + S_RC + 1))
    fi
done <<< "$(jq -r '.tasks | keys[]' "$TIMERS_FILE" 2>/dev/null | grep "^${BASE_TASK_ID_FOR_RETRY}")"

GLOBAL_MAX_RETRY=3
if [[ "$GLOBAL_RETRY_COUNT" -ge "$GLOBAL_MAX_RETRY" ]]; then
    GLOBAL_RESULT="blocked"
else
    GLOBAL_RESULT="allowed"
fi
assert_eq "시나리오2: 4 sibling (rc=1,1,1,0) → 합산=${GLOBAL_RETRY_COUNT} >= 3 → 거부" "blocked" "$GLOBAL_RESULT"

# 정상 케이스: sibling 1개만 있으면 허용
cat > "$TIMERS_FILE" << 'TIMEREOF2'
{
  "tasks": {
    "task-500": {"status":"running","retry_count":0}
  }
}
TIMEREOF2

TASK_ID="task-500"
BASE_TASK_ID_FOR_RETRY=$(echo "$TASK_ID" | sed 's/+[0-9]*$//')
GLOBAL_RETRY_COUNT=0
while IFS= read -r SIBLING_TID; do
    [[ -z "$SIBLING_TID" ]] && continue
    S_RC=$(jq -r --arg tid "$SIBLING_TID" '.tasks[$tid].retry_count // 0' "$TIMERS_FILE" 2>/dev/null)
    if [[ "$S_RC" =~ ^[0-9]+$ ]]; then
        GLOBAL_RETRY_COUNT=$((GLOBAL_RETRY_COUNT + S_RC + 1))
    fi
done <<< "$(jq -r '.tasks | keys[]' "$TIMERS_FILE" 2>/dev/null | grep "^${BASE_TASK_ID_FOR_RETRY}")"

if [[ "$GLOBAL_RETRY_COUNT" -ge "$GLOBAL_MAX_RETRY" ]]; then
    NORMAL_RESULT="blocked"
else
    NORMAL_RESULT="allowed"
fi
assert_eq "시나리오2: 단일 task (rc=0) → 합산=${GLOBAL_RETRY_COUNT} < 3 → 허용" "allowed" "$NORMAL_RESULT"


# === 시나리오 3: base task end_time 존재 시 +N 스킵 ===
echo '--- 시나리오 3: base task end_time 완료 체크 ---'

cat > "$TIMERS_FILE" << 'TIMEREOF3'
{
  "tasks": {
    "task-1869_2.2": {"status":"done","end_time":"2026-04-16T10:00:00","retry_count":0},
    "task-1869_2.2+1": {"status":"running","retry_count":0}
  }
}
TIMEREOF3

TASK_ID="task-1869_2.2+1"
BASE_TASK_ID_END=$(echo "$TASK_ID" | sed 's/+[0-9]*$//')
BASE_END_TIME=$(jq -r --arg tid "$BASE_TASK_ID_END" '.tasks[$tid].end_time // ""' "$TIMERS_FILE" 2>/dev/null)

if [[ "$BASE_TASK_ID_END" != "$TASK_ID" ]] && [[ -n "$BASE_END_TIME" && "$BASE_END_TIME" != "null" ]]; then
    END_RESULT="skip"
else
    END_RESULT="continue"
fi
assert_eq "시나리오3: base task end_time 존재 → +1 재위임 스킵" "skip" "$END_RESULT"

# end_time이 없는 base task의 +N은 계속 진행
cat > "$TIMERS_FILE" << 'TIMEREOF4'
{
  "tasks": {
    "task-900": {"status":"running","retry_count":0},
    "task-900+1": {"status":"running","retry_count":0}
  }
}
TIMEREOF4

TASK_ID="task-900+1"
BASE_TASK_ID_END=$(echo "$TASK_ID" | sed 's/+[0-9]*$//')
BASE_END_TIME=$(jq -r --arg tid "$BASE_TASK_ID_END" '.tasks[$tid].end_time // ""' "$TIMERS_FILE" 2>/dev/null)

if [[ "$BASE_TASK_ID_END" != "$TASK_ID" ]] && [[ -n "$BASE_END_TIME" && "$BASE_END_TIME" != "null" ]]; then
    NOEND_RESULT="skip"
else
    NOEND_RESULT="continue"
fi
assert_eq "시나리오3: base task end_time 없음 → +1 정상 진행" "continue" "$NOEND_RESULT"


# === 시나리오 4: bash -n 문법 검사 ===
echo '--- 시나리오 4: 문법 검사 ---'
bash -n /home/jay/workspace/scripts/session-watchdog.sh 2>&1 && SYNTAX="ok" || SYNTAX="fail"
assert_eq "시나리오4: bash -n 문법 검사 통과" "ok" "$SYNTAX"


# === 결과 요약 ===
echo ""
echo "================================"
echo "  테스트 결과: ${PASS}/${TOTAL} PASS, ${FAIL} FAIL"
echo "================================"

if [[ "$FAIL" -gt 0 ]]; then
    exit 1
fi
exit 0
