"""Content loading from TOML files."""

import importlib
import logging
import tomllib
from pathlib import Path
from typing import cast

from mudlib.commands import CommandDefinition, CommandHandler
from mudlib.player import Player

log = logging.getLogger(__name__)


def _resolve_handler(handler_ref: str) -> CommandHandler:
    """Resolve a handler reference string to a callable.

    Args:
        handler_ref: String in format "module.path:function_name"

    Returns:
        The resolved callable

    Raises:
        ImportError: If the module cannot be imported
        AttributeError: If the function doesn't exist in the module
    """
    if ":" not in handler_ref:
        msg = (
            f"Handler reference must be in format 'module:function', got: {handler_ref}"
        )
        raise ValueError(msg)

    module_path, func_name = handler_ref.split(":", 1)
    module = importlib.import_module(module_path)
    handler = getattr(module, func_name)

    if not callable(handler):
        msg = f"Handler reference {handler_ref} is not callable"
        raise TypeError(msg)

    return cast(CommandHandler, handler)


def _make_message_handler(message: str) -> CommandHandler:
    """Create a handler that sends a fixed message to the player.

    Args:
        message: The message text to send

    Returns:
        An async handler function
    """

    async def handler(player: Player, args: str) -> None:
        player.writer.write(message.strip() + "\r\n")
        await player.writer.drain()

    return handler


def load_command(path: Path) -> CommandDefinition:
    """Load a command definition from a TOML file.

    Args:
        path: Path to the .toml file

    Returns:
        CommandDefinition instance

    Raises:
        KeyError: If required fields are missing
        ValueError: If neither handler nor message is specified
        TypeError: If handler or message fields have wrong types
        ImportError: If handler reference cannot be resolved
    """
    with open(path, "rb") as f:
        data = tomllib.load(f)

    name = data["name"]

    # Determine the handler
    handler_ref = data.get("handler")
    message = data.get("message")

    if handler_ref and message:
        msg = "Command definition cannot specify both 'handler' and 'message'"
        raise ValueError(msg)

    if not handler_ref and not message:
        msg = "Command definition must specify either 'handler' or 'message'"
        raise ValueError(msg)

    # Validate types
    if handler_ref and not isinstance(handler_ref, str):
        msg = f"'handler' must be a string in {path}"
        raise TypeError(msg)

    if message and not isinstance(message, str):
        msg = f"'message' must be a string in {path}"
        raise TypeError(msg)

    handler: CommandHandler
    if handler_ref:
        handler = _resolve_handler(handler_ref)
    else:
        # message must be a string here since we checked it's not None
        handler = _make_message_handler(cast(str, message))

    # Optional fields with defaults
    aliases = data.get("aliases", [])
    mode = data.get("mode", "normal")
    help_text = data.get("help", "")

    return CommandDefinition(
        name=name,
        handler=handler,
        aliases=aliases,
        mode=mode,
        help=help_text,
    )


def load_commands(directory: Path) -> list[CommandDefinition]:
    """Load all command definitions from a directory.

    Args:
        directory: Path to directory containing .toml files

    Returns:
        List of CommandDefinition instances
    """
    commands = []

    for path in directory.glob("*.toml"):
        try:
            commands.append(load_command(path))
        except Exception as e:
            log.warning("failed to load command from %s: %s", path, e)

    return commands
