"""Storage and service contracts for gnexus-gauth."""

from __future__ import annotations

from abc import ABC, abstractmethod
from datetime import datetime
from typing import Any

from gnexus_gauth.dto import (
    AuthenticatedUser,
    TokenSet,
    VerifiedWebhook,
    WebhookEvent,
)


class StateStoreInterface(ABC):
    """Authorization state storage contract."""

    @abstractmethod
    def put(self, state: str, expires_at: datetime, context: dict | None = None) -> None:
        """Persist authorization state with optional context."""

    @abstractmethod
    def has(self, state: str) -> bool:
        """Check if state exists and is not expired."""

    @abstractmethod
    def get_context(self, state: str) -> dict:
        """Retrieve context for the given state."""

    @abstractmethod
    def forget(self, state: str) -> None:
        """Remove the state."""


class PkceStoreInterface(ABC):
    """PKCE verifier storage contract."""

    @abstractmethod
    def put(self, state: str, verifier: str, expires_at: datetime) -> None:
        """Persist PKCE verifier by state."""

    @abstractmethod
    def get(self, state: str) -> str | None:
        """Retrieve PKCE verifier for callback exchange."""

    @abstractmethod
    def forget(self, state: str) -> None:
        """Remove consumed verifier."""


class TokenStoreInterface(ABC):
    """Optional token set persistence contract."""

    @abstractmethod
    def put(self, key: str, token_set: TokenSet) -> None:
        """Persist token set."""

    @abstractmethod
    def get(self, key: str) -> TokenSet | None:
        """Retrieve token set."""

    @abstractmethod
    def forget(self, key: str) -> None:
        """Delete token set on logout/revoke."""


class ClockInterface(ABC):
    """Clock abstraction for deterministic testing."""

    @abstractmethod
    def now(self) -> datetime:
        """Return current time."""


class TokenEndpointInterface(ABC):
    """Token endpoint operations."""

    @abstractmethod
    def exchange_authorization_code(self, code: str, pkce_verifier: str) -> TokenSet:
        """Exchange authorization code for tokens."""

    @abstractmethod
    def refresh_token(self, refresh_token: str) -> TokenSet:
        """Refresh access token."""

    @abstractmethod
    def revoke_token(self, token: str, token_type_hint: str | None = None) -> None:
        """Revoke a token."""


class RuntimeUserProviderInterface(ABC):
    """Runtime user data provider."""

    @abstractmethod
    def fetch_user(self, access_token: str) -> AuthenticatedUser:
        """Fetch authenticated user data from runtime API."""


class WebhookVerifierInterface(ABC):
    """Webhook signature verifier."""

    @abstractmethod
    def verify(self, raw_body: str, headers: dict[str, Any], secret: str) -> VerifiedWebhook:
        """Verify webhook signature."""


class WebhookParserInterface(ABC):
    """Webhook payload parser."""

    @abstractmethod
    def parse(self, raw_body: str) -> WebhookEvent:
        """Parse webhook payload into structured event."""
