from typing import Union

from fastapi import Request
from fastapi.param_functions import Depends, Header
from fastapi.security import OAuth2PasswordBearer
from sqlmodel import Session, select

from ..core.constants import AccessLevel, ContextEnum
from ..core.helpers.database import make_session
from ..core.helpers.exceptions import NotAuthorizedError
from ..core.models import Context, ParsedToken, User
from ..core.security import load_jwt_token

reusable_oauth2 = OAuth2PasswordBearer(tokenUrl="api/v1/auth/access-token")


def get_string_token(token: str = Header(None, alias="Authorization")) -> Union[None, str]:
    if token:
        _, _, token = token.partition(" ")

    return token


def load_access_token(request: Request, token: str = Depends(reusable_oauth2)) -> ParsedToken:
    return load_jwt_token(token)


async def get_current_user(
    session: Session = Depends(make_session), token: ParsedToken = Depends(load_access_token)
) -> User:
    user = session.exec(select(User).where(User.id == token.sub)).first()

    if not user:
        raise NotAuthorizedError("Usuário não localizado")

    return user


async def login_required(current_user: User = Depends(get_current_user)) -> None:
    if not current_user.is_active:
        raise NotAuthorizedError("Sua licença expirou! Entre em contato com um administrador.")


async def validate_super_user(user: User = Depends(get_current_user)) -> None:
    if not user.is_super_user:
        raise NotAuthorizedError("Essa página só está disponível para administradores")


class ContextManager:
    context: ContextEnum

    def __init__(self, context: Union[str, ContextEnum]) -> None:
        self.context = context if isinstance(context, ContextEnum) else ContextEnum(context)

    def __call__(self, request: Request, token: str = Depends(get_string_token)) -> Context:
        try:
            parsed_token = load_jwt_token(token=token)
            user_id = parsed_token.sub
            access_level = parsed_token.access_level
            authenticated = True

        except NotAuthorizedError:
            user_id = None
            authenticated = False
            access_level = AccessLevel.ANONIMOUS

        return Context(
            context=self.context,
            user_id=user_id,
            method=request.url.path,
            authenticated=authenticated,
            access_level=access_level,
        )


context_manager = ContextManager(ContextEnum.API)

fastapi.param_functions.Depends sqlmodel.select fastapi.param_functions.Header fastapi.security.OAuth2PasswordBearer
[((469, 526), 'fastapi.security.OAuth2PasswordBearer', 'OAuth2PasswordBearer', ([], {'tokenUrl': '"""api/v1/auth/access-token"""'}), "(tokenUrl='api/v1/auth/access-token')\n", (489, 526), False, 'from fastapi.security import OAuth2PasswordBearer\n'), ((563, 598), 'fastapi.param_functions.Header', 'Header', (['None'], {'alias': '"""Authorization"""'}), "(None, alias='Authorization')\n", (569, 598), False, 'from fastapi.param_functions import Depends, Header\n'), ((751, 775), 'fastapi.param_functions.Depends', 'Depends', (['reusable_oauth2'], {}), '(reusable_oauth2)\n', (758, 775), False, 'from fastapi.param_functions import Depends, Header\n'), ((879, 900), 'fastapi.param_functions.Depends', 'Depends', (['make_session'], {}), '(make_session)\n', (886, 900), False, 'from fastapi.param_functions import Depends, Header\n'), ((923, 949), 'fastapi.param_functions.Depends', 'Depends', (['load_access_token'], {}), '(load_access_token)\n', (930, 949), False, 'from fastapi.param_functions import Depends, Header\n'), ((1177, 1202), 'fastapi.param_functions.Depends', 'Depends', (['get_current_user'], {}), '(get_current_user)\n', (1184, 1202), False, 'from fastapi.param_functions import Depends, Header\n'), ((1389, 1414), 'fastapi.param_functions.Depends', 'Depends', (['get_current_user'], {}), '(get_current_user)\n', (1396, 1414), False, 'from fastapi.param_functions import Depends, Header\n'), ((1808, 1833), 'fastapi.param_functions.Depends', 'Depends', (['get_string_token'], {}), '(get_string_token)\n', (1815, 1833), False, 'from fastapi.param_functions import Depends, Header\n'), ((985, 997), 'sqlmodel.select', 'select', (['User'], {}), '(User)\n', (991, 997), False, 'from sqlmodel import Session, select\n')]