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 (
    AdminToken,
    DecodedPayload,
    GenericToken,
)
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 AppAdmin, TokenInfo

ADMIN_KEY = require_env("ADMIN_KEY")

admin_token_generator = make_token_generator(ADMIN_KEY)


def generate_admin_token(
    admin: AppAdmin, token_type: str, expires_in: int = 900
) -> tuple[AdminToken, GenericToken]:
    token, token_info = admin_token_generator(
        id=admin.name,
        token_type=token_type,
        expires_in=expires_in,
    )
    return AdminToken(token), token_info


admin_token_sig_validator = make_token_sig_validator(ADMIN_KEY)
admin_validator = make_generic_validator(admin_token_sig_validator)
validate = make_validate_token(admin_validator, get_token_info)


def get_valid_payload(
    admin_session: Annotated[str | None, Cookie()] = None,
) -> DecodedPayload | None:
    if admin_session is not None:
        validation_result = admin_validator(
            token=admin_session, expected_type="admin"
        )
        if isinstance(validation_result, DecodedPayload):
            return validation_result


AdminTokenPayload = Annotated[
    DecodedPayload | None, Depends(get_valid_payload)
]


def get_valid_admin_token_info(
    payload: AdminTokenPayload,
    session: SessionDep,
) -> TokenInfo | None:
    if payload is not None:
        token_info = get_token_info(d_p=payload, session=session)
        token_info = token_info_validator(token_info=token_info)
        if isinstance(token_info, TokenInfo):
            return token_info


def admin_from_token(token_payload: AdminTokenPayload, session: SessionDep):
    if token_payload is not None:
        stmt = select(AppAdmin).where(AppAdmin.name == token_payload.id)
        result = session.exec(stmt).one_or_none()

        return result


AuthentifiedAdmin = Annotated[AppAdmin | None, Depends(admin_from_token)]
