#!/bin/bash
#
# cleanup-orphan-sessions.sh - Clean up orphaned session transcript files
#
# Usage: ./cleanup-orphan-sessions.sh [--dry-run]
#
# Finds .jsonl transcript files that have no matching entry in sessions.json
# and archives them. These orphans can occur when sessions are deleted from
# sessions.json but transcript files aren't cleaned up.
#

set -euo pipefail

# Configuration
SESSIONS_DIR="/home/aria/.openclaw/agents/main/sessions"
ARCHIVE_DIR="$SESSIONS_DIR/archive"
LOG_FILE="/home/aria/.openclaw/workspace/logs/cleanup-orphan-sessions.log"
DRY_RUN=false

# Parse arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        --dry-run)
            DRY_RUN=true
            echo "[DRY-RUN MODE] No changes will be made"
            shift
            ;;
        *)
            echo "Unknown option: $1"
            echo "Usage: $0 [--dry-run]"
            exit 1
            ;;
    esac
done

# Ensure log directory exists
mkdir -p "$(dirname "$LOG_FILE")"

# Logging
log() {
    echo "[$(date -u '+%Y-%m-%d %H:%M:%S UTC')] $*" | tee -a "$LOG_FILE"
}

log "=== Starting orphan cleanup ==="

# Acquire lock
LOCK_FILE="$SESSIONS_DIR/.orphan-cleanup.lock"
exec 200>"$LOCK_FILE"
if ! flock -n 200; then
    log "ERROR: Another cleanup process is running. Exiting."
    exit 1
fi
log "Lock acquired"

# Create archive directory
MONTH_DIR="$ARCHIVE_DIR/$(date -u '+%Y-%m')"
if [[ "$DRY_RUN" == false ]]; then
    mkdir -p "$MONTH_DIR"
fi

# Get all session IDs from sessions.json
SESSIONS_FILE="$SESSIONS_DIR/sessions.json"
if [[ ! -f "$SESSIONS_FILE" ]]; then
    log "ERROR: sessions.json not found"
    exit 1
fi

# Extract all sessionId values into a temp file for fast lookup
VALID_IDS_FILE=$(mktemp)
jq -r '.[].sessionId // empty' "$SESSIONS_FILE" | sort -u > "$VALID_IDS_FILE"
VALID_COUNT=$(wc -l < "$VALID_IDS_FILE")
log "Found $VALID_COUNT valid session IDs in sessions.json"

ORPHAN_COUNT=0
ORPHAN_SIZE=0

# Check each .jsonl file (excluding .lock, .deleted, .tmp files)
for transcript in "$SESSIONS_DIR"/*.jsonl; do
    [[ -f "$transcript" ]] || continue
    
    FILENAME=$(basename "$transcript")
    
    # Skip lock files and already-deleted files
    [[ "$FILENAME" == *.lock ]] && continue
    [[ "$FILENAME" == *.deleted.* ]] && continue
    [[ "$FILENAME" == *.tmp ]] && continue
    
    # Extract session ID from filename
    # Formats: {sessionId}.jsonl or {timestamp}_{sessionId}.jsonl
    if [[ "$FILENAME" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T.*_(.+)\.jsonl$ ]]; then
        SESSION_ID="${BASH_REMATCH[1]}"
    elif [[ "$FILENAME" =~ ^([a-f0-9-]+)\.jsonl$ ]]; then
        SESSION_ID="${BASH_REMATCH[1]}"
    else
        log "  Skipping unknown format: $FILENAME"
        continue
    fi
    
    # Check if this session ID exists in sessions.json
    if ! grep -qFx "$SESSION_ID" "$VALID_IDS_FILE"; then
        FILE_SIZE=$(stat -c%s "$transcript" 2>/dev/null || echo 0)
        ORPHAN_SIZE=$((ORPHAN_SIZE + FILE_SIZE))
        ORPHAN_COUNT=$((ORPHAN_COUNT + 1))
        
        log "Orphan found: $FILENAME ($FILE_SIZE bytes)"
        
        if [[ "$DRY_RUN" == false ]]; then
            # Archive the orphan
            ARCHIVE_FILE="$MONTH_DIR/${FILENAME}.orphan.gz"
            gzip -c "$transcript" > "$ARCHIVE_FILE"
            rm "$transcript"
            
            # Also remove any associated lock file
            [[ -f "${transcript}.lock" ]] && rm "${transcript}.lock"
        fi
    fi
done

# Cleanup temp file
rm -f "$VALID_IDS_FILE"

# Summary
log "=== Orphan Cleanup Complete ==="
log "Orphans archived: $ORPHAN_COUNT"
log "Total size cleaned: $(numfmt --to=iec $ORPHAN_SIZE 2>/dev/null || echo "${ORPHAN_SIZE} bytes")"

# Release lock
flock -u 200

log "Done."

# Output for cron job parsing
echo "ORPHANS_CLEANED=$ORPHAN_COUNT"
echo "SIZE_CLEANED=$ORPHAN_SIZE"
