import binascii
import datetime
import inspect
import logging
import os
from pathlib import Path

from . import exceptions

logger = logging.getLogger(__name__)


def generate_token(n=24):
    return str(binascii.hexlify(os.urandom(n)), 'utf-8')


def build_claim_iss(attr, *args, **kwargs):
    return attr


def build_claim_iat(attr, *args, **kwargs):
    return datetime.datetime.utcnow() if attr else None


def build_claim_nbf(attr, config, *args, **kwargs):
    seconds = config.leeway + config.claim_nbf_delta
    return datetime.datetime.utcnow() + datetime.timedelta(
        seconds=seconds
    ) if attr else None


def build_claim_aud(attr, *args, **kwargs):
    return attr


async def call(fn, *args, **kwargs):
    if inspect.iscoroutinefunction(fn) or inspect.isawaitable(fn):
        fn = await fn(*args, **kwargs)
    elif callable(fn):
        fn = fn(*args, **kwargs)
    return fn


def load_file_or_str(path_or_str):
    if isinstance(path_or_str, Path):
        if os.path.isfile(str(path_or_str)):
            logger.debug('reading file \"{}\"'.format(str(path_or_str)))
            return path_or_str.read_text()
        else:
            raise exceptions.ProvidedPathNotFound
    elif isinstance(path_or_str, str):
        if os.path.isfile(path_or_str):
            return Path(path_or_str).read_text()
    return path_or_str


def algorithm_is_asymmetric(algorithm):
    """This is a simple method to verify the need to provide a private key to
    a given ``algorithm``, as `documented by PyJWT
    <https://pyjwt.readthedocs.io/en/latest/algorithms.html>`_

    :param algorithm: the given algorithm, like HS256, ES384, RS512, PS256, etc
    :return: True if algorithm is asymmetric
    """
    return algorithm.lower()[:2] in ('rs', 'es', 'ps')
