"""
Command router for mapping /gsd-rlm-* commands to orchestrator entry points.

This module provides the CommandRouter class that dispatches commands to
appropriate handlers, and convenience functions for one-shot routing.

Requirements: INT-04 (command routing), INT-05 (handler mapping)
"""

from __future__ import annotations

import logging
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Callable, Optional

from pydantic import BaseModel, Field

logger = logging.getLogger(__name__)


class CommandConfig(BaseModel):
    """Configuration for command execution.

    Attributes:
        command: Command name (e.g., "new-project", "plan-phase")
        args: Command arguments as keyword arguments
        project_dir: Project directory path
        config: Additional configuration options
    """

    model_config = {"extra": "forbid"}

    command: str = Field(..., min_length=1, description="Command name")
    args: dict[str, Any] = Field(default_factory=dict, description="Command arguments")
    project_dir: Path = Field(..., description="Project directory")
    config: dict[str, Any] = Field(default_factory=dict, description="Configuration")


@dataclass
class CommandResult:
    """Result of command execution.

    Attributes:
        success: Whether the command completed successfully
        message: Human-readable result message
        data: Optional data returned by the command
        error: Error message if command failed
    """

    success: bool
    message: str
    data: dict[str, Any] | None = None
    error: str | None = None


class CommandRouter:
    """Router for dispatching commands to handlers.

    Maps command names to handler functions and provides routing
    functionality. Handlers can be registered dynamically.

    Example:
        ```python
        from gsd_rlm.commands.router import CommandRouter, CommandConfig

        async def handle_new_project(config: CommandConfig) -> CommandResult:
            # Create project structure
            return CommandResult(success=True, message="Project created")

        router = CommandRouter()
        router.register("new-project", handle_new_project)

        config = CommandConfig(
            command="new-project",
            args={},
            project_dir=Path("."),
            config={}
        )
        result = await router.route(config)
        ```

    Attributes:
        handlers: Dictionary mapping command names to handler functions
    """

    def __init__(self, skills_registry: Any = None):
        """Initialize the command router.

        Args:
            skills_registry: Optional SkillRegistry for skill-based handlers
        """
        self.handlers: dict[str, Callable] = {}
        self._skills_registry = skills_registry

    def register(self, command: str, handler: Callable) -> None:
        """Register a handler for a command.

        Args:
            command: Command name (e.g., "new-project")
            handler: Async function that handles the command

        Example:
            >>> router.register("new-project", new_project_command)
        """
        self.handlers[command] = handler
        logger.debug(f"Registered handler for command: {command}")

    def unregister(self, command: str) -> bool:
        """Unregister a command handler.

        Args:
            command: Command name to unregister

        Returns:
            True if handler was removed, False if not found
        """
        if command in self.handlers:
            del self.handlers[command]
            logger.debug(f"Unregistered handler for command: {command}")
            return True
        return False

    async def route(self, config: CommandConfig) -> CommandResult:
        """Route a command to its handler.

        Looks up the handler for the command and executes it with
        the provided configuration.

        Args:
            config: Command configuration with args and project directory

        Returns:
            CommandResult from the handler execution

        Raises:
            KeyError: If no handler is registered for the command
        """
        command = config.command

        if command not in self.handlers:
            logger.error(f"No handler registered for command: {command}")
            return CommandResult(
                success=False,
                message=f"Unknown command: {command}",
                error=f"No handler registered for '{command}'",
            )

        handler = self.handlers[command]
        logger.info(f"Routing command: {command}")

        try:
            result = await handler(config)
            logger.info(f"Command {command} completed: success={result.success}")
            return result
        except Exception as e:
            logger.exception(f"Command {command} failed: {e}")
            return CommandResult(
                success=False,
                message=f"Command failed: {e}",
                error=str(e),
            )

    def list_commands(self) -> list[str]:
        """List all registered commands.

        Returns:
            List of command names that have registered handlers
        """
        return list(self.handlers.keys())

    def has_handler(self, command: str) -> bool:
        """Check if a handler is registered for a command.

        Args:
            command: Command name to check

        Returns:
            True if handler exists, False otherwise
        """
        return command in self.handlers


async def route_command(
    command: str,
    args: dict[str, Any],
    project_dir: Path,
    config: dict[str, Any] | None = None,
    skills_registry: Any = None,
) -> CommandResult:
    """Convenience function for one-shot command routing.

    Creates a router, registers default handlers, and routes the command.
    This is useful for simple use cases where you don't need to manage
    the router lifecycle.

    Args:
        command: Command name to execute
        args: Command arguments
        project_dir: Project directory path
        config: Optional configuration dictionary
        skills_registry: Optional SkillRegistry for skill-based handlers

    Returns:
        CommandResult from the command execution

    Example:
        ```python
        from pathlib import Path
        from gsd_rlm.commands.router import route_command

        result = await route_command(
            command="new-project",
            args={"name": "my-project"},
            project_dir=Path("."),
        )
        print(f"Success: {result.success}")
        ```
    """
    from gsd_rlm.commands.handlers import register_default_handlers

    router = CommandRouter(skills_registry=skills_registry)
    register_default_handlers(router)

    cmd_config = CommandConfig(
        command=command,
        args=args,
        project_dir=project_dir,
        config=config or {},
    )

    return await router.route(cmd_config)


def create_router_with_defaults(skills_registry: Any = None) -> CommandRouter:
    """Create a router with default handlers pre-registered.

    Args:
        skills_registry: Optional SkillRegistry for skill-based handlers

    Returns:
        CommandRouter with default handlers registered

    Example:
        ```python
        from gsd_rlm.commands.router import create_router_with_defaults

        router = create_router_with_defaults()
        print(router.list_commands())  # ['new-project', 'plan-phase', 'execute-phase']
        ```
    """
    from gsd_rlm.commands.handlers import register_default_handlers

    router = CommandRouter(skills_registry=skills_registry)
    register_default_handlers(router)
    return router
