#!/usr/bin/env python3
"""
Corrections Retrieval Engine
Searches and ranks corrections based on intent and context.
"""

import os
import sys
import json
import re
from datetime import datetime, timedelta
from pathlib import Path

# Paths
WORKSPACE = Path("/home/aria/.openclaw/workspace")
CORRECTIONS_DIR = WORKSPACE / "agency" / "corrections"
CONFIG_FILE = WORKSPACE / "agency" / "corrections-config.yaml"
INTENTS_FILE = Path(__file__).parent / "intents.yaml"

# Simple YAML parser (no external deps)
def parse_yaml_simple(filepath):
    """Basic YAML parser for our simple structures."""
    result = {}
    current_key = None
    
    with open(filepath, 'r') as f:
        content = f.read()
    
    lines = content.split('\n')
    i = 0
    while i < len(lines):
        line = lines[i].rstrip()
        
        if not line or line.startswith('#'):
            i += 1
            continue
        
        # Top-level key-value or key with block
        if ':' in line and not line.startswith(' ') and not line.startswith('\t'):
            key, _, value = line.partition(':')
            key = key.strip()
            value = value.strip()
            
            # Handle quoted strings
            if value.startswith('"') and value.endswith('"'):
                value = value[1:-1]
            
            # Check if next lines are list items
            if not value:
                # Look ahead for list items
                items = []
                j = i + 1
                while j < len(lines):
                    next_line = lines[j].rstrip()
                    if next_line.strip().startswith('- '):
                        item = next_line.strip()[2:].strip()
                        if item.startswith('"') and item.endswith('"'):
                            item = item[1:-1]
                        items.append(item)
                        j += 1
                    elif next_line and not next_line.startswith(' ') and not next_line.startswith('\t') and ':' in next_line:
                        break
                    elif next_line.strip().startswith('|'):
                        j += 1
                    elif not next_line:
                        j += 1
                    else:
                        j += 1
                
                if items:
                    result[key] = items
                    i = j
                    continue
                else:
                    result[key] = None
            else:
                result[key] = value
            
            current_key = key
        
        i += 1
    
    return result

def load_correction(filepath):
    """Load a single correction YAML file."""
    return parse_yaml_simple(filepath)

def load_all_corrections():
    """Load all correction YAML files."""
    corrections = []
    for f in CORRECTIONS_DIR.glob("COR-*.yaml"):
        try:
            corr = load_correction(f)
            corr['_file'] = f.name
            corrections.append(corr)
        except Exception as e:
            print(f"Warning: Failed to load {f}: {e}", file=sys.stderr)
    return corrections

def detect_intent(text):
    """Detect intent from user message text."""
    text_lower = text.lower()
    
    # Intent keywords mapping
    intent_keywords = {
        'deployment': ['deploy', 'build', 'release', 'ship', 'production', 'cloud run', 'caddy', 'server', 'restart', 'process'],
        'qa': ['test', 'qa', 'verify', 'fixed', 'done', 'ready', 'working', 'check'],
        'code': ['create', 'new project', 'new app', 'branch', 'merge', 'code'],
        'security': ['credentials', 'password', 'api key', 'secret', 'env', 'token'],
        'infrastructure': ['firebase', 'firestore', 'config', 'gateway', 'gcp', 'auth'],
        'design': ['logo', 'brand', 'design', 'ui', 'ux'],
        'communication': ['discord', 'message', 'reply', 'format', 'error'],
    }
    
    detected = []
    for intent, keywords in intent_keywords.items():
        for kw in keywords:
            if kw in text_lower:
                detected.append(intent)
                break
    
    return list(set(detected)) if detected else ['general']

def calculate_score(correction, intents, person=None, query=''):
    """Calculate relevance score for a correction."""
    
    # Severity weights
    severity_weights = {
        'critical': 100,
        'high': 50,
        'medium': 20,
        'low': 5
    }
    
    # Authority weights
    authority_weights = {
        'cto': 30,
        'lead': 20,
        'member': 10
    }
    
    # Base scores
    severity = correction.get('severity', 'medium')
    authority = correction.get('authority', 'member')
    
    score = severity_weights.get(severity, 20)
    score += authority_weights.get(authority, 10)
    
    # Trigger match bonus - check if triggers appear in query
    triggers = correction.get('triggers', [])
    if isinstance(triggers, str):
        triggers = [triggers]
    
    query_lower = query.lower()
    trigger_matches = 0
    for trigger in triggers:
        if trigger.lower() in query_lower:
            trigger_matches += 1
            score += 40  # Strong bonus for direct keyword match
    
    # Category match bonus
    category = correction.get('category', '')
    for intent in intents:
        if intent == category:
            score += 30
    
    # Times applied bonus (experience)
    times_applied = int(correction.get('times_applied', 0) or 0)
    score += min(times_applied * 5, 50)  # Cap at 50
    
    # Confirmed by bonus
    confirmed = correction.get('confirmed_by', [])
    if isinstance(confirmed, str):
        confirmed = [confirmed] if confirmed else []
    score += len(confirmed) * 10
    
    # Teacher bonus (if talking to the person who taught this)
    if person:
        taught_by = correction.get('taught_by', '').lower()
        if taught_by and taught_by in person.lower():
            score += 20
    
    # Freshness decay
    date_str = correction.get('date', '')
    if date_str:
        try:
            corr_date = datetime.strptime(date_str, '%Y-%m-%d')
            age_days = (datetime.now() - corr_date).days
            
            if age_days < 30:
                freshness = 1.0
            elif age_days < 90:
                freshness = 0.8
            elif age_days < 180:
                freshness = 0.5
            else:
                freshness = 0.3
            
            # Critical corrections don't decay
            if severity != 'critical':
                score = score * freshness
        except:
            pass
    
    return score

def retrieve_corrections(query, top_n=3, person=None):
    """Retrieve top N relevant corrections for a query."""
    
    # Detect intents
    intents = detect_intent(query)
    
    # Load all corrections
    corrections = load_all_corrections()
    
    # Score each correction
    scored = []
    for corr in corrections:
        score = calculate_score(corr, intents, person, query)
        scored.append((score, corr))
    
    # Sort by score descending
    scored.sort(key=lambda x: x[0], reverse=True)
    
    # Return top N
    return [(s, c) for s, c in scored[:top_n]]

def format_as_memory(score, correction):
    """Format a correction as a micro-memory."""
    taught_by = correction.get('taught_by', 'unknown')
    summary = correction.get('summary', 'No summary')
    cor_id = correction.get('id', 'COR-???')
    severity = correction.get('severity', 'medium')
    times = correction.get('times_applied', 0)
    confirmed = correction.get('confirmed_by', [])
    
    # Build the memory string
    memory = f"💡 I learned from {taught_by.title()}: {summary}"
    
    # Add metadata
    meta_parts = [cor_id]
    if severity == 'critical':
        meta_parts.append("⚠️ critical")
    if times and int(times) > 0:
        meta_parts.append(f"applied {times}x")
    if confirmed and len(confirmed) > 0:
        if isinstance(confirmed, list):
            meta_parts.append(f"confirmed by: {', '.join(confirmed)}")
    
    memory += f"\n   ({', '.join(meta_parts)})"
    
    return memory

def main():
    """CLI interface."""
    if len(sys.argv) < 2:
        print("Usage: retrieve.py <query> [--top N] [--person NAME] [--json]")
        sys.exit(1)
    
    query = sys.argv[1]
    top_n = 3
    person = None
    output_json = False
    
    # Parse args
    args = sys.argv[2:]
    i = 0
    while i < len(args):
        if args[i] == '--top' and i + 1 < len(args):
            top_n = int(args[i + 1])
            i += 2
        elif args[i] == '--person' and i + 1 < len(args):
            person = args[i + 1]
            i += 2
        elif args[i] == '--json':
            output_json = True
            i += 1
        else:
            i += 1
    
    # Retrieve
    results = retrieve_corrections(query, top_n, person)
    
    if output_json:
        output = []
        for score, corr in results:
            output.append({
                'id': corr.get('id'),
                'score': score,
                'summary': corr.get('summary'),
                'taught_by': corr.get('taught_by'),
                'severity': corr.get('severity'),
            })
        print(json.dumps(output, indent=2))
    else:
        # Print as micro-memories
        intents = detect_intent(query)
        print(f"Query: {query}")
        print(f"Detected intents: {', '.join(intents)}")
        print(f"\n{'='*60}\n")
        
        for score, corr in results:
            print(format_as_memory(score, corr))
            print()

if __name__ == '__main__':
    main()
