from typing import List, Literal, Optional, Tuple

import pytest
from fastapi import Request
from pytest import MonkeyPatch
from starlette.datastructures import Headers

from sag_py_auth.jwt_auth import JwtAuth
from sag_py_auth.models import AuthConfig, Token, TokenRole
from sag_py_auth.token_types import TokenDict

from .helpers import get_token_dict

pytest_plugins: Tuple[Literal["pytest_asyncio"]] = ("pytest_asyncio",)


def verify_and_decode_token_mock(_: AuthConfig, __: str) -> TokenDict:
    return get_token_dict(None, None)


def _verify_roles_mock(_: JwtAuth, token: Optional[Token]) -> None:
    if token:
        token.token_dict["_verify_roles"] = "True"


def _verify_realm_roles_mock(_: JwtAuth, token: Optional[Token]) -> None:
    if token:
        token.token_dict["_verify_realm_roles"] = "True"


def auth_context_set_token_mock(token: Token) -> None:
    if token:
        token.token_dict["auth_context_set_token"] = "True"


@pytest.mark.asyncio
async def test__call__correctly_processes_request(monkeypatch: MonkeyPatch) -> None:
    # Arrange
    auth_config = AuthConfig("https://authserver.com/auth/realms/projectName", "audienceOne")
    required_roles: List[TokenRole] = [TokenRole("clientOne", "clientOneRoleOne")]
    required_realm_roles: List[str] = ["realmRoleOne"]

    monkeypatch.setattr("sag_py_auth.jwt_auth.verify_and_decode_token", verify_and_decode_token_mock)
    monkeypatch.setattr("sag_py_auth.jwt_auth.JwtAuth._verify_roles", _verify_roles_mock)
    monkeypatch.setattr("sag_py_auth.jwt_auth.JwtAuth._verify_realm_roles", _verify_realm_roles_mock)
    monkeypatch.setattr("sag_py_auth.jwt_auth.auth_context_set_token", auth_context_set_token_mock)

    jwt = JwtAuth(auth_config, required_roles, required_realm_roles)

    request: Request = Request(scope={"type": "http"})
    request._headers = Headers({"Authorization": "Bearer validToken"})

    # Act
    actual: Token = await jwt.__call__(request)

    # Assert - Verify that all steps have been executed
    assert actual.get_field_value("typ") == "Bearer"
    assert actual.get_field_value("azp") == "public-project-swagger"
    assert actual.get_field_value("_verify_roles") == "True"
    assert actual.get_field_value("_verify_realm_roles") == "True"
    assert actual.get_field_value("auth_context_set_token") == "True"
