"""User-perspective tests for ``mgf.apiprobe.auth``.

Surfaces exercised:
  - All five built-in auth flows construct cleanly.
  - Each implements :class:`AuthFlow` (via duck-typed ``name`` +
    ``prepare()``).
  - Bearer + Basic + Cookie + ApiKey + Custom all produce
    :class:`AuthCredentials` with the right header / query /
    cookie payload.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

from mgf.apiprobe.auth import (
    ApiKeyAuth,
    BasicAuth,
    BearerAuth,
    CookieAuth,
    CustomAuth,
)
from mgf.apiprobe.core import AuthCredentials, AuthFlow

if TYPE_CHECKING:
    import pytest


class TestBearerAuth:
    def test_construct_with_token(self) -> None:
        b = BearerAuth(token="abc123")
        assert isinstance(b, AuthFlow)
        assert b.name == "bearer"

    def test_prepare_emits_authorization_header(self) -> None:
        b = BearerAuth(token="abc123")
        creds = b.prepare()
        assert isinstance(creds, AuthCredentials)
        assert ("Authorization", "Bearer abc123") in creds.headers

    def test_construct_with_env(
        self,
        monkeypatch: pytest.MonkeyPatch,
    ) -> None:
        monkeypatch.setenv("MY_BEARER_TOKEN", "from-env-secret")
        b = BearerAuth(env="MY_BEARER_TOKEN")
        creds = b.prepare()
        assert ("Authorization", "Bearer from-env-secret") in creds.headers


class TestBasicAuth:
    def test_construct_and_prepare(self) -> None:
        b = BasicAuth(username="alice", password="hunter2")
        assert isinstance(b, AuthFlow)
        creds = b.prepare()
        # Header name is Authorization; value starts with "Basic ".
        auth_header = next(
            (v for k, v in creds.headers if k == "Authorization"),
            None,
        )
        assert auth_header is not None
        assert auth_header.startswith("Basic ")


class TestApiKeyAuth:
    def test_header_location(self) -> None:
        a = ApiKeyAuth(header="X-API-Key", value="abc")
        creds = a.prepare()
        assert ("X-API-Key", "abc") in creds.headers

    def test_query_location(self) -> None:
        a = ApiKeyAuth(query="api_key", value="abc")
        creds = a.prepare()
        assert ("api_key", "abc") in creds.query_params


class TestCookieAuth:
    def test_construct_and_prepare(self) -> None:
        c = CookieAuth(cookie_name="session", value="xyz789")
        creds = c.prepare()
        assert ("session", "xyz789") in creds.cookies


class TestCustomAuth:
    def test_callback_round_trip(self) -> None:
        # Custom flow takes a prepare_func and uses its return value.
        called: list[bool] = []

        def my_prepare() -> AuthCredentials:
            called.append(True)
            return AuthCredentials(
                headers=(("X-Custom-Auth", "yes"),),
            )

        c = CustomAuth(name="my-custom", prepare_func=my_prepare)
        assert isinstance(c, AuthFlow)
        creds = c.prepare()
        assert called == [True]
        assert ("X-Custom-Auth", "yes") in creds.headers
