"""
Orchestrator Commands - Command handler for the orchestration agent.

This module processes commands from the orchestration agent:
- Task Management: /assign, /broadcast, /priority
- Monitoring: /status, /usage, /health
- Memory: /memory, /decisions, /context
- Agent Management: /spawn, /pause, /resume, /reassign
- System: /save, /report, /help
"""

import re
import logging
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple
from dataclasses import dataclass, field

from ..persistence.database import OrchestratorDB
from ..persistence.models import Task
from ..tracking.cli_usage import CLIUsageTracker, get_cli_tracker, AgentAvailability
from ..memory.operational import OperationalMemory

# Import project and agent modules
try:
    from ..projects import ProjectManager, ProjectPlanner, create_project_plan
    from ..intelligence import analyze_task
    from ..agents import (
        get_registry, get_template, list_templates,
        AgentDeveloper, TemplateWizard
    )
    PROJECT_FEATURES_AVAILABLE = True
except ImportError:
    PROJECT_FEATURES_AVAILABLE = False


logger = logging.getLogger(__name__)


@dataclass
class CommandResult:
    """Result of executing an orchestrator command."""
    success: bool
    message: str
    data: Dict[str, Any] = field(default_factory=dict)
    suggestions: List[str] = field(default_factory=list)


class OrchestratorCommands:
    """
    Processes orchestrator commands.

    The orchestration agent (Claude Code) issues commands like /assign, /status, etc.
    This class parses and executes those commands.
    """

    def __init__(
        self,
        db: OrchestratorDB,
        operational_memory: OperationalMemory,
        cli_tracker: Optional[CLIUsageTracker] = None,
        adapters: Optional[Dict[str, Any]] = None,
    ):
        """
        Initialize the command handler.

        Args:
            db: Database for task/agent management
            operational_memory: Operational memory for project state
            cli_tracker: CLI usage tracker for session management
            adapters: Registered agent adapters
        """
        self.db = db
        self.operational_memory = operational_memory
        self.cli_tracker = cli_tracker or get_cli_tracker()
        self.adapters = adapters or {}
        self.spawned_agents: Dict[str, Dict[str, Any]] = {}

        # Command registry
        self._commands = {
            # Project Management
            "/project": self._cmd_project,

            # Agent Templates
            "/agent": self._cmd_agent,

            # Task Management
            "/assign": self._cmd_assign,
            "/cancel": self._cmd_cancel,
            "/broadcast": self._cmd_broadcast,
            "/priority": self._cmd_priority,

            # Monitoring
            "/status": self._cmd_status,
            "/progress": self._cmd_progress,
            "/usage": self._cmd_usage,
            "/health": self._cmd_health,

            # Memory & Context
            "/memory": self._cmd_memory,
            "/decisions": self._cmd_decisions,
            "/context": self._cmd_context,

            # Agent Management
            "/spawn": self._cmd_spawn,
            "/pause": self._cmd_pause,
            "/resume": self._cmd_resume,
            "/reassign": self._cmd_reassign,
            "/view": self._cmd_view,

            # System
            "/save": self._cmd_save,
            "/report": self._cmd_report,
            "/help": self._cmd_help,
        }

        # Project manager (lazy initialized)
        self._project_manager: Optional[Any] = None
        self._agent_developer: Optional[Any] = None

        # Workspace manager for tmux sessions (lazy initialized)
        self._workspace_manager = None

    def register_adapter(self, agent_id: str, adapter: Any) -> None:
        """Register an agent adapter."""
        self.adapters[agent_id] = adapter

    async def execute(self, command_str: str) -> CommandResult:
        """
        Execute an orchestrator command.

        Args:
            command_str: The full command string (e.g., "/assign claude-code Fix the bug")

        Returns:
            CommandResult with success status and output
        """
        # Parse command
        parts = command_str.strip().split(maxsplit=1)
        if not parts:
            return CommandResult(False, "Empty command")

        cmd = parts[0].lower()
        args = parts[1] if len(parts) > 1 else ""

        # Find and execute handler
        handler = self._commands.get(cmd)
        if not handler:
            return CommandResult(
                False,
                f"Unknown command: {cmd}",
                suggestions=["/help for available commands"]
            )

        try:
            return await handler(args)
        except Exception as e:
            logger.error(f"Command {cmd} failed: {e}")
            return CommandResult(False, f"Command failed: {str(e)}")

    # =========================================================================
    # Project Management Commands
    # =========================================================================

    def _get_project_manager(self) -> Any:
        """Get or create the project manager."""
        if self._project_manager is None and PROJECT_FEATURES_AVAILABLE:
            self._project_manager = ProjectManager(self.db)
        return self._project_manager

    def _get_agent_developer(self) -> Any:
        """Get or create the agent developer."""
        if self._agent_developer is None and PROJECT_FEATURES_AVAILABLE:
            self._agent_developer = AgentDeveloper()
        return self._agent_developer

    async def _cmd_project(self, args: str) -> CommandResult:
        """
        /project <subcommand> [args]
        Project management commands.

        Subcommands:
            new <task>      - Plan and create a new project
            list            - List recent projects
            resume <id>     - Resume a previous project
            status          - Show current project status
            archive <id>    - Archive a completed project
        """
        if not PROJECT_FEATURES_AVAILABLE:
            return CommandResult(
                False,
                "Project features not available. Check module imports.",
                suggestions=["Ensure intelligence and projects modules are installed"]
            )

        parts = args.split(maxsplit=1)
        if not parts:
            return CommandResult(
                False,
                "Usage: /project <new|list|resume|status|archive> [args]",
                suggestions=[
                    "/project new Write a story about robots",
                    "/project list",
                    "/project resume proj-12345",
                ]
            )

        subcommand = parts[0].lower()
        sub_args = parts[1] if len(parts) > 1 else ""

        if subcommand == "new":
            return await self._project_new(sub_args)
        elif subcommand == "list":
            return await self._project_list()
        elif subcommand == "resume":
            return await self._project_resume(sub_args)
        elif subcommand == "status":
            return await self._project_status()
        elif subcommand == "archive":
            return await self._project_archive(sub_args)
        else:
            return CommandResult(
                False,
                f"Unknown project subcommand: {subcommand}",
                suggestions=["Use: new, list, resume, status, archive"]
            )

    async def _project_new(self, task_description: str) -> CommandResult:
        """Create a new project with planning phase."""
        if not task_description:
            return CommandResult(
                False,
                "Usage: /project new <task description>",
                suggestions=["/project new Write a short story about a robot learning to love"]
            )

        manager = self._get_project_manager()
        planner = ProjectPlanner(manager)

        # Create the plan
        plan = planner.plan_project(task_description)

        # Format plan for display
        plan_text = planner.format_plan(plan)

        # Store plan for later execution
        self.operational_memory.record_decision(
            decision=f"Project planned: {plan.suggested_name}",
            rationale=f"Domain: {plan.primary_domain_name}, Team: {plan.team.team_size} agents",
        )

        return CommandResult(
            True,
            plan_text,
            data={
                "plan": {
                    "name": plan.suggested_name,
                    "domain": plan.primary_domain_name,
                    "confidence": f"{plan.domain_analysis.primary_confidence:.0%}",
                    "complexity": plan.estimated_complexity,
                    "team_size": plan.team.team_size,
                    "lead_agent": plan.team.lead.id,
                    "approach": plan.approach_steps,
                },
                "status": "awaiting_approval",
            },
            suggestions=[
                "Review the plan above",
                "Type 'yes' or '/project execute' to create the project",
                "Type 'no' or a new task to start over",
            ]
        )

    async def _project_list(self) -> CommandResult:
        """List recent projects."""
        manager = self._get_project_manager()
        projects = manager.list_recent_projects(limit=10)

        if not projects:
            return CommandResult(
                True,
                "No projects found",
                suggestions=["/project new <task> to create your first project"]
            )

        projects_data = []
        for proj in projects:
            projects_data.append({
                "id": proj.id,
                "name": proj.name,
                "domain": proj.domain.value,
                "status": proj.status,
                "progress": f"{proj.completed_tasks}/{proj.total_tasks}" if proj.total_tasks else "0/0",
                "last_accessed": str(proj.last_accessed_at)[:19] if proj.last_accessed_at else "N/A",
            })

        # Format as table-like output
        lines = ["Recent Projects:", ""]
        for p in projects_data:
            status_emoji = {"active": "🟢", "paused": "🟡", "completed": "✅", "archived": "📦"}.get(p["status"], "⚪")
            lines.append(f"  {status_emoji} {p['id'][:20]}")
            lines.append(f"     {p['name'][:40]} ({p['domain']})")
            lines.append(f"     Progress: {p['progress']} | Last: {p['last_accessed']}")
            lines.append("")

        return CommandResult(
            True,
            "\n".join(lines),
            data={"projects": projects_data, "count": len(projects_data)},
            suggestions=["/project resume <id> to continue a project"]
        )

    async def _project_resume(self, project_id: str) -> CommandResult:
        """Resume a previous project."""
        if not project_id:
            return CommandResult(
                False,
                "Usage: /project resume <project-id>",
                suggestions=["/project list to see available projects"]
            )

        manager = self._get_project_manager()

        try:
            project = manager.resume_project(project_id)
        except ValueError as e:
            return CommandResult(False, str(e))

        # Get project agents
        agents = manager.get_project_agents(project_id)

        # Format summary
        summary = manager.format_project_summary(project)

        return CommandResult(
            True,
            f"Project Resumed\n\n{summary}",
            data={
                "project_id": project.id,
                "name": project.name,
                "domain": project.domain.value,
                "status": project.status,
                "agents": [{"template": a.template_id, "role": a.role, "status": a.status} for a in agents],
                "context": project.context,
            },
            suggestions=[
                f"Project '{project.name}' is now active",
                "/project status for current status",
                "/assign <agent> <task> to assign work",
            ]
        )

    async def _project_status(self) -> CommandResult:
        """Show current project status."""
        manager = self._get_project_manager()
        project = manager.current_project

        if not project:
            return CommandResult(
                True,
                "No active project",
                suggestions=[
                    "/project list to see available projects",
                    "/project new <task> to start a new project",
                ]
            )

        # Get agents
        agents = manager.get_project_agents(project.id)

        # Get recent history
        history = manager.get_history(project.id, limit=5)

        return CommandResult(
            True,
            manager.format_project_summary(project),
            data={
                "project": {
                    "id": project.id,
                    "name": project.name,
                    "domain": project.domain.value,
                    "status": project.status,
                    "progress": f"{project.completed_tasks}/{project.total_tasks}",
                    "progress_pct": project.progress_percentage,
                },
                "agents": [{"template": a.template_id, "role": a.role, "status": a.status} for a in agents],
                "recent_history": history[:5],
            }
        )

    async def _project_archive(self, project_id: str) -> CommandResult:
        """Archive a completed project."""
        if not project_id:
            return CommandResult(
                False,
                "Usage: /project archive <project-id>",
                suggestions=["/project list to see available projects"]
            )

        manager = self._get_project_manager()
        project = manager.get_project(project_id)

        if not project:
            return CommandResult(False, f"Project '{project_id}' not found")

        manager.archive_project(project_id)

        return CommandResult(
            True,
            f"Project '{project.name}' archived",
            data={"project_id": project_id, "name": project.name}
        )

    # =========================================================================
    # Agent Template Commands
    # =========================================================================

    async def _cmd_agent(self, args: str) -> CommandResult:
        """
        /agent <subcommand> [args]
        Agent template management commands.

        Subcommands:
            list            - List available agent templates
            info <id>       - Show agent template details
            create          - Create a custom agent template (wizard)
            export <id>     - Export template to YAML
            import <file>   - Import template from YAML
        """
        if not PROJECT_FEATURES_AVAILABLE:
            return CommandResult(
                False,
                "Agent features not available. Check module imports.",
            )

        parts = args.split(maxsplit=1)
        if not parts:
            return CommandResult(
                False,
                "Usage: /agent <list|info|create|export|import> [args]",
                suggestions=[
                    "/agent list",
                    "/agent info story-writer",
                    "/agent create",
                ]
            )

        subcommand = parts[0].lower()
        sub_args = parts[1] if len(parts) > 1 else ""

        if subcommand == "list":
            return await self._agent_list()
        elif subcommand == "info":
            return await self._agent_info(sub_args)
        elif subcommand == "create":
            return await self._agent_create()
        elif subcommand == "export":
            return await self._agent_export(sub_args)
        elif subcommand == "import":
            return await self._agent_import(sub_args)
        else:
            return CommandResult(
                False,
                f"Unknown agent subcommand: {subcommand}",
                suggestions=["Use: list, info, create, export, import"]
            )

    async def _agent_list(self) -> CommandResult:
        """List available agent templates."""
        templates = list_templates()

        # Group by domain
        by_domain: Dict[str, List[Any]] = {}
        for template in templates:
            domain = template.domain.value.replace("_", " ").title()
            if domain not in by_domain:
                by_domain[domain] = []
            by_domain[domain].append(template)

        # Format output
        lines = ["Available Agent Templates:", ""]
        for domain, domain_templates in by_domain.items():
            lines.append(f"  {domain}:")
            for t in domain_templates:
                lines.append(f"    • {t.id}: {t.description[:50]}...")
            lines.append("")

        return CommandResult(
            True,
            "\n".join(lines),
            data={
                "templates": [
                    {"id": t.id, "name": t.name, "domain": t.domain.value}
                    for t in templates
                ],
                "count": len(templates),
            },
            suggestions=["/agent info <id> for details", "/spawn <id> to create an agent"]
        )

    async def _agent_info(self, template_id: str) -> CommandResult:
        """Show agent template details."""
        if not template_id:
            return CommandResult(
                False,
                "Usage: /agent info <template-id>",
                suggestions=["/agent list to see available templates"]
            )

        template = get_template(template_id)
        if not template:
            return CommandResult(
                False,
                f"Template '{template_id}' not found",
                suggestions=["/agent list to see available templates"]
            )

        developer = self._get_agent_developer()
        info_text = developer.format_template_info(template)

        return CommandResult(
            True,
            info_text,
            data=template.to_dict(),
            suggestions=[f"/spawn {template_id} to create this agent"]
        )

    async def _agent_create(self) -> CommandResult:
        """Start agent creation wizard."""
        return CommandResult(
            True,
            "Agent Creation Wizard\n\n"
            "To create a custom agent template, provide the following:\n\n"
            "1. Template ID (e.g., my-specialist)\n"
            "2. Display name\n"
            "3. Domain (creative_writing, technical_coding, research, etc.)\n"
            "4. Description\n"
            "5. Capabilities (comma-separated)\n\n"
            "Example command:\n"
            "/agent create-custom my-analyst \"My Data Analyst\" data_analysis "
            "\"Custom data analysis agent\" \"data exploration, visualization, reporting\"",
            data={"status": "wizard_info"},
            suggestions=[
                "Use /agent list to see domain examples",
                "Templates are saved to ~/.orchestrator/templates/",
            ]
        )

    async def _agent_export(self, template_id: str) -> CommandResult:
        """Export a template to YAML."""
        if not template_id:
            return CommandResult(
                False,
                "Usage: /agent export <template-id>",
            )

        template = get_template(template_id)
        if not template:
            return CommandResult(False, f"Template '{template_id}' not found")

        developer = self._get_agent_developer()
        file_path = developer.export_template(template)

        return CommandResult(
            True,
            f"Template exported to: {file_path}",
            data={"template_id": template_id, "file_path": str(file_path)}
        )

    async def _agent_import(self, file_path: str) -> CommandResult:
        """Import a template from YAML."""
        if not file_path:
            return CommandResult(
                False,
                "Usage: /agent import <file-path>",
            )

        from pathlib import Path
        path = Path(file_path)

        if not path.exists():
            return CommandResult(False, f"File not found: {file_path}")

        developer = self._get_agent_developer()

        try:
            template = developer.import_template(path)
            developer.register_template(template)

            return CommandResult(
                True,
                f"Template '{template.id}' imported and registered",
                data={"template_id": template.id, "name": template.name}
            )
        except Exception as e:
            return CommandResult(False, f"Import failed: {e}")

    # =========================================================================
    # Task Management Commands
    # =========================================================================

    async def _cmd_assign(self, args: str) -> CommandResult:
        """
        /assign <agent-id> <task description>
        Assign a task to a specific agent.
        """
        parts = args.split(maxsplit=1)
        if len(parts) < 2:
            return CommandResult(
                False,
                "Usage: /assign <agent-id> <task description>",
                suggestions=["Example: /assign claude-code Refactor the auth module"]
            )

        agent_id, description = parts

        # Check agent exists and is available
        if agent_id not in self.adapters:
            available = list(self.adapters.keys())
            return CommandResult(
                False,
                f"Agent '{agent_id}' not registered",
                data={"available_agents": available},
                suggestions=[f"Available agents: {', '.join(available)}"]
            )

        # Check availability via CLI tracker
        availability = self.cli_tracker.get_availability(agent_id)
        if availability in (AgentAvailability.EXHAUSTED, AgentAvailability.UNAVAILABLE):
            # Find alternative
            alternative = self.cli_tracker.get_best_available_agent(
                list(self.adapters.keys())
            )
            return CommandResult(
                False,
                f"Agent '{agent_id}' is {availability.value}",
                data={"suggested_alternative": alternative},
                suggestions=[f"Try: /assign {alternative} {description}" if alternative else "No alternatives available"]
            )

        # Create task
        import uuid
        task_id = f"task-{uuid.uuid4().hex[:8]}"
        task = Task(
            id=task_id,
            description=description,
            task_type="assigned",
            status="pending",
            assigned_agent_id=agent_id,
        )

        self.db.create_task(task)

        # Record usage
        self.cli_tracker.record_request(
            agent_id=agent_id,
            success=True,
            input_tokens=0,  # Will be updated when task completes
        )

        return CommandResult(
            True,
            f"Task {task_id} assigned to {agent_id}",
            data={
                "task_id": task_id,
                "agent_id": agent_id,
                "description": description,
                "agent_availability": availability.value,
            }
        )

    async def _cmd_cancel(self, args: str) -> CommandResult:
        """
        /cancel <task-id>
        Cancel a running or pending task.
        """
        if not args:
            return CommandResult(
                False,
                "Usage: /cancel <task-id>",
                suggestions=["/progress to see running tasks"]
            )

        task_id = args.strip()
        task = self.db.get_task(task_id)

        if not task:
            return CommandResult(False, f"Task '{task_id}' not found")

        if task.status in ("completed", "failed"):
            return CommandResult(
                False,
                f"Task '{task_id}' already {task.status}",
            )

        # Cancel the task
        agent_id = task.assigned_agent_id
        self.db.update_task_status(task_id, "failed", error_message="Cancelled by user")

        # If assigned to an agent, cancel the adapter
        if agent_id and agent_id in self.adapters:
            adapter = self.adapters[agent_id]
            if hasattr(adapter, 'cancel'):
                try:
                    await adapter.cancel()
                except Exception as e:
                    logger.warning(f"Failed to cancel adapter: {e}")

        return CommandResult(
            True,
            f"Task {task_id} cancelled",
            data={
                "task_id": task_id,
                "previous_status": task.status,
                "agent": agent_id or "none",
            }
        )

    async def _cmd_broadcast(self, args: str) -> CommandResult:
        """
        /broadcast <message>
        Send information to all agents.
        """
        if not args:
            return CommandResult(False, "Usage: /broadcast <message>")

        # In practice, this would be added to shared context or memory
        self.operational_memory.record_decision(
            decision=f"Broadcast: {args}",
            rationale="Orchestrator broadcast to all agents",
        )

        return CommandResult(
            True,
            f"Broadcast sent to {len(self.adapters)} agents",
            data={
                "message": args,
                "recipients": list(self.adapters.keys()),
                "timestamp": datetime.now().isoformat(),
            }
        )

    async def _cmd_priority(self, args: str) -> CommandResult:
        """
        /priority <task-id> <high|medium|low>
        Set task priority.
        """
        parts = args.split()
        if len(parts) < 2:
            return CommandResult(False, "Usage: /priority <task-id> <high|medium|low>")

        task_id, priority = parts[0], parts[1].lower()

        if priority not in ("high", "medium", "low"):
            return CommandResult(False, "Priority must be: high, medium, or low")

        # Update task priority (would need to add priority field to Task model)
        # For now, record in operational memory
        self.operational_memory.record_decision(
            decision=f"Task {task_id} priority set to {priority}",
            rationale="Orchestrator priority adjustment",
        )

        return CommandResult(
            True,
            f"Task {task_id} priority set to {priority}",
            data={"task_id": task_id, "priority": priority}
        )

    # =========================================================================
    # Monitoring Commands
    # =========================================================================

    async def _cmd_status(self, args: str) -> CommandResult:
        """
        /status [agent-id]
        Show system or specific agent status.
        """
        if args:
            # Specific agent status
            agent_id = args.strip()
            if agent_id not in self.adapters:
                return CommandResult(False, f"Agent '{agent_id}' not found")

            usage = self.cli_tracker.get_usage_stats(agent_id)
            availability = self.cli_tracker.get_availability(agent_id)

            # Get active tasks for this agent
            tasks = self.operational_memory.get_task_history(
                agent_id=agent_id,
                status="in_progress",
                limit=5
            )

            return CommandResult(
                True,
                f"Status for {agent_id}",
                data={
                    "agent_id": agent_id,
                    "availability": availability.value,
                    "usage": usage,
                    "active_tasks": len(tasks),
                    "tasks": [{"id": t.id, "description": t.description[:50]} for t in tasks],
                }
            )

        # System-wide status
        agents_status = []
        for agent_id in self.adapters:
            availability = self.cli_tracker.get_availability(agent_id)
            usage = self.cli_tracker.get_usage_stats(agent_id)
            agents_status.append({
                "agent_id": agent_id,
                "availability": availability.value,
                "session_percentage": usage.get("session_percentage", 0),
            })

        project_state = self.operational_memory.read_project_state()
        pending_tasks = len(self.db.get_pending_tasks(limit=100))

        return CommandResult(
            True,
            "System Status",
            data={
                "project": project_state.get("project", {}).get("name", "Unknown"),
                "phase": project_state.get("current_phase", "Unknown"),
                "agents": agents_status,
                "pending_tasks": pending_tasks,
                "timestamp": datetime.now().isoformat(),
            }
        )

    async def _cmd_progress(self, args: str) -> CommandResult:
        """
        /progress [task-id]
        Show progress of running tasks.

        Without arguments: Shows all running tasks
        With task-id: Shows detailed progress for that task
        """
        # Get running tasks from database
        all_tasks = self.db.get_pending_tasks(limit=100)
        running_tasks = [t for t in all_tasks if t.status in ("running", "in_progress", "assigned")]

        if args:
            # Specific task progress
            task_id = args.strip()
            task = self.db.get_task(task_id)

            if not task:
                return CommandResult(False, f"Task '{task_id}' not found")

            # Calculate duration if running
            duration = None
            if task.started_at:
                duration = (datetime.now() - task.started_at).total_seconds()

            # Get agent info
            agent_status = None
            if task.assigned_agent_id:
                adapter = self.adapters.get(task.assigned_agent_id)
                if adapter:
                    agent_status = adapter.status.value if hasattr(adapter, 'status') else "unknown"

            return CommandResult(
                True,
                f"Task Progress: {task_id}",
                data={
                    "task_id": task_id,
                    "description": task.description[:100],
                    "status": task.status,
                    "assigned_to": task.assigned_agent_id or "unassigned",
                    "agent_status": agent_status,
                    "started_at": task.started_at.isoformat() if task.started_at else None,
                    "duration_seconds": round(duration) if duration else None,
                    "error": task.error_message,
                }
            )

        # All running tasks
        if not running_tasks:
            return CommandResult(
                True,
                "No tasks currently running",
                data={"running_tasks": 0},
                suggestions=["Use /assign to start a task"]
            )

        tasks_data = []
        for task in running_tasks:
            duration = None
            if task.started_at:
                duration = (datetime.now() - task.started_at).total_seconds()

            tasks_data.append({
                "task_id": task.id,
                "description": task.description[:60] + "..." if len(task.description) > 60 else task.description,
                "status": task.status,
                "agent": task.assigned_agent_id or "unassigned",
                "duration": f"{int(duration)}s" if duration else "pending",
            })

        return CommandResult(
            True,
            f"Running Tasks ({len(running_tasks)})",
            data={
                "running_tasks": len(running_tasks),
                "tasks": tasks_data,
            },
            suggestions=[
                "/progress <task-id> for details",
                "/view <agent-id> to see agent output",
            ]
        )

    async def _cmd_usage(self, args: str) -> CommandResult:
        """
        /usage
        Show token/session usage for all agents.
        """
        usage_data = {}
        for agent_id in self.adapters:
            usage_data[agent_id] = self.cli_tracker.get_usage_stats(agent_id)

        return CommandResult(
            True,
            "Agent Usage Statistics",
            data=usage_data
        )

    async def _cmd_health(self, args: str) -> CommandResult:
        """
        /health
        Check agent health and availability.
        """
        health_data = {}
        warnings = []

        for agent_id in self.adapters:
            availability = self.cli_tracker.get_availability(agent_id)
            usage = self.cli_tracker.get_usage_stats(agent_id)

            is_healthy = availability not in (
                AgentAvailability.EXHAUSTED,
                AgentAvailability.UNAVAILABLE
            )

            health_data[agent_id] = {
                "healthy": is_healthy,
                "availability": availability.value,
                "session_percentage": usage.get("session_percentage", 0),
                "error_rate": usage.get("error_rate", 0),
            }

            # Generate warnings
            if usage.get("session_percentage", 0) > 80:
                warnings.append(f"{agent_id}: Approaching session limit ({usage['session_percentage']:.0f}%)")
            if usage.get("error_rate", 0) > 0.1:
                warnings.append(f"{agent_id}: High error rate ({usage['error_rate']:.0%})")

        return CommandResult(
            True,
            "Agent Health Check",
            data={
                "agents": health_data,
                "warnings": warnings,
                "overall_healthy": all(h["healthy"] for h in health_data.values()),
            }
        )

    # =========================================================================
    # Memory & Context Commands
    # =========================================================================

    async def _cmd_memory(self, args: str) -> CommandResult:
        """
        /memory <search|add> <query|type content>
        Search or add to project memory.
        """
        parts = args.split(maxsplit=1)
        if not parts:
            return CommandResult(False, "Usage: /memory <search|add> <args>")

        action = parts[0].lower()
        rest = parts[1] if len(parts) > 1 else ""

        if action == "search":
            if not rest:
                return CommandResult(False, "Usage: /memory search <query>")

            # Search in operational memory (simplified)
            state = self.operational_memory.read_project_state()
            decisions = state.get("decisions", [])

            matches = [
                d for d in decisions
                if rest.lower() in d.get("decision", "").lower()
            ]

            return CommandResult(
                True,
                f"Found {len(matches)} matching items",
                data={"query": rest, "results": matches[:10]}
            )

        elif action == "add":
            parts = rest.split(maxsplit=1)
            if len(parts) < 2:
                return CommandResult(False, "Usage: /memory add <type> <content>")

            mem_type, content = parts
            self.operational_memory.record_decision(
                decision=content,
                rationale=f"Added via /memory add ({mem_type})",
            )

            return CommandResult(
                True,
                f"Added {mem_type} to memory",
                data={"type": mem_type, "content": content}
            )

        return CommandResult(False, "Unknown memory action. Use: search, add")

    async def _cmd_decisions(self, args: str) -> CommandResult:
        """
        /decisions
        Show recent architectural decisions.
        """
        decisions = self.operational_memory.get_active_decisions()

        return CommandResult(
            True,
            f"Recent Decisions ({len(decisions)})",
            data={"decisions": decisions}
        )

    async def _cmd_context(self, args: str) -> CommandResult:
        """
        /context <task-id>
        Get full context for a task.
        """
        if not args:
            return CommandResult(False, "Usage: /context <task-id>")

        task_id = args.strip()

        # Get task from database
        tasks = self.db.get_pending_tasks(limit=100)
        task = next((t for t in tasks if t.id == task_id), None)

        if not task:
            # Check completed tasks
            task = next(
                (t for t in self.db.get_recent_tasks(limit=50) if t.id == task_id),
                None
            )

        if not task:
            return CommandResult(False, f"Task '{task_id}' not found")

        # Build context
        context = self.operational_memory.build_context_for_agent(
            agent_id=task.assigned_to or "unknown",
            task_type=task.task_type,
        )

        return CommandResult(
            True,
            f"Context for {task_id}",
            data={
                "task": {
                    "id": task.id,
                    "description": task.description,
                    "type": task.task_type,
                    "status": task.status,
                    "assigned_to": task.assigned_to,
                },
                "context": context,
            }
        )

    # =========================================================================
    # Agent Management Commands
    # =========================================================================

    async def _cmd_spawn(self, args: str) -> CommandResult:
        """
        /spawn <type> [config]
        Create a new specialized agent using templates.
        """
        parts = args.split(maxsplit=1)
        if not parts:
            # Show available types from templates
            suggestions = ["Usage: /spawn <type> [context]"]
            if PROJECT_FEATURES_AVAILABLE:
                templates = list_templates()
                by_domain = {}
                for t in templates:
                    domain = t.domain.value.replace("_", " ").title()
                    if domain not in by_domain:
                        by_domain[domain] = []
                    by_domain[domain].append(t.id)

                for domain, types in list(by_domain.items())[:3]:
                    suggestions.append(f"{domain}: {', '.join(types[:3])}")
                suggestions.append("Use /agent list for full catalog")

            return CommandResult(
                False,
                "Usage: /spawn <type> [context]",
                suggestions=suggestions
            )

        agent_type = parts[0].lower()
        task_context = parts[1] if len(parts) > 1 else ""

        # Try to get template for rich agent definition
        template = None
        template_name = agent_type
        if PROJECT_FEATURES_AVAILABLE:
            template = get_template(agent_type)
            if template:
                template_name = template.name

        # Generate agent ID
        import uuid
        agent_id = f"{agent_type}-{uuid.uuid4().hex[:4]}"

        # Build prompt from template or use legacy
        if template:
            # Build rich prompt from template
            prompt_parts = [template.system_prompt]
            if template.capabilities:
                cap_list = ", ".join(c.name for c in template.capabilities)
                prompt_parts.append(f"\n\nYour capabilities: {cap_list}")
            if template.suggested_tools:
                tools_list = ", ".join(template.suggested_tools)
                prompt_parts.append(f"\nSuggested tools: {tools_list}")
            prompt_parts.append(f"\nCollaboration style: {template.collaboration_style.value}")
            if task_context:
                prompt_parts.append(f"\n\n## Current Task Context\n{task_context}")
            prompt = "\n".join(prompt_parts)
        else:
            # Legacy prompt
            from ..prompts.orchestrator_system import get_specialized_prompt
            prompt = get_specialized_prompt(agent_type, task_context)

        # Record spawned agent with rich metadata
        self.spawned_agents[agent_id] = {
            "type": agent_type,
            "template_name": template_name,
            "domain": template.domain.value if template else "unknown",
            "context": task_context,
            "prompt": prompt[:200] + "..." if len(prompt) > 200 else prompt,
            "spawned_at": datetime.now().isoformat(),
            "status": "initializing",
        }

        return CommandResult(
            True,
            f"Spawned agent: {agent_id} ({template_name})",
            data={
                "agent_id": agent_id,
                "type": agent_type,
                "template_name": template_name,
                "domain": template.domain.value if template else "unknown",
                "context": task_context,
                "status": "initializing",
            },
            suggestions=[
                f"Use /assign {agent_id} <task> to assign work",
                f"Use /status {agent_id} to check status",
                f"Use /view {agent_id} to see agent output"
            ]
        )

    async def _cmd_pause(self, args: str) -> CommandResult:
        """
        /pause <agent-id>
        Pause an agent.
        """
        if not args:
            return CommandResult(False, "Usage: /pause <agent-id>")

        agent_id = args.strip()

        if agent_id not in self.adapters and agent_id not in self.spawned_agents:
            return CommandResult(False, f"Agent '{agent_id}' not found")

        # Mark as paused in tracker
        self.cli_tracker.set_availability(agent_id, AgentAvailability.PAUSED)

        return CommandResult(
            True,
            f"Agent {agent_id} paused",
            data={"agent_id": agent_id, "status": "paused"}
        )

    async def _cmd_resume(self, args: str) -> CommandResult:
        """
        /resume <agent-id>
        Resume a paused agent.
        """
        if not args:
            return CommandResult(False, "Usage: /resume <agent-id>")

        agent_id = args.strip()

        if agent_id not in self.adapters and agent_id not in self.spawned_agents:
            return CommandResult(False, f"Agent '{agent_id}' not found")

        # Clear paused status
        self.cli_tracker.set_availability(agent_id, AgentAvailability.AVAILABLE)

        return CommandResult(
            True,
            f"Agent {agent_id} resumed",
            data={"agent_id": agent_id, "status": "available"}
        )

    async def _cmd_reassign(self, args: str) -> CommandResult:
        """
        /reassign <task-id> <new-agent-id>
        Move task to a different agent.
        """
        parts = args.split()
        if len(parts) < 2:
            return CommandResult(False, "Usage: /reassign <task-id> <new-agent-id>")

        task_id, new_agent_id = parts[0], parts[1]

        if new_agent_id not in self.adapters:
            return CommandResult(False, f"Agent '{new_agent_id}' not registered")

        # Check new agent availability
        availability = self.cli_tracker.get_availability(new_agent_id)
        if availability in (AgentAvailability.EXHAUSTED, AgentAvailability.UNAVAILABLE):
            return CommandResult(
                False,
                f"Agent '{new_agent_id}' is {availability.value}",
                suggestions=[f"Check /health for available agents"]
            )

        # Update task assignment (would need DB method)
        self.operational_memory.record_decision(
            decision=f"Task {task_id} reassigned to {new_agent_id}",
            rationale="Orchestrator reassignment",
        )

        return CommandResult(
            True,
            f"Task {task_id} reassigned to {new_agent_id}",
            data={
                "task_id": task_id,
                "new_agent_id": new_agent_id,
                "agent_availability": availability.value,
            }
        )

    async def _cmd_view(self, args: str) -> CommandResult:
        """
        /view <agent-id> [--attach | --lines N]
        View an agent's console session.

        Options:
            --attach    Attach to the tmux session (use Ctrl+B, D to detach)
            --lines N   Show last N lines of output (default: 50)

        Examples:
            /view claude-code           Show last 50 lines
            /view claude-code --lines 100  Show last 100 lines
            /view claude-code --attach  Attach to live session
        """
        if not args:
            return CommandResult(
                False,
                "Usage: /view <agent-id> [--attach | --lines N]",
                suggestions=[
                    "/view claude-code - Show recent output",
                    "/view claude-code --attach - Attach to live session",
                ]
            )

        # Parse arguments
        parts = args.split()
        agent_id = parts[0]
        attach_mode = "--attach" in parts
        lines = 50  # default

        # Parse --lines N
        for i, part in enumerate(parts):
            if part == "--lines" and i + 1 < len(parts):
                try:
                    lines = int(parts[i + 1])
                except ValueError:
                    pass

        # Validate agent exists
        if agent_id not in self.adapters and agent_id not in self.spawned_agents:
            available = list(self.adapters.keys())
            return CommandResult(
                False,
                f"Agent '{agent_id}' not found",
                suggestions=[f"Available agents: {', '.join(available)}"]
            )

        # Get or create workspace manager
        if self._workspace_manager is None:
            from pathlib import Path
            from ..workspace.manager import DIYAgentWorkspace
            self._workspace_manager = DIYAgentWorkspace(Path.cwd())

        # Check if tmux session exists
        if not self._workspace_manager.is_session_active(agent_id):
            # No active session - try to show adapter info instead
            adapter = self.adapters.get(agent_id)
            if adapter:
                return CommandResult(
                    True,
                    f"Agent '{agent_id}' has no active tmux session",
                    data={
                        "agent_id": agent_id,
                        "adapter_type": adapter.get_name() if hasattr(adapter, 'get_name') else "unknown",
                        "status": self.cli_tracker.get_availability(agent_id).value,
                        "note": "Use /spawn to create an isolated workspace with tmux session",
                    }
                )
            return CommandResult(
                False,
                f"No active session for '{agent_id}'",
                suggestions=["Use /spawn to create an agent with tmux session"]
            )

        if attach_mode:
            # Attach to tmux session
            return CommandResult(
                True,
                f"Attaching to {agent_id}... (Ctrl+B, D to detach)",
                data={
                    "agent_id": agent_id,
                    "action": "attach",
                    "tmux_session": agent_id,
                    "detach_hint": "Press Ctrl+B then D to return to orchestrator",
                }
            )
        else:
            # Capture and display output
            try:
                output = self._workspace_manager.capture_output(agent_id, lines=lines)
                return CommandResult(
                    True,
                    f"Last {lines} lines from {agent_id}:",
                    data={
                        "agent_id": agent_id,
                        "lines": lines,
                        "output": output,
                        "tip": "Use --attach to interact directly",
                    }
                )
            except Exception as e:
                return CommandResult(
                    False,
                    f"Failed to capture output: {e}",
                    suggestions=["Try /view {agent_id} --attach"]
                )

    # =========================================================================
    # System Commands
    # =========================================================================

    async def _cmd_save(self, args: str) -> CommandResult:
        """
        /save
        Save current system state.
        """
        # Force write current state
        state = self.operational_memory.read_project_state()
        state["last_saved"] = datetime.now().isoformat()
        self.operational_memory.write_project_state(state)

        return CommandResult(
            True,
            "State saved",
            data={"timestamp": state["last_saved"]}
        )

    async def _cmd_report(self, args: str) -> CommandResult:
        """
        /report
        Generate a status report.
        """
        # Gather all information
        state = self.operational_memory.read_project_state()

        agents_info = []
        for agent_id in self.adapters:
            usage = self.cli_tracker.get_usage_stats(agent_id)
            availability = self.cli_tracker.get_availability(agent_id)
            agents_info.append({
                "id": agent_id,
                "availability": availability.value,
                "usage_pct": usage.get("session_percentage", 0),
                "requests": usage.get("total_requests", 0),
                "errors": usage.get("error_count", 0),
            })

        pending_tasks = self.db.get_pending_tasks(limit=100)
        decisions = self.operational_memory.get_active_decisions()

        report = {
            "generated_at": datetime.now().isoformat(),
            "project": {
                "name": state.get("project", {}).get("name", "Unknown"),
                "phase": state.get("current_phase", "Unknown"),
                "version": state.get("version", "0.0.0"),
            },
            "agents": {
                "total": len(self.adapters),
                "details": agents_info,
            },
            "tasks": {
                "pending": len([t for t in pending_tasks if t.status == "pending"]),
                "in_progress": len([t for t in pending_tasks if t.status == "in_progress"]),
            },
            "recent_decisions": len(decisions),
        }

        return CommandResult(
            True,
            "Status Report Generated",
            data=report
        )

    async def _cmd_help(self, args: str) -> CommandResult:
        """
        /help
        Show all available commands.
        """
        help_text = """
## Project Management
- `/project new <task>` - Plan and create a new project
- `/project list` - List recent projects
- `/project resume <id>` - Resume a previous project
- `/project status` - Show current project status
- `/project archive <id>` - Archive a completed project

## Agent Templates
- `/agent list` - List available agent templates by domain
- `/agent info <id>` - Show agent template details
- `/agent create` - Create a custom agent template
- `/agent export <id>` - Export template to YAML
- `/agent import <file>` - Import template from YAML

## Task Management
- `/assign <agent-id> <task>` - Assign task to specific agent
- `/cancel <task-id>` - Cancel a running task
- `/broadcast <message>` - Send info to all agents
- `/priority <task-id> <high|medium|low>` - Set task priority

## Monitoring
- `/status [agent-id]` - Show system or agent status
- `/progress [task-id]` - Show running task progress
- `/usage` - Show token/session usage for all agents
- `/health` - Check agent health and availability

## Memory & Context
- `/memory search <query>` - Search project memory
- `/memory add <type> <content>` - Add to project memory
- `/decisions` - Show recent architectural decisions
- `/context <task-id>` - Get full context for a task

## Agent Management
- `/spawn <type> [context]` - Create specialized agent from template
- `/pause <agent-id>` - Pause an agent
- `/resume <agent-id>` - Resume a paused agent
- `/reassign <task-id> <new-agent>` - Move task to different agent
- `/view <agent-id>` - View agent console output

## System
- `/save` - Save current state
- `/report` - Generate status report
- `/help` - Show this help

## Quick Start
1. Enter a task to get intelligent agent suggestions
2. Use `/project new <task>` for complex multi-step projects
3. Use `/agent list` to explore available specialist templates
"""

        return CommandResult(
            True,
            help_text,
            data={"commands": list(self._commands.keys())}
        )
