import logging
from typing import Annotated
from fastapi import Cookie, Depends
from sqlmodel import Session, 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,
    token_info_validator,
)
from rvpc.auth.tokens.typing import (
    CaptureToken,
    DecodedPayload,
    GenericToken,
)
from rvpc.auth.utils import require_env
from rvpc.db import SessionDep
from rvpc.models.models import AppAdmin, TokenInfo, CaptureTokenInfo

ADMIN_KEY = require_env("ADMIN_KEY")

capture_token_generator = make_token_generator(ADMIN_KEY)


def generate_capture_token(
    admin: AppAdmin, expires_in: int = 900
) -> tuple[CaptureToken, GenericToken]:
    token, token_info = capture_token_generator(
        id=admin.name,
        token_type="capture",
        expires_in=expires_in,
    )
    return CaptureToken(token), token_info


def make_capture_info_getter(expected_loc: str):
    def capture_info_getter(
        d_p: DecodedPayload, session: Session
    ) -> CaptureTokenInfo | None:
        stmt = select(CaptureTokenInfo).where(
            CaptureTokenInfo.nonce == d_p.nonce,
            CaptureTokenInfo.token_type == d_p.token_type,
            CaptureTokenInfo.expires_at == d_p.expires_at,
            CaptureTokenInfo.admin_name == d_p.id,
            CaptureTokenInfo.location_name == expected_loc,
        )
        result = session.exec(stmt).one_or_none()
        return result

    return capture_info_getter


capture_sig_validator = make_token_sig_validator(ADMIN_KEY)
capture_validator = make_generic_validator(capture_sig_validator)


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


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


def get_valid_token_info(
    payload: CaptureTokenPayload,
    session: SessionDep,
    location: Annotated[str | None, Cookie()] = None,
) -> TokenInfo | None:
    logging.warning(location)
    logging.warning("LOCATION ^")
    if payload is not None and location is not None:
        capture_info_getter = make_capture_info_getter(expected_loc=location)
        token_info = capture_info_getter(payload, session=session)
        token_info = token_info_validator(token_info=token_info)
        if isinstance(token_info, CaptureTokenInfo):
            return token_info


ValidCaptureTokenInfo = Annotated[
    TokenInfo | None, Depends(get_valid_token_info)
]


def capture_enabled_on_device(
    payload: CaptureTokenPayload,
    token_info: ValidCaptureTokenInfo,
) -> bool:
    return (payload is not None) and (token_info is not None)


CaptureEnabled = Annotated[bool, Depends(capture_enabled_on_device)]
