#!/bin/bash
# Aria Memory Curator (V5 Sprint 1, 08.05.2026)
# Analog zu aria-skill-curator.sh, aber für /root/.claude/projects/-/memory/
#
# Pflichten:
#   - Snapshot (tar.gz) von /root/.claude/projects/-/memory/ in .archive/
#   - Per Memory-File: stat last-modified, scan letzte 7 Daily-Logs auf
#     Read/Write-Activity-Mention
#   - Stale (>30 Tage ohne Activity) markieren in .usage.json
#   - Report nach 02-Wissen/memory-curator-reports/<date>.md
#
# Strict invariants:
#   - NIE Delete, nur Archive (restorable)
#   - Pinned-Memories exempt (.usage.json key "pinned": true)
#   - Liest und schreibt — verändert keine Memory-Inhalte selbst
#   - Default: weekly via systemd Timer aria-memory-curator.timer

set -e

MEMORY_DIR="/root/.claude/projects/-/memory"
ARCHIVE_DIR="${MEMORY_DIR}/.archive"
USAGE_FILE="${MEMORY_DIR}/.usage.json"
DAILY_DIR="${ARIA_BRAIN:-/root/aria/brain}/06-Daily"
REPORT_DIR="${ARIA_BRAIN:-/root/aria/brain}/02-Wissen/memory-curator-reports"
DATE=$(date +%Y-%m-%d)
REPORT="${REPORT_DIR}/memory-curator-${DATE}.md"
LOG="/var/log/aria-memory-curator.log"

mkdir -p "$ARCHIVE_DIR" "$REPORT_DIR"

log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >> "$LOG"
}

log "=== Memory-Curator gestartet ==="

# Step 1 — Snapshot
SNAPSHOT="${ARCHIVE_DIR}/memory-${DATE}.tar.gz"
if [ ! -f "$SNAPSHOT" ]; then
    tar czf "$SNAPSHOT" -C "$(dirname "$MEMORY_DIR")" "$(basename "$MEMORY_DIR")" \
        --exclude=".archive" --exclude=".usage.json" 2>>"$LOG"
    log "Snapshot erstellt: $SNAPSHOT"
else
    log "Snapshot existiert bereits, skipped: $SNAPSHOT"
fi

# Step 2 — Per Memory-File: Activity-Scan
declare -A LAST_MODIFIED
declare -A DAILY_MENTIONS
declare -A IS_STALE
declare -A STALE_REASON

# Bestehende usage.json laden, falls vorhanden (für Pinned)
declare -A PINNED
if [ -f "$USAGE_FILE" ]; then
    while IFS='=' read -r key val; do
        if [ "$val" = "true" ]; then
            PINNED["$key"]=1
        fi
    done < <(python3 -c "
import json, sys
try:
    with open('$USAGE_FILE') as f:
        data = json.load(f)
    for k, v in data.items():
        if isinstance(v, dict) and v.get('pinned'):
            print(f'{k}=true')
except Exception:
    pass
" 2>/dev/null)
fi

# Stale-Threshold: 30 Tage
STALE_DAYS=30
NOW_TS=$(date +%s)
STALE_THRESHOLD_TS=$((NOW_TS - STALE_DAYS * 86400))

# Pro File analysieren
for f in "$MEMORY_DIR"/*.md; do
    [ ! -f "$f" ] && continue
    NAME=$(basename "$f" .md)

    # Last-modified
    MTIME=$(stat -c %Y "$f" 2>/dev/null || echo "$NOW_TS")
    LAST_MODIFIED["$NAME"]=$MTIME

    # Mentions in letzte 7 Daily-Logs
    MENTIONS=0
    if [ -d "$DAILY_DIR" ]; then
        for daily in $(find "$DAILY_DIR" -name "*.md" -newermt "7 days ago" 2>/dev/null); do
            if grep -q "$NAME" "$daily" 2>/dev/null; then
                MENTIONS=$((MENTIONS + 1))
            fi
        done
    fi
    DAILY_MENTIONS["$NAME"]=$MENTIONS

    # Stale-Klassifikation (Pinned exempt)
    if [ -n "${PINNED[$NAME]:-}" ]; then
        IS_STALE["$NAME"]=0
        STALE_REASON["$NAME"]="pinned"
    elif [ "$MTIME" -lt "$STALE_THRESHOLD_TS" ] && [ "$MENTIONS" -eq 0 ]; then
        IS_STALE["$NAME"]=1
        DAYS_OLD=$(( (NOW_TS - MTIME) / 86400 ))
        STALE_REASON["$NAME"]="last modified ${DAYS_OLD}d ago, 0 daily mentions in last 7 days"
    else
        IS_STALE["$NAME"]=0
        STALE_REASON["$NAME"]="active"
    fi
done

# Step 3 — usage.json schreiben
python3 << EOF
import json
import os
from datetime import datetime, timezone

usage_data = {}
mem_dir = "$MEMORY_DIR"
now = $NOW_TS

# Load existing
try:
    with open("$USAGE_FILE") as f:
        existing = json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
    existing = {}

EOF

# Bash-Daten an Python übergeben über tmp file
TMP_DATA=$(mktemp)
{
    for name in "${!LAST_MODIFIED[@]}"; do
        printf '%s\t%s\t%s\t%s\t%s\n' \
            "$name" \
            "${LAST_MODIFIED[$name]}" \
            "${DAILY_MENTIONS[$name]}" \
            "${IS_STALE[$name]}" \
            "${STALE_REASON[$name]}"
    done
} > "$TMP_DATA"

python3 << EOF
import json
from datetime import datetime, timezone

usage_file = "$USAGE_FILE"
data_file = "$TMP_DATA"

# Load existing usage.json (for pinned-flag preservation)
try:
    with open(usage_file) as f:
        existing = json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
    existing = {}

now_iso = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
new_data = {}

with open(data_file) as f:
    for line in f:
        parts = line.rstrip("\n").split("\t")
        if len(parts) < 5:
            continue
        name, mtime, mentions, is_stale, reason = parts
        prev = existing.get(name, {})
        new_data[name] = {
            "last_modified_ts": int(mtime),
            "last_modified_iso": datetime.fromtimestamp(int(mtime), tz=timezone.utc).isoformat().replace("+00:00", "Z"),
            "daily_mentions_7d": int(mentions),
            "stale": is_stale == "1",
            "stale_reason": reason,
            "pinned": prev.get("pinned", False),
            "scanned_at": now_iso,
        }

# Preserve entries for files that no longer exist (deleted by user)
for name, prev in existing.items():
    if name not in new_data:
        prev["scanned_at"] = now_iso
        prev["status"] = "missing"
        new_data[name] = prev

with open(usage_file, "w") as f:
    json.dump(new_data, f, indent=2, sort_keys=True)
EOF

rm -f "$TMP_DATA"

# Step 4 — Markdown-Report
cat > "$REPORT" << EOF
---
title: Memory Curator Report ${DATE}
type: audit
tags: [memory-curator, audit, autonomous]
date: ${DATE}
status: aktiv
related: [[brain/CLAUDE]], [[HOOKS]], [[MEMORIES]]
---

# Memory Curator Report ${DATE}

> Wöchentlicher autonomer Scan von \`/root/.claude/projects/-/memory/\`.
> Generator: \`/root/aria/scripts/aria-memory-curator.sh\` (V5 Sprint 1).
> **Niemals Auto-Delete.** Nur Archive (.tar.gz) und Stale-Markierung.

## Snapshot

\`${SNAPSHOT}\`

## Files-Übersicht

| File | Last-Modified | Mentions 7d | Pinned | Status |
|------|---------------|-------------|--------|--------|
EOF

for name in "${!LAST_MODIFIED[@]}"; do
    PIN_FLAG="-"
    [ -n "${PINNED[$name]:-}" ] && PIN_FLAG="ja"
    DATE_HUMAN=$(date -d @"${LAST_MODIFIED[$name]}" '+%Y-%m-%d' 2>/dev/null || echo "?")
    STATUS_FLAG="aktiv"
    [ "${IS_STALE[$name]}" = "1" ] && STATUS_FLAG="**stale**"
    echo "| ${name} | ${DATE_HUMAN} | ${DAILY_MENTIONS[$name]} | ${PIN_FLAG} | ${STATUS_FLAG} |" >> "$REPORT"
done

# Stale-Liste detailliert
cat >> "$REPORT" << EOF

## Stale-Detection (>${STALE_DAYS} Tage ohne Activity)

EOF

STALE_COUNT=0
for name in "${!IS_STALE[@]}"; do
    if [ "${IS_STALE[$name]}" = "1" ]; then
        echo "- **${name}**: ${STALE_REASON[$name]}" >> "$REPORT"
        STALE_COUNT=$((STALE_COUNT + 1))
    fi
done

if [ "$STALE_COUNT" -eq 0 ]; then
    echo "Keine Memory-Files als stale markiert." >> "$REPORT"
fi

cat >> "$REPORT" << EOF

## Vorschläge (Aria reviewed beim nächsten Boot)

1. Stale-Memories prüfen ob noch relevant. Wenn nein: nach \`.archive/<name>.md\` verschieben.
2. Pinned-Flag in \`.usage.json\` setzen für Memories die nicht autoarchiviert werden sollen.
3. Snapshot-Restore möglich via:
   \`\`\`
   tar xzf .archive/memory-${DATE}.tar.gz -C ../
   \`\`\`

## Invariants

- Niemals Auto-Delete
- Pinned exempt
- Snapshot wird nur einmal pro Tag gemacht (idempotent)
EOF

log "Report geschrieben: $REPORT (${STALE_COUNT} stale)"
log "=== Memory-Curator fertig ==="

echo "OK Memory-Curator-Report: ${REPORT}"
echo "Stale Memories: ${STALE_COUNT}"
echo "Snapshot: ${SNAPSHOT}"
