from typing import Annotated

from fastapi import Cookie, Depends
from sqlmodel import select

from rvpc.auth.tokens.generic_generators import make_token_generator
from rvpc.auth.tokens.generic_validators import (
    make_generic_validator,
    make_token_sig_validator,
    make_validate_token,
    token_info_validator,
)
from rvpc.auth.tokens.typing import DecodedPayload, GenericToken, UserToken
from rvpc.auth.tokens.utils import get_token_info
from rvpc.auth.utils import require_env
from rvpc.db import SessionDep
from rvpc.models.models import TokenInfo, AppUser


USERS_KEY = require_env("SECRET_KEY")


user_token_generator = make_token_generator(USERS_KEY)


def generate_user_token(
    user: AppUser, expires_in: int = 900
) -> tuple[UserToken, GenericToken]:
    token, token_info = user_token_generator(
        id=user.hashid,
        token_type="user",
        expires_in=expires_in,
    )
    return (
        UserToken(token),
        GenericToken(
            nonce=token_info.nonce,
            expires_at=token_info.expires_at,
            token_type=token_info.token_type,
        ),
    )


user_sig_validator = make_token_sig_validator(USERS_KEY)
user_validator = make_generic_validator(user_sig_validator)
validate = make_validate_token(user_validator, get_token_info)


def get_valid_payload(user_session: Annotated[str | None, Cookie()] = None):
    if user_session is not None:
        validation_result = user_validator(
            token=user_session, expected_type="user"
        )
        if isinstance(validation_result, DecodedPayload):
            return validation_result


UserTokenPayload = Annotated[DecodedPayload, Depends(get_valid_payload)]


def get_valid_token_info(payload: UserTokenPayload, session: SessionDep):
    token_info = get_token_info(payload, session=session)
    token_info = token_info_validator(token_info=token_info)
    if isinstance(token_info, TokenInfo):
        return token_info


ValidTokenInfo = Annotated[TokenInfo, Depends(get_valid_token_info)]


def user_from_token(token_payload: UserTokenPayload, session: SessionDep):
    if token_payload is not None:
        stmt = select(AppUser).where(AppUser.hashid == token_payload.id)
        result = session.exec(stmt).one()

        return result


AuthentifiedUser = Annotated[AppUser, Depends(user_from_token)]
