from collections.abc import Callable
from functools import wraps
from typing import TypeVar

from ..models import Message
from .registry import PROVIDERS, register_provider
from .types import AsyncSendFn, SendFn

T = TypeVar("T")


def register_sync(name: str, *, string_key: str | None = None):
    """Register a given provider's synchronous `send` method."""

    def decorator(func: SendFn) -> SendFn:
        register_provider(
            name=name,
            send=func,
            string_key=string_key,
        )
        return func

    return decorator


def register_async(name: str):
    """Register an asynchronous send function to a provider."""

    def decorator(func: AsyncSendFn) -> AsyncSendFn:
        PROVIDERS[name].async_send = func
        return func

    return decorator


def normalise_message(func: Callable[..., T]) -> Callable[..., T]:
    """Ensure the first argument is always a Message, coercing strings automatically."""

    @wraps(func)
    def wrapper(message: Message | str, *args, **kwargs) -> T:
        if not isinstance(message, Message):
            message = Message(text=message)
        return func(message, *args, **kwargs)

    return wrapper
