"""Type definitions for aiokwikset.

This module contains Protocol definitions and type aliases used
throughout the library for improved type safety and documentation.
"""

from __future__ import annotations

from collections.abc import Awaitable, Callable
from typing import Any, Protocol, runtime_checkable

# Subscription callback: receives (subscription_name, event_data)
SubscriptionCallback = Callable[[str, dict[str, Any]], None]

# Credentials provider: async callable returning an id_token string
CredentialsProvider = Callable[[], Awaitable[str]]

# Disconnect callback: invoked when a WebSocket connection drops unexpectedly
DisconnectCallback = Callable[[], None]

# Reconnect callback: invoked when a WebSocket connection is restored
ReconnectCallback = Callable[[], None]


@runtime_checkable
class RequestProtocol(Protocol):
    """Protocol defining the interface for HTTP request callables.

    This protocol ensures that endpoint classes (Device, User) receive
    a callable with the expected signature for making authenticated
    HTTP requests against the Kwikset API.

    The callable should:
    - Accept an HTTP method and URL as positional arguments
    - Accept additional keyword arguments (headers, data, etc.)
    - Return a dictionary containing the JSON response
    - Handle authentication headers automatically
    - Raise RequestError on failures

    Example implementation:
        >>> async def request(method: str, url: str, **kwargs: Any) -> Dict[str, Any]:
        ...     async with session.request(method, url, **kwargs) as resp:
        ...         return await resp.json()
    """

    async def __call__(
        self,
        method: str,
        url: str,
        **kwargs: Any,
    ) -> dict[str, Any]:
        """Make an HTTP request.

        :param method: HTTP method (get, post, patch, delete, etc.)
        :type method: ``str``
        :param url: The URL to request
        :type url: ``str``
        :param kwargs: Additional arguments passed to the request
            (e.g., headers, data, json, params)
        :rtype: ``Dict[str, Any]``
        :raises RequestError: If the request fails
        """
        ...
