#!/bin/bash
# task-monitor-v2.sh — "Alert once, then shut up until something changes"
#
# Runs every 5 min via cron. Max 3 reminders per task state.
# State tracked in .task-monitor/state.json (per-task, via jq).
#
# Decision tree per run:
#   - No active task           → clear state, exit
#   - New task (different ID)  → reset state, exit (fresh start)
#   - Task DONE/COMPLETED      → clear state, exit
#   - Task BLOCKED             → acknowledge, exit (shut up)
#   - OUTBOX updated since last → reset stuck timer, exit (CC is working)
#   - No activity:
#       <10 min   → exit (be patient)
#       10 min    → gentle nudge (level 1)
#       20 min    → escalation (level 2)
#       30 min    → final alert + Telegram (level 3)
#       already 3 → exit (done)

set -euo pipefail

PROJECT_ROOT="/home/ccuser/rateright-growth"
INBOX="$PROJECT_ROOT/.claude/INBOX.md"
OUTBOX="$PROJECT_ROOT/.claude/OUTBOX.md"
STATUS_FILE="$PROJECT_ROOT/.claude/STATUS.md"
STATE_DIR="$PROJECT_ROOT/.task-monitor"
STATE_JSON="$STATE_DIR/state.json"
TELEGRAM_SCRIPT="$PROJECT_ROOT/clawd-scripts/telegram-alert.sh"

LOG_PREFIX="[task-monitor-v2]"

log() { echo "$LOG_PREFIX $(date '+%Y-%m-%d %H:%M:%S') $1"; }

# --- Setup ---
mkdir -p "$STATE_DIR"

# Initialize state.json if missing or empty
if [ ! -s "$STATE_JSON" ]; then
    echo '{}' > "$STATE_JSON"
fi

# --- Helpers ---

# Read a key from state.json (returns empty string if missing)
state_get() {
    jq -r ".$1 // empty" "$STATE_JSON" 2>/dev/null || echo ""
}

# Write full state object
state_write() {
    local task_id="$1"
    local task_status="$2"
    local cc_status="$3"
    local outbox_mtime="$4"
    local first_seen_stuck="$5"
    local alert_level="$6"
    local blocked_acknowledged="$7"

    jq -n \
        --arg tid "$task_id" \
        --arg ts "$task_status" \
        --arg cs "$cc_status" \
        --argjson om "$outbox_mtime" \
        --argjson fss "$first_seen_stuck" \
        --argjson al "$alert_level" \
        --argjson ba "$blocked_acknowledged" \
        '{
            task_id: $tid,
            task_status: $ts,
            cc_status: $cs,
            outbox_mtime: $om,
            first_seen_stuck: $fss,
            alert_level: $al,
            blocked_acknowledged: $ba
        }' > "$STATE_JSON"
}

state_clear() {
    echo '{}' > "$STATE_JSON"
    log "State cleared"
}

# --- Parse INBOX.md for first IN PROGRESS task ---
# Looks for pattern: "## IN PROGRESS" section, then "### Task: TASK-ID" and "**Status**:" line
parse_inbox() {
    if [ ! -f "$INBOX" ]; then
        log "ERROR: INBOX.md not found"
        exit 1
    fi

    # Find first task ID under IN PROGRESS section
    # Match "### Task: TASK-XXXXX" lines that appear after "## IN PROGRESS"
    local in_progress_block
    in_progress_block=$(awk '/^## IN PROGRESS/,/^## (BLOCKED|COMPLETED|DONE)/' "$INBOX" 2>/dev/null || echo "")

    ACTIVE_TASK_ID=""
    ACTIVE_TASK_STATUS=""

    if [ -n "$in_progress_block" ]; then
        ACTIVE_TASK_ID=$(echo "$in_progress_block" | grep -oP '### Task: \K\S+' | head -1 || echo "")
        # Get status line for this task
        ACTIVE_TASK_STATUS=$(echo "$in_progress_block" | grep -oP '\*\*Status\*\*: \K.*' | head -1 || echo "")
    fi
}

# --- Read CC status ---
read_cc_status() {
    CC_STATUS="unknown"
    if [ -f "$STATUS_FILE" ]; then
        CC_STATUS=$(head -1 "$STATUS_FILE" | tr '[:upper:]' '[:lower:]' | xargs)
    fi
}

# --- Get OUTBOX mtime ---
get_outbox_mtime() {
    OUTBOX_MTIME=0
    if [ -f "$OUTBOX" ]; then
        OUTBOX_MTIME=$(stat -c %Y "$OUTBOX" 2>/dev/null || echo "0")
    fi
}

# --- Append reminder to INBOX ---
append_reminder() {
    local task_id="$1"
    local stale_minutes="$2"
    local level="$3"

    local monitor_id="MONITOR-$(date +%Y%m%d-%H%M%S)"
    local note=""

    case "$level" in
        1)
            note="Just checking - still working on this?"
            ;;
        2)
            note="This seems stalled. Are you stuck? Need help?"
            ;;
        3)
            note="Final check-in. Escalating to Telegram."
            ;;
    esac

    cat >> "$INBOX" <<EOF

## $monitor_id - Check-in
**Task:** $task_id
**Stale for:** ~${stale_minutes} minutes
**Note:** $note
EOF

    log "Appended level-$level reminder for $task_id (~${stale_minutes}m stale)"
}

# --- Send Telegram alert (level 3 only) ---
send_telegram() {
    local task_id="$1"
    local stale_minutes="$2"

    if [ -x "$TELEGRAM_SCRIPT" ]; then
        "$TELEGRAM_SCRIPT" "URGENT" "Task $task_id stale for ~${stale_minutes} minutes. CC VPS may be stuck."
        log "Telegram alert sent for $task_id"
    else
        log "WARNING: telegram-alert.sh not found or not executable at $TELEGRAM_SCRIPT"
    fi
}

# ===========================
# MAIN
# ===========================

log "Run started"

parse_inbox
read_cc_status
get_outbox_mtime

NOW=$(date +%s)

# Load previous state
PREV_TASK_ID=$(state_get "task_id")
PREV_OUTBOX_MTIME=$(state_get "outbox_mtime")
PREV_FIRST_STUCK=$(state_get "first_seen_stuck")
PREV_ALERT_LEVEL=$(state_get "alert_level")
PREV_BLOCKED=$(state_get "blocked_acknowledged")

# Default numeric values
[ -z "$PREV_OUTBOX_MTIME" ] && PREV_OUTBOX_MTIME=0
[ -z "$PREV_FIRST_STUCK" ] && PREV_FIRST_STUCK=0
[ -z "$PREV_ALERT_LEVEL" ] && PREV_ALERT_LEVEL=0
[ -z "$PREV_BLOCKED" ] && PREV_BLOCKED="false"

# --- Decision tree ---

# 1. No active task → clear state, exit
if [ -z "$ACTIVE_TASK_ID" ]; then
    log "No active task found. Clearing state."
    state_clear
    exit 0
fi

log "Active task: $ACTIVE_TASK_ID (status: $ACTIVE_TASK_STATUS, cc: $CC_STATUS)"

# 2. New task (different ID) → reset state, exit
if [ "$ACTIVE_TASK_ID" != "$PREV_TASK_ID" ]; then
    log "New task detected (was: $PREV_TASK_ID). Resetting state."
    state_write "$ACTIVE_TASK_ID" "$ACTIVE_TASK_STATUS" "$CC_STATUS" "$OUTBOX_MTIME" "$NOW" 0 false
    exit 0
fi

# 3. Task DONE/COMPLETED → clear state, exit
if echo "$ACTIVE_TASK_STATUS" | grep -qiE '(done|completed|complete)'; then
    log "Task $ACTIVE_TASK_ID is done. Clearing state."
    state_clear
    exit 0
fi

# 4. Task BLOCKED → acknowledge, exit
if echo "$ACTIVE_TASK_STATUS" | grep -qiE 'blocked'; then
    if [ "$PREV_BLOCKED" != "true" ]; then
        log "Task $ACTIVE_TASK_ID is BLOCKED. Acknowledging (will not alert)."
        state_write "$ACTIVE_TASK_ID" "$ACTIVE_TASK_STATUS" "$CC_STATUS" "$OUTBOX_MTIME" "$PREV_FIRST_STUCK" "$PREV_ALERT_LEVEL" true
    else
        log "Task $ACTIVE_TASK_ID still BLOCKED (already acknowledged)."
    fi
    exit 0
fi

# 5. OUTBOX updated since last check → CC is working, reset stuck timer
if [ "$OUTBOX_MTIME" -gt "$PREV_OUTBOX_MTIME" ] && [ "$PREV_OUTBOX_MTIME" -gt 0 ]; then
    log "OUTBOX updated (mtime $PREV_OUTBOX_MTIME -> $OUTBOX_MTIME). CC is working. Resetting timer."
    state_write "$ACTIVE_TASK_ID" "$ACTIVE_TASK_STATUS" "$CC_STATUS" "$OUTBOX_MTIME" "$NOW" 0 false
    exit 0
fi

# 6. No activity — check how long stuck
# If first_seen_stuck is 0, this is first detection
if [ "$PREV_FIRST_STUCK" -eq 0 ]; then
    log "First run with no activity. Starting stuck timer."
    state_write "$ACTIVE_TASK_ID" "$ACTIVE_TASK_STATUS" "$CC_STATUS" "$OUTBOX_MTIME" "$NOW" 0 false
    exit 0
fi

STUCK_SECONDS=$((NOW - PREV_FIRST_STUCK))
STUCK_MINUTES=$((STUCK_SECONDS / 60))

log "No activity for ~${STUCK_MINUTES} minutes (alert_level: $PREV_ALERT_LEVEL)"

# <10 min → be patient
if [ "$STUCK_MINUTES" -lt 10 ]; then
    log "Under 10 min. Being patient."
    state_write "$ACTIVE_TASK_ID" "$ACTIVE_TASK_STATUS" "$CC_STATUS" "$OUTBOX_MTIME" "$PREV_FIRST_STUCK" "$PREV_ALERT_LEVEL" false
    exit 0
fi

# 10 min, level < 1 → gentle nudge
if [ "$STUCK_MINUTES" -ge 10 ] && [ "$PREV_ALERT_LEVEL" -lt 1 ]; then
    append_reminder "$ACTIVE_TASK_ID" "$STUCK_MINUTES" 1
    state_write "$ACTIVE_TASK_ID" "$ACTIVE_TASK_STATUS" "$CC_STATUS" "$OUTBOX_MTIME" "$PREV_FIRST_STUCK" 1 false
    exit 0
fi

# 20 min, level < 2 → escalation
if [ "$STUCK_MINUTES" -ge 20 ] && [ "$PREV_ALERT_LEVEL" -lt 2 ]; then
    append_reminder "$ACTIVE_TASK_ID" "$STUCK_MINUTES" 2
    state_write "$ACTIVE_TASK_ID" "$ACTIVE_TASK_STATUS" "$CC_STATUS" "$OUTBOX_MTIME" "$PREV_FIRST_STUCK" 2 false
    exit 0
fi

# 30 min, level < 3 → final alert + Telegram
if [ "$STUCK_MINUTES" -ge 30 ] && [ "$PREV_ALERT_LEVEL" -lt 3 ]; then
    append_reminder "$ACTIVE_TASK_ID" "$STUCK_MINUTES" 3
    send_telegram "$ACTIVE_TASK_ID" "$STUCK_MINUTES"
    state_write "$ACTIVE_TASK_ID" "$ACTIVE_TASK_STATUS" "$CC_STATUS" "$OUTBOX_MTIME" "$PREV_FIRST_STUCK" 3 false
    exit 0
fi

# Already at level 3 → done, shut up
log "Already at max alert level (3). Nothing to do."
state_write "$ACTIVE_TASK_ID" "$ACTIVE_TASK_STATUS" "$CC_STATUS" "$OUTBOX_MTIME" "$PREV_FIRST_STUCK" "$PREV_ALERT_LEVEL" false
exit 0
