#!/usr/bin/env python3
"""
Autonomous Task Executor for Rivet
Reads TODO.md, picks safe tasks, executes them autonomously.
"""

import re
import os
import sys
from datetime import datetime
from pathlib import Path

# Base paths
WORKSPACE = Path("/home/ccuser/rateright-growth/rivet")
TODO_FILE = WORKSPACE / "TODO.md"
MEMORY_DIR = WORKSPACE / "memory"

# Patterns for unsafe tasks (external comms, deploys, etc.)
# Level 4 (Active) + Production deploys - Approved by Michael 2026-02-05
# Blocked: external comms, social posts, spend >$10, deletes, new accounts
UNSAFE_PATTERNS = [
    # External communications (still blocked)
    r'\bsend\b.*\b(email|sms|message)\b', r'\bemail\b.*\bsend', r'\bsms\b',
    r'\btweet\b', r'\bmessage\b.*\bsend',
    r'\bnotif.*user', r'\bcall\b.*\b(customer|lead|client)\b',
    # Social media posting (still blocked)
    r'\binstagram\b', r'\bfacebook\b', r'\btiktok\b', r'\btwitter\b',
    r'\blinkedin\b.*post', r'\bsocial\b.*post', r'\bpost\b.*\bsocial',
    # Meta/self-referential tasks
    r'sub-agent', r'heartbeat', r'task.?executor',
    # Dangerous operations
    r'\bdelete\b.*\b(account|user|data)\b', r'\bdrop\b.*\btable',
    r'\bcreate\b.*\baccount\b', r'\bsignup\b.*\bnew'
]

# Safe task indicators (research, design, build, analyze, etc.)
SAFE_INDICATORS = [
    r'\bresearch\b', r'\bdesign\b', r'\bbuild\b', r'\bcreate\b',
    r'\banalyze\b', r'\bupdate\b', r'\bwrite\b', r'\brefactor\b',
    r'\btest\b', r'\bdocument\b', r'\bimplement\b', r'\bplan\b',
    r'\bscript\b', r'\breview\b', r'\boptimize\b', r'\bfix\b'
]


def log(message, level="INFO"):
    """Log to console and daily memory file"""
    timestamp = datetime.now().strftime("%H:%M:%S")
    log_line = f"[{timestamp}] [{level}] {message}"
    print(log_line)
    
    # Append to daily memory
    today = datetime.now().strftime("%Y-%m-%d")
    memory_file = MEMORY_DIR / f"{today}.md"
    
    MEMORY_DIR.mkdir(exist_ok=True)
    
    with open(memory_file, "a") as f:
        f.write(f"\n{log_line}")


def is_task_safe(task_text):
    """Determine if a task is safe for autonomous execution"""
    lower_text = task_text.lower()
    
    # Check for unsafe patterns
    for pattern in UNSAFE_PATTERNS:
        if re.search(pattern, lower_text, re.IGNORECASE):
            return False
    
    # Prefer tasks with safe indicators
    for pattern in SAFE_INDICATORS:
        if re.search(pattern, lower_text, re.IGNORECASE):
            return True
    
    # If no clear indicators, be conservative
    return False


def parse_todo():
    """Parse TODO.md and extract tasks with metadata"""
    if not TODO_FILE.exists():
        log("TODO.md not found", "ERROR")
        return []
    
    with open(TODO_FILE, 'r') as f:
        content = f.read()
    
    tasks = []
    current_section = None
    current_priority = 0
    
    # Priority scoring: 🔴 Priority = 100, 🔴 Active = 50, 🟡 Queued = 10
    priority_map = {
        '🔴 Priority': 100,
        '🔴 Active': 50,
        '🟡 Queued': 10
    }
    
    lines = content.split('\n')
    for i, line in enumerate(lines):
        # Track section for priority
        for section, score in priority_map.items():
            if section in line:
                current_section = section
                current_priority = score
                break
        
        # Find incomplete tasks: [ ] or [⏳]
        # Match: - [ ] Task text or - [⏳] Task text
        task_match = re.match(r'^(\s*)- \[([ ⏳])\] (.+)$', line)
        if task_match:
            indent, status, task_text = task_match.groups()
            indent_level = len(indent) // 2  # Assuming 2 spaces per indent
            
            # Skip completed tasks
            if status == ' ' or status == '⏳':
                tasks.append({
                    'line_num': i,
                    'indent': indent_level,
                    'status': status,
                    'text': task_text,
                    'full_line': line,
                    'priority': current_priority - (indent_level * 5),  # Reduce for sub-tasks
                    'safe': is_task_safe(task_text)
                })
    
    return tasks


def select_next_task(tasks):
    """Select highest priority safe, incomplete task"""
    # Filter for safe tasks that aren't already in progress
    eligible = [t for t in tasks if t['safe'] and t['status'] != '⏳']
    
    if not eligible:
        log("No eligible autonomous-safe tasks found")
        return None
    
    # Sort by priority (highest first)
    eligible.sort(key=lambda t: t['priority'], reverse=True)
    
    return eligible[0]


def update_task_status(line_num, new_status):
    """Update task status in TODO.md"""
    with open(TODO_FILE, 'r') as f:
        lines = f.readlines()
    
    # Replace status marker
    line = lines[line_num]
    if '[x]' in line:
        return  # Already done
    
    # Replace [ ] or [⏳] with new status
    updated_line = re.sub(r'\[([ ⏳x])\]', f'[{new_status}]', line)
    lines[line_num] = updated_line
    
    with open(TODO_FILE, 'w') as f:
        f.writelines(lines)


def execute_task(task):
    """Execute task by spawning a sub-agent via clawdbot"""
    log(f"Executing task: {task['text']}")
    
    # Mark as in-progress
    update_task_status(task['line_num'], '⏳')
    log(f"Marked task as in-progress: {task['text']}")
    
    # Build sub-agent command
    task_description = task['text']
    
    # Create a focused instruction for the sub-agent
    instruction = f"""Complete this task from TODO.md:

{task_description}

Rules:
- Read relevant files in /home/ccuser/rateright-growth/rivet/
- Create/update files as needed
- Log your work (what you did, what files you changed)
- If you can't complete it, explain why
- NO external communications (no emails, posts, deploys)
- Keep it focused and practical

Your final message should summarize what you accomplished."""
    
    # Generate unique session ID for this task
    session_id = f"task-executor-{task['line_num']}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
    
    # Spawn sub-agent via clawdbot CLI
    cmd = [
        'clawdbot', 'agent',
        '--session-id', session_id,
        '--message', instruction,
        '--timeout', '300',  # 5 minute timeout
        '--json'  # Get JSON output for easier parsing
    ]
    
    try:
        import subprocess
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
            timeout=330  # Slightly longer than agent timeout
        )
        
        if result.returncode == 0:
            log(f"Task completed successfully: {task['text']}")
            update_task_status(task['line_num'], 'x')
            
            # Log the output
            if result.stdout:
                log(f"Agent output:\n{result.stdout[:500]}")  # First 500 chars
            
            return True
        else:
            log(f"Task failed: {task['text']}", "ERROR")
            log(f"Error: {result.stderr[:500]}", "ERROR")
            
            # Reset to incomplete
            update_task_status(task['line_num'], ' ')
            return False
            
    except subprocess.TimeoutExpired:
        log(f"Task timed out: {task['text']}", "ERROR")
        update_task_status(task['line_num'], ' ')
        return False
    except Exception as e:
        log(f"Task execution error: {str(e)}", "ERROR")
        update_task_status(task['line_num'], ' ')
        return False


def show_status():
    """Show current task execution status"""
    tasks = parse_todo()
    
    # Find in-progress tasks
    in_progress = [t for t in tasks if t['status'] == '⏳']
    
    print("\n=== Task Executor Status ===\n")
    
    if in_progress:
        print(f"⏳ {len(in_progress)} task(s) in progress:")
        for task in in_progress:
            print(f"  - {task['text']}")
    else:
        print("✅ No tasks currently in progress")
    
    # Show safe task queue
    safe_incomplete = [t for t in tasks if t['safe'] and t['status'] == ' ']
    if safe_incomplete:
        print(f"\n📋 {len(safe_incomplete)} safe tasks queued:")
        for task in sorted(safe_incomplete, key=lambda t: t['priority'], reverse=True)[:5]:
            print(f"  - [P{task['priority']}] {task['text']}")
    
    print()


def main():
    """Main execution loop"""
    import argparse
    
    parser = argparse.ArgumentParser(description='Autonomous task executor')
    parser.add_argument('--dry-run', action='store_true', help='Show what would be done without executing')
    parser.add_argument('--status', action='store_true', help='Show current execution status')
    parser.add_argument('--max-tasks', type=int, default=1, help='Maximum tasks to execute in one run')
    args = parser.parse_args()
    
    if args.status:
        show_status()
        return 0
    
    log("=== Autonomous Task Executor Started ===")
    if args.dry_run:
        log("DRY RUN MODE - No tasks will be executed")
    
    # Parse TODO.md
    tasks = parse_todo()
    log(f"Found {len(tasks)} total tasks")
    
    safe_tasks = [t for t in tasks if t['safe']]
    log(f"Found {len(safe_tasks)} autonomous-safe tasks")
    
    if args.dry_run:
        log("\nSafe tasks that would be eligible:")
        for i, task in enumerate(sorted(safe_tasks, key=lambda t: t['priority'], reverse=True)[:5]):
            log(f"  {i+1}. [Priority {task['priority']}] {task['text']}")
        return 0
    
    # Execute up to max_tasks
    completed = 0
    failed = 0
    
    for i in range(args.max_tasks):
        # Select next task
        task = select_next_task(tasks)
        
        if not task:
            log(f"No more tasks to execute (completed {completed}, failed {failed})")
            break
        
        log(f"Selected task {i+1}/{args.max_tasks} (priority {task['priority']}): {task['text']}")
        
        # Execute task
        success = execute_task(task)
        
        if success:
            log("✅ Task completed successfully")
            completed += 1
            # Remove from task list so we don't pick it again
            tasks = [t for t in tasks if t['line_num'] != task['line_num']]
        else:
            log("❌ Task failed, moving to next", "WARN")
            failed += 1
            # Remove failed task from consideration this run
            tasks = [t for t in tasks if t['line_num'] != task['line_num']]
    
    log(f"=== Execution complete: {completed} completed, {failed} failed ===")
    return 0 if failed == 0 else 1


if __name__ == "__main__":
    try:
        sys.exit(main())
    except Exception as e:
        log(f"Fatal error: {str(e)}", "ERROR")
        import traceback
        log(traceback.format_exc(), "ERROR")
        sys.exit(1)
