"""Thing template loading, registry, and spawning."""

import functools
import importlib
import logging
import tomllib
from collections.abc import Awaitable, Callable
from dataclasses import dataclass, field
from pathlib import Path

from mudlib.container import Container
from mudlib.object import Object
from mudlib.thing import Thing

logger = logging.getLogger(__name__)


@dataclass
class ThingTemplate:
    """Definition loaded from TOML — used to spawn Thing instances."""

    name: str
    description: str
    portable: bool = True
    aliases: list[str] = field(default_factory=list)
    # Container fields (presence of capacity indicates a container template)
    capacity: int | None = None
    closed: bool = False
    locked: bool = False
    # Verb handlers (verb_name -> module:function reference)
    verbs: dict[str, str] = field(default_factory=dict)
    readable_text: str = ""
    tags: list[str] = field(default_factory=list)


# Module-level registry
thing_templates: dict[str, ThingTemplate] = {}


def _resolve_handler(ref: str) -> Callable[..., Awaitable[None]] | None:
    """Resolve a 'module:function' reference to a callable."""
    module_path, _, func_name = ref.rpartition(":")
    try:
        module = importlib.import_module(module_path)
        return getattr(module, func_name)
    except (ImportError, AttributeError) as e:
        logger.warning("Failed to resolve verb handler '%s': %s", ref, e)
        return None


def load_thing_template(path: Path) -> ThingTemplate:
    """Parse a thing TOML file into a ThingTemplate."""
    with open(path, "rb") as f:
        data = tomllib.load(f)
    return ThingTemplate(
        name=data["name"],
        description=data["description"],
        portable=data.get("portable", True),
        aliases=data.get("aliases", []),
        capacity=data.get("capacity"),
        closed=data.get("closed", False),
        locked=data.get("locked", False),
        verbs=data.get("verbs", {}),
        readable_text=data.get("readable_text", ""),
        tags=data.get("tags", []),
    )


def load_thing_templates(directory: Path) -> dict[str, ThingTemplate]:
    """Load all .toml files in a directory into a dict keyed by name."""
    templates: dict[str, ThingTemplate] = {}
    for path in sorted(directory.glob("*.toml")):
        template = load_thing_template(path)
        templates[template.name] = template
    return templates


def spawn_thing(
    template: ThingTemplate,
    location: Object | None,
    *,
    x: int | None = None,
    y: int | None = None,
) -> Thing:
    """Create a Thing instance from a template at the given location."""
    # If template has capacity, spawn a Container instead of a Thing
    if template.capacity is not None:
        obj = Container(
            name=template.name,
            description=template.description,
            portable=template.portable,
            aliases=list(template.aliases),
            readable_text=template.readable_text,
            tags=list(template.tags),
            capacity=template.capacity,
            closed=template.closed,
            locked=template.locked,
            location=location,
            x=x,
            y=y,
        )
    else:
        obj = Thing(
            name=template.name,
            description=template.description,
            portable=template.portable,
            aliases=list(template.aliases),
            readable_text=template.readable_text,
            tags=list(template.tags),
            location=location,
            x=x,
            y=y,
        )

    # Register verbs from the template
    for verb_name, handler_ref in template.verbs.items():
        handler = _resolve_handler(handler_ref)
        if handler is None:
            continue
        # Bind the object as first argument using partial
        bound_handler = functools.partial(handler, obj)
        obj.register_verb(verb_name, bound_handler)

    return obj
