"""Internal AP inbox dispatch for synchronous inter-service writes.

Each service can register handlers for (activity_type, object_type) pairs.
When an internal AP activity arrives, it is routed to the matching handler.

This mirrors the federated ``dispatch_inbox_activity()`` pattern but for
HMAC-authenticated internal service-to-service calls.
"""
from __future__ import annotations

import logging
from typing import Callable, Awaitable

from sqlalchemy.ext.asyncio import AsyncSession

log = logging.getLogger(__name__)

# Registry: (activity_type, object_type) → async handler(session, body) → dict
_internal_handlers: dict[tuple[str, str], Callable[[AsyncSession, dict], Awaitable[dict]]] = {}


def register_internal_handler(
    activity_type: str,
    object_type: str,
    handler: Callable[[AsyncSession, dict], Awaitable[dict]],
) -> None:
    """Register a handler for an internal AP activity type + object type pair."""
    key = (activity_type, object_type)
    if key in _internal_handlers:
        log.warning("Overwriting internal handler for %s", key)
    _internal_handlers[key] = handler


async def dispatch_internal_activity(session: AsyncSession, body: dict) -> dict:
    """Route an internal AP activity to the correct handler.

    Returns the handler result dict. Raises ValueError for unknown types.
    """
    activity_type = body.get("type", "")
    obj = body.get("object") or {}
    object_type = obj.get("type", "") if isinstance(obj, dict) else ""

    key = (activity_type, object_type)
    handler = _internal_handlers.get(key)
    if handler is None:
        raise ValueError(f"No internal handler for {key}")

    log.info("Dispatching internal activity %s", key)
    return await handler(session, body)
