"""Tests for runtime-checkable protocols."""

from __future__ import annotations

import uuid
from typing import Any

import pytest

from aura_auth._core.protocols import BackendProtocol, StrategyProtocol, TransportProtocol, UserProtocol
from aura_auth._core.types import ID


class GoodUser:
    def __init__(self) -> None:
        self.id = uuid.uuid4()
        self.email = "u@example.com"
        self.hashed_password = "hash"
        self.is_active = True
        self.is_verified = False


class BadUser:
    def __init__(self) -> None:
        self.id = uuid.uuid4()
        self.email = "u@example.com"


@pytest.mark.parametrize("obj,expected", [(GoodUser(), True), (BadUser(), False)])
def test_user_protocol_runtime_check(obj: object, expected: bool) -> None:
    assert isinstance(obj, UserProtocol) is expected


class DummyBackend:
    async def get_by_id(self, user_id: ID) -> UserProtocol | None:
        return None

    async def get_by_email(self, email: str) -> UserProtocol | None:
        return None

    async def create(self, data: dict[str, Any]) -> UserProtocol:
        return GoodUser()  # type: ignore[return-value]

    async def update(self, user: UserProtocol, data: dict[str, Any]) -> UserProtocol:
        return user

    async def delete(self, user: UserProtocol) -> None:
        return None


class BrokenBackend:
    async def get_by_id(self, user_id: ID) -> UserProtocol | None:
        return None


def test_backend_protocol_runtime_check() -> None:
    assert isinstance(DummyBackend(), BackendProtocol)
    assert not isinstance(BrokenBackend(), BackendProtocol)


class DummyStrategy:
    async def authenticate(self, credentials: dict[str, Any], backend: BackendProtocol) -> UserProtocol | None:
        return None

    async def on_after_register(self, user: UserProtocol) -> None:
        return None

    async def on_after_login(self, user: UserProtocol) -> None:
        return None


class BrokenStrategy:
    async def authenticate(self, credentials: dict[str, Any], backend: BackendProtocol) -> UserProtocol | None:
        return None


def test_strategy_protocol_runtime_check() -> None:
    assert isinstance(DummyStrategy(), StrategyProtocol)
    assert not isinstance(BrokenStrategy(), StrategyProtocol)


class DummyTransport:
    async def get_token(self, request: object) -> str | None:
        return None

    def set_token(self, response: object, token: str) -> None:
        return None

    def remove_token(self, response: object) -> None:
        return None


class BrokenTransport:
    async def get_token(self, request: object) -> str | None:
        return None


def test_transport_protocol_runtime_check() -> None:
    assert isinstance(DummyTransport(), TransportProtocol)
    assert not isinstance(BrokenTransport(), TransportProtocol)
