"""
Provider protocols and implementations for Daisi SDK.

This module provides Python-idiomatic abstractions for key providers.
Uses Protocol (structural subtyping) instead of ABC for flexibility.

Note: Unlike .NET's IClientKeyProvider interface, Python's Protocol allows
duck typing - any object with a get_client_key() method works without
explicit inheritance.
"""

from typing import Optional, Protocol, runtime_checkable


@runtime_checkable
class ClientKeyProvider(Protocol):
    """Protocol for client key providers.

    Implement this protocol to provide custom client key retrieval logic.
    Unlike .NET's IClientKeyProvider which requires explicit implementation,
    Python's Protocol uses structural subtyping - any class with a matching
    get_client_key() method is considered compatible.

    Example:
        class MyKeyProvider:
            def get_client_key(self) -> str:
                return fetch_key_from_vault()

        # Works without explicit inheritance
        provider: ClientKeyProvider = MyKeyProvider()
    """

    def get_client_key(self) -> str:
        """Get the current client key.

        Returns:
            The client key string for authentication.
        """
        ...


class DefaultClientKeyProvider:
    """Default client key provider using a static key.

    This is the simplest implementation that stores a fixed key.
    For production, consider implementing a provider that fetches
    keys from a secure vault or rotates keys automatically.
    """

    def __init__(self, client_key: str = "") -> None:
        """Initialize with a client key.

        Args:
            client_key: The client key to use.
        """
        self._client_key = client_key

    def get_client_key(self) -> str:
        """Get the stored client key.

        Returns:
            The client key string.
        """
        return self._client_key

    def set_client_key(self, client_key: str) -> None:
        """Update the stored client key.

        Args:
            client_key: New client key to store.
        """
        self._client_key = client_key


class EnvironmentClientKeyProvider:
    """Client key provider that reads from environment variables.

    Useful for containerized deployments where keys are injected
    via environment variables.
    """

    def __init__(
        self,
        env_var: str = "DAISI_CLIENT_KEY",
        fallback: Optional[str] = None,
    ) -> None:
        """Initialize with environment variable name.

        Args:
            env_var: Name of the environment variable.
            fallback: Fallback value if env var is not set.
        """
        import os

        self._env_var = env_var
        self._fallback = fallback or ""
        self._os = os

    def get_client_key(self) -> str:
        """Get client key from environment.

        Returns:
            The client key from environment or fallback.
        """
        return self._os.getenv(self._env_var, self._fallback)


class CallableClientKeyProvider:
    """Client key provider that uses a callable to fetch the key.

    Useful for dynamic key retrieval from external sources.

    Example:
        provider = CallableClientKeyProvider(lambda: vault.get_secret("daisi-key"))
    """

    def __init__(self, key_getter: "Callable[[], str]") -> None:
        """Initialize with a key getter function.

        Args:
            key_getter: Callable that returns the client key.
        """
        from typing import Callable

        self._key_getter: Callable[[], str] = key_getter

    def get_client_key(self) -> str:
        """Get client key by calling the getter.

        Returns:
            The client key from the getter function.
        """
        return self._key_getter()
