import logging
import time

from joserfc import jwt
from joserfc.errors import JoseError

from authlib._joserfc_helpers import import_any_key

from ..rfc6749 import TokenMixin
from ..rfc6750 import BearerTokenValidator

logger = logging.getLogger(__name__)


class JWTBearerToken(TokenMixin, dict):
    def check_client(self, client):
        return self["client_id"] == client.get_client_id()

    def get_scope(self):
        return self.get("scope")

    def get_expires_in(self):
        return self["exp"] - self["iat"]

    def is_expired(self):
        return self["exp"] < time.time()

    def is_revoked(self):
        return False


class JWTBearerTokenValidator(BearerTokenValidator):
    TOKEN_TYPE = "bearer"
    token_cls = JWTBearerToken

    def __init__(self, public_key, issuer=None, realm=None, leeway=60, **extra_attributes):
        super().__init__(realm, **extra_attributes)
        self.public_key = import_any_key(public_key)
        self.leeway = leeway
        claims_options = {
            "exp": {"essential": True},
            "client_id": {"essential": True},
            "grant_type": {"essential": True},
        }
        if issuer:
            claims_options["iss"] = {"essential": True, "value": issuer}
        self.claims_options = claims_options

    def authenticate_token(self, token_string: str):
        try:
            token = jwt.decode(token_string, self.public_key)
        except JoseError as error:
            logger.debug("Authenticate token failed. %r", error)
            return None

        claims_requests = jwt.JWTClaimsRegistry(leeway=self.leeway, **self.claims_options)
        try:
            claims_requests.validate(token.claims)
        except JoseError as error:
            logger.debug("Authenticate token failed. %r", error)
            return None

        return JWTBearerToken(token.claims)
