"""Tests for ``mgf.apiprobe.core.auth`` — Protocol + AuthCredentials."""

from __future__ import annotations

import dataclasses

from mgf.apiprobe.core.auth import AuthCredentials, AuthFlow


class TestAuthCredentials:
    def test_default_construction(self) -> None:
        c = AuthCredentials()
        assert c.headers == ()
        assert c.cookies == ()
        assert c.query_params == ()

    def test_full_construction(self) -> None:
        c = AuthCredentials(
            headers=(("Authorization", "Bearer abc"),),
            cookies=(("session", "xyz"),),
            query_params=(("api_key", "k"),),
        )
        assert c.headers[0] == ("Authorization", "Bearer abc")
        assert c.cookies[0] == ("session", "xyz")
        assert c.query_params[0] == ("api_key", "k")

    def test_frozen(self) -> None:
        c = AuthCredentials()
        try:
            c.headers = (("X", "Y"),)  # type: ignore[misc]
        except dataclasses.FrozenInstanceError:
            pass
        else:
            raise AssertionError("AuthCredentials should be frozen")


class TestAuthFlowProtocol:
    def test_runtime_checkable(self) -> None:
        # Confirms the @runtime_checkable decorator is in place — a
        # duck-typed object satisfies the Protocol via isinstance.
        class FakeBearer:
            name = "fake-bearer"

            def prepare(self) -> AuthCredentials:
                return AuthCredentials(headers=(("Authorization", "Bearer xyz"),))

        assert isinstance(FakeBearer(), AuthFlow)

    def test_object_missing_method_fails_isinstance(self) -> None:
        class IncompleteAuth:
            name = "x"
            # missing .prepare()

        assert not isinstance(IncompleteAuth(), AuthFlow)

    def test_object_missing_name_fails_isinstance(self) -> None:
        class NoName:
            def prepare(self) -> AuthCredentials:
                return AuthCredentials()

        # runtime_checkable Protocol requires data attributes too.
        # Note: Protocol's runtime check inspects __init__/instance attrs
        # somewhat loosely; this test pins the current behavior.
        assert not isinstance(NoName(), AuthFlow)
