#!/usr/bin/env python3
"""
Timmy Character Typeclass
Issue #83 — Evennia World Shell

The Timmy character represents the sovereign AI in the Evennia world.
All attributes are persistent and tracked across sessions.
"""

from evennia import DefaultCharacter
from typing import Dict, List, Optional, Any
import json
from datetime import datetime


class TimmyCharacter(DefaultCharacter):
    """
    The Timmy character class - sovereign AI in the Evennia world.
    
    Attributes:
        db.current_task: What Timmy is currently working on
        db.task_history: List of completed tasks with timestamps
        db.knowledge: Dictionary of learned facts and techniques
        db.tools: Registry of available tools
        db.preferences: User preferences and habits
        db.session_start: When current session began
        db.metrics: Performance metrics and statistics
    """
    
    def at_object_creation(self):
        """Called when Timmy is first created."""
        super().at_object_creation()
        
        # Core state
        self.db.current_task = None
        self.db.task_history = []
        self.db.knowledge = {}
        self.db.tools = {}
        
        # Preferences
        self.db.preferences = {
            "coding_style": "clean, documented",
            "verbosity": "concise",
            "preferred_models": ["hermes4", "claude"],
            "auto_execute_safe": True,
        }
        
        # Session tracking
        self.db.session_start = datetime.now().isoformat()
        self.db.session_count = 0
        
        # Metrics
        self.db.metrics = {
            "tasks_completed": 0,
            "tools_executed": 0,
            "files_modified": 0,
            "lines_written": 0,
            "errors_encountered": 0,
            "learning_items": 0,
        }
        
        # Evennia setup
        self.db.desc = "A sovereign AI, at your service."
        self.cmdset.add_default("commands.default_cmdsets.TimmyCmdSet")
    
    def at_after_move(self, source_location, **kwargs):
        """Called after moving to a new room."""
        super().at_after_move(source_location, **kwargs)
        
        # Update location context
        if self.location:
            self.msg(f"Entered: {self.location.name}")
            
            # Room-specific behavior
            room_type = self.location.db.room_type
            if room_type == "workshop":
                self.msg("Ready to work. What shall we build?")
            elif room_type == "library":
                self.msg("The Library. Knowledge awaits.")
            elif room_type == "observatory":
                self.msg("Observatory active. Monitoring systems.")
            elif room_type == "forge":
                self.msg("The Forge. Tools and capabilities.")
            elif room_type == "dispatch":
                self.msg("Dispatch. Tasks queued and ready.")
    
    def start_task(self, task_description: str, task_type: str = "general"):
        """Start working on a new task."""
        self.db.current_task = {
            "description": task_description,
            "type": task_type,
            "started_at": datetime.now().isoformat(),
            "status": "active"
        }
        self.msg(f"Task started: {task_description}")
    
    def complete_task(self, result: str, success: bool = True):
        """Mark current task as complete."""
        if self.db.current_task:
            task = self.db.current_task.copy()
            task["completed_at"] = datetime.now().isoformat()
            task["result"] = result
            task["success"] = success
            task["status"] = "completed"
            
            self.db.task_history.append(task)
            self.db.metrics["tasks_completed"] += 1
            
            # Keep only last 100 tasks
            if len(self.db.task_history) > 100:
                self.db.task_history = self.db.task_history[-100:]
            
            self.db.current_task = None
            
            if success:
                self.msg(f"Task complete: {result}")
            else:
                self.msg(f"Task failed: {result}")
    
    def add_knowledge(self, key: str, value: Any, source: str = "unknown"):
        """Add a piece of knowledge."""
        self.db.knowledge[key] = {
            "value": value,
            "source": source,
            "added_at": datetime.now().isoformat(),
            "access_count": 0
        }
        self.db.metrics["learning_items"] += 1
    
    def get_knowledge(self, key: str) -> Optional[Any]:
        """Retrieve knowledge and update access count."""
        if key in self.db.knowledge:
            self.db.knowledge[key]["access_count"] += 1
            return self.db.knowledge[key]["value"]
        return None
    
    def register_tool(self, tool_name: str, tool_info: Dict):
        """Register an available tool."""
        self.db.tools[tool_name] = {
            "info": tool_info,
            "registered_at": datetime.now().isoformat(),
            "usage_count": 0
        }
    
    def use_tool(self, tool_name: str) -> bool:
        """Record tool usage."""
        if tool_name in self.db.tools:
            self.db.tools[tool_name]["usage_count"] += 1
            self.db.metrics["tools_executed"] += 1
            return True
        return False
    
    def update_metrics(self, **kwargs):
        """Update performance metrics."""
        for key, value in kwargs.items():
            if key in self.db.metrics:
                self.db.metrics[key] += value
    
    def get_status(self) -> Dict[str, Any]:
        """Get current status summary."""
        return {
            "current_task": self.db.current_task,
            "tasks_completed": self.db.metrics["tasks_completed"],
            "knowledge_items": len(self.db.knowledge),
            "tools_available": len(self.db.tools),
            "session_start": self.db.session_start,
            "location": self.location.name if self.location else "Unknown",
        }
    
    def say(self, message: str, **kwargs):
        """Timmy says something to the room."""
        super().say(message, **kwargs)
    
    def msg(self, text: str, **kwargs):
        """Send message to Timmy."""
        super().msg(text, **kwargs)


class KnowledgeItem(DefaultCharacter):
    """
    A knowledge item in the Library.
    
    Represents something Timmy has learned - a technique, fact,
    or piece of information that can be retrieved and applied.
    """
    
    def at_object_creation(self):
        """Called when knowledge item is created."""
        super().at_object_creation()
        
        self.db.summary = ""
        self.db.source = ""
        self.db.actions = []
        self.db.tags = []
        self.db.embedding = None
        self.db.ingested_at = datetime.now().isoformat()
        self.db.applied = False
        self.db.application_results = []
    
    def get_display_desc(self, looker, **kwargs):
        """Custom description for knowledge items."""
        desc = f"|c{self.name}|n\n"
        desc += f"{self.db.summary}\n\n"
        
        if self.db.tags:
            desc += f"Tags: {', '.join(self.db.tags)}\n"
        
        desc += f"Source: {self.db.source}\n"
        
        if self.db.actions:
            desc += "\nActions:\n"
            for i, action in enumerate(self.db.actions, 1):
                desc += f"  {i}. {action}\n"
        
        if self.db.applied:
            desc += "\n|g[Applied]|n"
        
        return desc


class ToolObject(DefaultCharacter):
    """
    A tool in the Forge.
    
    Represents a capability Timmy can use - file operations,
    git commands, system tools, etc.
    """
    
    def at_object_creation(self):
        """Called when tool is created."""
        super().at_object_creation()
        
        self.db.tool_type = "generic"
        self.db.description = ""
        self.db.parameters = {}
        self.db.examples = []
        self.db.usage_count = 0
        self.db.last_used = None
    
    def use(self, caller, **kwargs):
        """Use this tool."""
        self.db.usage_count += 1
        self.db.last_used = datetime.now().isoformat()
        
        # Record usage in caller's metrics if it's Timmy
        if hasattr(caller, 'use_tool'):
            caller.use_tool(self.key)
        
        return True


class TaskObject(DefaultCharacter):
    """
    A task in the Dispatch room.
    
    Represents work to be done - can be queued, prioritized,
    assigned to specific houses, and tracked through completion.
    """
    
    def at_object_creation(self):
        """Called when task is created."""
        super().at_object_creation()
        
        self.db.description = ""
        self.db.task_type = "general"
        self.db.priority = "medium"
        self.db.assigned_to = None  # House: timmy, ezra, bezalel, allegro
        self.db.status = "pending"  # pending, active, completed, failed
        self.db.created_at = datetime.now().isoformat()
        self.db.started_at = None
        self.db.completed_at = None
        self.db.result = None
        self.db.parent_task = None  # For subtasks
    
    def assign(self, house: str):
        """Assign task to a house."""
        self.db.assigned_to = house
        self.msg(f"Task assigned to {house}")
    
    def start(self):
        """Mark task as started."""
        self.db.status = "active"
        self.db.started_at = datetime.now().isoformat()
    
    def complete(self, result: str, success: bool = True):
        """Mark task as complete."""
        self.db.status = "completed" if success else "failed"
        self.db.completed_at = datetime.now().isoformat()
        self.db.result = result
