"""
Decorators that wrap automation handlers: parse CloudEvent data into a Pydantic model
and pass (event_data, StaxContext) to the handler. Return an ASGI callable for Knative func-python.
"""

from __future__ import annotations

import json
from collections.abc import Callable
from typing import Any, MutableMapping, TypeVar

from pydantic import BaseModel

from stax_sdk.automation.context import StaxContext

T = TypeVar("T", bound=BaseModel)


def _event_data_as_dict(event: Any) -> dict[str, Any]:
    """Extract event.data as a dict (decode bytes if needed)."""
    data = getattr(event, "data", event.get("data") if isinstance(event, dict) else None)
    if data is None:
        return {}
    if isinstance(data, bytes):
        return json.loads(data.decode("utf-8"))
    if isinstance(data, dict):
        return data
    if isinstance(data, str):
        return json.loads(data)
    return dict(data)


def _raw_event_to_dict(event: Any) -> dict[str, Any]:
    """Turn scope['event'] into a plain dict for StaxContext.raw_event."""
    if isinstance(event, dict):
        return dict(event)
    # CloudEvent-like object
    out: dict[str, Any] = {}
    for attr in ("id", "source", "type", "specversion", "time", "subject", "data"):
        if hasattr(event, attr):
            val = getattr(event, attr)
            if isinstance(val, bytes):
                try:
                    val = json.loads(val.decode("utf-8"))
                except Exception:
                    val = val.decode("utf-8")
            out[attr] = val
    return out


def stax_automation(
    event_data_model: type[T],
    inject_headers: Callable[[MutableMapping[str, str]], None] | None = None,
):
    """
    Decorator for sync automation handlers. Use with Knative Functions (func-python).
    The decorated function receives (event_data: event_data_model, context: StaxContext).
    Returns an ASGI callable (scope, receive, send) that Knative invokes.
    """

    def decorator(
        handler: Callable[[T, StaxContext], Any],
    ) -> Callable[..., Any]:
        from stax_sdk.automation.asgi import asgi_app_for_sync

        return asgi_app_for_sync(
            handler=handler,
            event_data_model=event_data_model,
            inject_headers=inject_headers,
        )

    return decorator


def stax_automation_async(
    event_data_model: type[T],
    inject_headers: Callable[[MutableMapping[str, str]], None] | None = None,
):
    """
    Decorator for async automation handlers. Returns an ASGI callable for Knative func-python.
    """

    def decorator(
        handler: Callable[[T, StaxContext], Any],
    ) -> Callable[..., Any]:
        from stax_sdk.automation.asgi import asgi_app_for_async

        return asgi_app_for_async(
            handler=handler,
            event_data_model=event_data_model,
            inject_headers=inject_headers,
        )

    return decorator
