"""Lambda entrypoint helpers."""

from collections.abc import Callable
from dataclasses import dataclass
from typing import Any, Protocol, cast

from aws_lambda_typing.context import Context
from aws_lambda_typing.events import APIGatewayProxyEventV1, EventBridgeEvent
from punq import Container  # type: ignore[import-untyped]

from ..dispatch.api_gateway import ApiGatewayEventHandler
from ..dispatch.eventbridge import EventBridgeEventHandler
from ..dispatch.models import ApiRequest, EventEnvelope
from ..support.authz import Principal
from .context import RequestScope

Event = APIGatewayProxyEventV1 | EventBridgeEvent
ContainerProvider = Callable[[Event, Context], Container]


class LambdaDispatcher(Protocol):
    def dispatch(self, event: Event, context: Context, container: Container) -> Any: ...


class LambdaHandler(Protocol):
    def __call__(self, event: Event, context: Context, *args: Any) -> Any: ...


@dataclass(slots=True, frozen=True)
class DefaultLambdaDispatcher:
    """Dispatch a Lambda event from the container."""

    api_handler_type: type[ApiGatewayEventHandler] = ApiGatewayEventHandler
    event_handler_type: type[EventBridgeEventHandler] = EventBridgeEventHandler

    def dispatch(self, event: Event, context: Context, container: Container) -> Any:
        del context
        if _is_eventbridge_event(event):
            return container.resolve(self.event_handler_type).handle(cast(EventBridgeEvent, event))
        return container.resolve(self.api_handler_type).handle(cast(APIGatewayProxyEventV1, event))


def build_lambda_handler(
    container_provider: ContainerProvider,
    *,
    dispatcher: LambdaDispatcher | None = None,
) -> LambdaHandler:
    """Create a Lambda handler."""

    resolved_dispatcher = dispatcher or DefaultLambdaDispatcher()

    def handle(event: Event, context: Context, *_: Any) -> Any:
        container = container_provider(event, context)
        correlation = _correlation_id_for(event)
        with RequestScope(container=container, correlation_id=correlation, principal=Principal.guest()):
            return resolved_dispatcher.dispatch(event, context, container)

    return handle


def _is_eventbridge_event(event: Event) -> bool:
    return "detail-type" in event


def _correlation_id_for(event: Event) -> str:
    if _is_eventbridge_event(event):
        return EventEnvelope.from_event(cast(EventBridgeEvent, event)).correlation_id
    return ApiRequest.from_event(cast(APIGatewayProxyEventV1, event)).correlation_id


__all__ = [
    "ContainerProvider",
    "DefaultLambdaDispatcher",
    "Event",
    "LambdaDispatcher",
    "LambdaHandler",
    "build_lambda_handler",
]
