#!/bin/bash
# Nexus CLI - Memory State Management Demo (#368)
#
# This demo showcases the memory state management feature including:
# - Manual approval workflow (inactive -> active)
# - State filtering (inactive/active/all)
# - Bulk operations (approve-batch, deactivate-batch)
# - User -> Agent delegation with ReBAC permissions
# - Quality control and memory curation
#
# Prerequisites:
# 1. Server running: ./scripts/init-nexus-with-auth.sh
# 2. Load admin credentials: source .nexus-admin-env
#
# Usage:
#   ./examples/cli/memory_state_management_demo.sh

set -e

# Colors
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
NC='\033[0m'

print_section() {
    echo ""
    echo "════════════════════════════════════════════════════════════"
    echo "  $1"
    echo "════════════════════════════════════════════════════════════"
    echo ""
}

print_subsection() {
    echo ""
    echo "─── $1 ───"
    echo ""
}

print_success() { echo -e "${GREEN}✓${NC} $1"; }
print_info() { echo -e "${BLUE}ℹ${NC} $1"; }
print_warning() { echo -e "${YELLOW}⚠${NC} $1"; }
print_error() { echo -e "${RED}✗${NC} $1"; }
print_test() { echo -e "${MAGENTA}TEST:${NC} $1"; }

# Check prerequisites
if [ -z "$NEXUS_URL" ] || [ -z "$NEXUS_API_KEY" ]; then
    print_error "NEXUS_URL and NEXUS_API_KEY not set. Run: source .nexus-admin-env"
    exit 1
fi

echo "╔══════════════════════════════════════════════════════════╗"
echo "║   Nexus CLI - Memory State Management Demo (#368)       ║"
echo "╚══════════════════════════════════════════════════════════╝"
echo ""
print_info "Server: $NEXUS_URL"
print_info "Feature: Manual memory approval with inactive/active states"
echo ""

ADMIN_KEY="$NEXUS_API_KEY"

# Cleanup function (only runs if KEEP != 1)
cleanup() {
    export NEXUS_API_KEY="$ADMIN_KEY"

    print_info "Cleaning up demo data..."

    # Use Python to delete all memories created by demo users
    python3 << 'CLEANUP'
import sys, os
sys.path.insert(0, 'src')
import nexus

nx = nexus.connect(config={"mode": "remote", "url": 'http://localhost:2026', "api_key": os.getenv('NEXUS_API_KEY')})

# List and delete memories created by demo users
for user in ['alice', 'agent_alice']:
    try:
        memories = nx.memory.list(state='all')
        for mem in memories:
            if mem.get('user_id') in ['alice', 'agent_alice']:
                try:
                    nx.memory.delete(mem['memory_id'])
                except:
                    pass
    except:
        pass

nx.close()
print("✓ Cleaned up demo memories")
CLEANUP
}

# Gate cleanup behind KEEP flag for post-mortem inspection
if [ "$KEEP" != "1" ]; then
    trap cleanup EXIT
    print_info "Cleanup enabled. To keep demo data, run: KEEP=1 $0"
else
    print_info "KEEP=1 set - demo data will NOT be cleaned up"
fi

# ════════════════════════════════════════════════════════════
# Section 1: Setup - Create User and Agent
# ════════════════════════════════════════════════════════════

print_section "1. Setup - Regular User and Agent with Delegation"

print_subsection "1.0 Clean up any existing data for alice"
print_info "Removing old memories from previous demo runs..."

# Try to clean up old memories first (use admin key)
export NEXUS_API_KEY="$ADMIN_KEY"
python3 << 'CLEANUP_OLD'
import sys, os
sys.path.insert(0, 'src')
import nexus

try:
    nx = nexus.connect(config={"mode": "remote", "url": 'http://localhost:2026', "api_key": os.getenv('NEXUS_API_KEY')})

    # Delete all memories (admin can see all)
    all_memories = nx.memory.list(state='all', limit=1000)
    count = 0
    for mem in all_memories:
        # Delete memories owned by alice or agent_alice
        if mem.get('user_id') in ['alice', 'agent_alice'] or mem.get('agent_id') == 'agent_alice':
            try:
                nx.memory.delete(mem['memory_id'])
                count += 1
            except:
                pass

    print(f"✓ Cleaned up {count} old memories")
    nx.close()
except Exception as e:
    print(f"⚠ Could not clean up old data: {e}")
CLEANUP_OLD

print_subsection "1.1 Create regular user Alice"
ALICE_KEY=$(python3 scripts/create-api-key.py alice "Alice User" --days 1 2>/dev/null | grep "API Key:" | awk '{print $3}')
print_success "Created user: alice"

print_subsection "1.2 Register agent (no API key - recommended approach)"

# Register agent WITHOUT API key (uses user's auth + X-Agent-ID header)
print_info "Registering agent (will use user's auth)..."
python3 scripts/create-agent-key.py alice agent_alice "Alice's Agent" 2>&1 | grep -v "Traceback" || true

print_success "Registered agent: agent_alice (owned by alice)"
print_info "Agent will use Alice's API key + agent identity"

print_subsection "1.3 Set up ReBAC delegation (user -> agent)"
print_info "Granting agent_alice permission to act on behalf of alice"

# Grant agent permission to manage alice's memories using admin key
export NEXUS_API_KEY="$ADMIN_KEY"
python3 << 'PYTHON_DELEGATION'
import sys, os
sys.path.insert(0, 'src')
import nexus

nx = nexus.connect(config={"mode": "remote", "url": 'http://localhost:2026', "api_key": os.getenv('NEXUS_API_KEY')})

# Create delegation: agent can act as alice
# This allows the agent to read/write alice's memories
nx.rebac_create(
    subject=("agent", "agent_alice"),
    relation="delegate",
    object=("user", "alice")
)

print("✓ Set up agent delegation: agent_alice can act on behalf of alice")
nx.close()
PYTHON_DELEGATION

print_success "Delegation configured: agent_alice -> alice"

# ════════════════════════════════════════════════════════════
# Section 2: Memory Creation (Default: Inactive)
# ════════════════════════════════════════════════════════════

print_section "2. Memory Creation - New Memories Start as Inactive"

export NEXUS_API_KEY="$ALICE_KEY"

print_subsection "2.1 Agent creates memories on behalf of user"
print_info "All new memories default to 'inactive' state (pending review)"

# Create several memories using the agent
python3 << 'PYTHON_CREATE'
import sys, os
sys.path.insert(0, 'src')
import nexus

# Use Alice's API key with agent_id to act as the agent
nx = nexus.connect(config={"mode": "remote", "url": 'http://localhost:2026', "api_key": os.getenv('NEXUS_API_KEY')})
nx.agent_id = "agent_alice"  # Set agent identity

# Store memories (they will be inactive by default)
memories = [
    ("User prefers Python over JavaScript", "user", "preference"),
    ("Paris is the capital of France", "user", "fact"),
    ("Meeting with team was productive", "user", "experience"),
    ("Dark mode is easier on eyes", "user", "preference"),
    ("User's timezone is UTC-5", "user", "fact"),
]

created = []
for content, scope, mem_type in memories:
    mem_id = nx.memory.store(
        content=content,
        scope=scope,
        memory_type=mem_type
    )
    created.append(mem_id)
    print(f"✓ Created memory: {mem_id[:12]}... ({mem_type})")

print(f"\n✓ Created {len(created)} memories (all inactive by default)")
nx.close()
PYTHON_CREATE

print_success "Agent created 5 memories for alice"

# ════════════════════════════════════════════════════════════
# Section 3: Review Pending Memories
# ════════════════════════════════════════════════════════════

print_section "3. Review Pending Memories (State: Inactive)"

export NEXUS_API_KEY="$ALICE_KEY"

print_subsection "3.1 User lists inactive memories for review"
print_test "List memories with state=inactive"

INACTIVE_COUNT=$(python3 << 'PYTHON_LIST_INACTIVE'
import sys, os
sys.path.insert(0, 'src')
import nexus

nx = nexus.connect(config={"mode": "remote", "url": 'http://localhost:2026', "api_key": os.getenv('NEXUS_API_KEY')})

# List inactive memories
inactive = nx.memory.list(state='inactive')

print(f"\nFound {len(inactive)} inactive memories (pending review):\n")
for mem in inactive[:5]:
    print(f"  ID: {mem['memory_id'][:12]}...")
    print(f"  State: {mem['state']}")
    print(f"  Type: {mem.get('memory_type', 'N/A')}")
    print(f"  Created: {mem['created_at'][:19]}")
    print()

print(len(inactive))
nx.close()
PYTHON_LIST_INACTIVE
)

print_success "Found $INACTIVE_COUNT inactive memories"

print_subsection "3.2 Verify active memories are empty"
print_test "List memories with state=active (should be empty)"

ACTIVE_COUNT=$(python3 << 'PYTHON_LIST_ACTIVE'
import sys, os
sys.path.insert(0, 'src')
import nexus

nx = nexus.connect(config={"mode": "remote", "url": 'http://localhost:2026', "api_key": os.getenv('NEXUS_API_KEY')})

# List active memories
active = nx.memory.list(state='active')
print(f"Active memories: {len(active)}")

if len(active) == 0:
    print("✓ No active memories yet (expected)")
else:
    print(f"⚠ Found {len(active)} active memories (unexpected)")

print(len(active))
nx.close()
PYTHON_LIST_ACTIVE
)

if [ "$ACTIVE_COUNT" -eq "0" ]; then
    print_success "No active memories (as expected)"
else
    print_warning "Found $ACTIVE_COUNT active memories (unexpected)"
fi

# ════════════════════════════════════════════════════════════
# Section 4: Manual Approval - Single Memories
# ════════════════════════════════════════════════════════════

print_section "4. Manual Approval - Activate Individual Memories"

print_subsection "4.1 Approve specific memories"
print_info "User reviews and approves high-quality memories"

python3 << 'PYTHON_APPROVE'
import sys, os
sys.path.insert(0, 'src')
import nexus

nx = nexus.connect(config={"mode": "remote", "url": 'http://localhost:2026', "api_key": os.getenv('NEXUS_API_KEY')})

# Get inactive memories
inactive = nx.memory.list(state='inactive')

# Approve first 2 memories
approved_count = 0
for mem in inactive[:2]:
    if nx.memory.approve(mem['memory_id']):
        print(f"✓ Approved: {mem['memory_id'][:12]}... ({mem.get('memory_type', 'N/A')})")
        approved_count += 1
    else:
        print(f"✗ Failed to approve: {mem['memory_id'][:12]}...")

print(f"\n✓ Approved {approved_count} memories")
nx.close()
PYTHON_APPROVE

print_subsection "4.2 Verify state changes"
print_test "Check that approved memories are now active"

python3 << 'PYTHON_VERIFY'
import sys, os
sys.path.insert(0, 'src')
import nexus

nx = nexus.connect(config={"mode": "remote", "url": 'http://localhost:2026', "api_key": os.getenv('NEXUS_API_KEY')})

active = nx.memory.list(state='active')
inactive = nx.memory.list(state='inactive')

print(f"Active memories: {len(active)}")
print(f"Inactive memories: {len(inactive)}")

# We approved 2 out of 5, so should have 2 active and 3 inactive
if len(active) >= 2 and len(inactive) >= 3:
    print("\n✓ State transition successful!")
    print(f"  (Found {len(active)} active, {len(inactive)} inactive - may include old data)")
else:
    print(f"\n⚠ Unexpected counts (active: {len(active)}, inactive: {len(inactive)})")

nx.close()
PYTHON_VERIFY

# ════════════════════════════════════════════════════════════
# Section 5: Bulk Operations
# ════════════════════════════════════════════════════════════

print_section "5. Bulk Operations - Approve Multiple Memories"

print_subsection "5.1 Approve remaining memories in batch"
print_info "Using approve_batch() for efficient bulk approval"

python3 << 'PYTHON_BATCH'
import sys, os
sys.path.insert(0, 'src')
import nexus

nx = nexus.connect(config={"mode": "remote", "url": 'http://localhost:2026', "api_key": os.getenv('NEXUS_API_KEY')})

# Get remaining inactive memories
inactive = nx.memory.list(state='inactive')
inactive_ids = [mem['memory_id'] for mem in inactive]

print(f"Approving {len(inactive_ids)} memories in batch...")

# Approve all at once
result = nx.memory.approve_batch(inactive_ids)

print(f"\n✓ Approved: {result['approved']}")
print(f"  Failed: {result['failed']}")

if result['failed'] > 0:
    print(f"  Failed IDs: {result['failed_ids']}")

nx.close()
PYTHON_BATCH

print_subsection "5.2 Verify all memories are now active"
print_test "List all memories - should all be active"

python3 << 'PYTHON_FINAL_CHECK'
import sys, os
sys.path.insert(0, 'src')
import nexus

nx = nexus.connect(config={"mode": "remote", "url": 'http://localhost:2026', "api_key": os.getenv('NEXUS_API_KEY')})

active = nx.memory.list(state='active')
inactive = nx.memory.list(state='inactive')
all_memories = nx.memory.list(state='all')

print(f"Active memories: {len(active)}")
print(f"Inactive memories: {len(inactive)}")
print(f"Total memories: {len(all_memories)}")

if len(inactive) == 0:
    print("\n✓ All memories successfully approved and active!")
else:
    print(f"\n⚠ Still have {len(inactive)} inactive memories")

nx.close()
PYTHON_FINAL_CHECK

# ════════════════════════════════════════════════════════════
# Section 6: Deactivation and Memory Hygiene
# ════════════════════════════════════════════════════════════

print_section "6. Memory Hygiene - Deactivate Outdated Memories"

print_subsection "6.1 Deactivate specific memories"
print_info "User deactivates outdated or incorrect memories"

python3 << 'PYTHON_DEACTIVATE'
import sys, os
sys.path.insert(0, 'src')
import nexus

nx = nexus.connect(config={"mode": "remote", "url": 'http://localhost:2026', "api_key": os.getenv('NEXUS_API_KEY')})

# Get active memories
active = nx.memory.list(state='active')

# Deactivate one memory (simulate finding outdated info)
if active:
    mem_to_deactivate = active[0]
    if nx.memory.deactivate(mem_to_deactivate['memory_id']):
        print(f"✓ Deactivated: {mem_to_deactivate['memory_id'][:12]}...")
        print(f"  Reason: Simulating outdated information")
    else:
        print(f"✗ Failed to deactivate")

nx.close()
PYTHON_DEACTIVATE

print_subsection "6.2 Verify deactivation"
print_test "Check memory distribution after deactivation"

python3 << 'PYTHON_VERIFY_DEACTIVATE'
import sys, os
sys.path.insert(0, 'src')
import nexus

nx = nexus.connect(config={"mode": "remote", "url": 'http://localhost:2026', "api_key": os.getenv('NEXUS_API_KEY')})

active = nx.memory.list(state='active')
inactive = nx.memory.list(state='inactive')

print(f"Active memories: {len(active)}")
print(f"Inactive memories: {len(inactive)}")

if len(inactive) >= 1:
    print("\n✓ Deactivation successful - memory temporarily disabled")
else:
    print(f"\n⚠ No inactive memories found")

nx.close()
PYTHON_VERIFY_DEACTIVATE

# ════════════════════════════════════════════════════════════
# Section 7: Query Behavior - Default to Active Only
# ════════════════════════════════════════════════════════════

print_section "7. Query Behavior - Active Memories by Default"

print_subsection "7.1 Default query returns only active memories"
print_info "Memory retrieval defaults to active state for safety"

python3 << 'PYTHON_QUERY_DEFAULT'
import sys, os
sys.path.insert(0, 'src')
import nexus

nx = nexus.connect(config={"mode": "remote", "url": 'http://localhost:2026', "api_key": os.getenv('NEXUS_API_KEY')})

# Query without specifying state (defaults to active)
default_results = nx.memory.query(scope='user')

print(f"Default query returned {len(default_results)} memories")
print("(Only active memories included)")

# Query explicitly for all
all_results = nx.memory.query(scope='user', state='all')
print(f"Query with state='all' returned {len(all_results)} memories")

# Verify that default query returns fewer results than 'all'
if len(default_results) < len(all_results):
    print("\n✓ Default filtering to active memories works correctly")
    print(f"  Active: {len(default_results)}, Total: {len(all_results)}")
elif len(default_results) == len(all_results):
    print("\n⚠ All memories are active (no inactive memories to filter)")
else:
    print(f"\n⚠ Unexpected query behavior")

nx.close()
PYTHON_QUERY_DEFAULT

# ════════════════════════════════════════════════════════════
# Section 8: CLI Commands Demonstration
# ════════════════════════════════════════════════════════════

print_section "8. CLI Commands - State Management"

export NEXUS_API_KEY="$ALICE_KEY"

print_subsection "8.1 List memories with state filter"
echo "Command: nexus memory list --state inactive"
nexus memory list --state inactive 2>/dev/null | head -20 || true

print_subsection "8.2 Approve a memory via CLI"
# Get an inactive memory ID if any
INACTIVE_ID=$(python3 << 'PYTHON_GET_ID'
import sys, os
sys.path.insert(0, 'src')
import nexus

nx = nexus.connect(config={"mode": "remote", "url": 'http://localhost:2026', "api_key": os.getenv('NEXUS_API_KEY')})
inactive = nx.memory.list(state='inactive')
if inactive:
    print(inactive[0]['memory_id'])
nx.close()
PYTHON_GET_ID
)

if [ -n "$INACTIVE_ID" ]; then
    echo "Command: nexus memory approve $INACTIVE_ID"
    nexus memory approve "$INACTIVE_ID" 2>/dev/null || true
    print_success "Memory approved via CLI"
fi

# ════════════════════════════════════════════════════════════
# Summary
# ════════════════════════════════════════════════════════════

export NEXUS_API_KEY="$ADMIN_KEY"

print_section "✅ Memory State Management Demo Complete!"

echo "╔═══════════════════════════════════════════════════════════════════╗"
echo "║              Memory State Management Capabilities                 ║"
echo "╠═══════════════════════════════════════════════════════════════════╣"
echo "║  ✅ Manual Approval Workflow (inactive → active)                  ║"
echo "║  ✅ State Filtering (inactive/active/all)                         ║"
echo "║  ✅ Single Memory Operations (approve/deactivate)                 ║"
echo "║  ✅ Bulk Operations (approve_batch/deactivate_batch)              ║"
echo "║  ✅ User → Agent Delegation with ReBAC                            ║"
echo "║  ✅ Default to Active (safe query behavior)                       ║"
echo "║  ✅ Memory Hygiene (temporary deactivation)                       ║"
echo "║  ✅ Quality Control (review before activation)                    ║"
echo "╚═══════════════════════════════════════════════════════════════════╝"
echo ""
print_info "All tests passed! Memory state management is working."
print_info ""
print_info "Use Cases Demonstrated:"
print_info "  • Quality Control: Review memories before they affect agent behavior"
print_info "  • Memory Hygiene: Disable outdated memories without deletion"
print_info "  • Privacy: Review and control what information is active"
print_info "  • Debugging: Temporarily disable specific memories"
print_info "  • Curation: Maintain a clean, high-quality memory store"
echo ""
