# SPDX-License-Identifier: MIT
# Copyright (c) 2019, Mathias Laurin

"""Generate secure random numbers.

This is an implementation of the PEP 506 API based on a
CSPRNG (Cryptographically Strong Pseudo Random Number Generator).

This module is compatibale with the standard `secrets` (PEP 506) module.

"""

from __future__ import annotations

import base64 as _base64
import binascii as _binascii
from typing import Callable, Final, Sequence, TypeVar, cast

import mbedtls._random as _rnd  # pylint: disable=no-name-in-module

__all__ = [
    "randbits",
    "choice",
    "randbelow",
    "token_bytes",
    "token_hex",
    "token_urlsafe",
]


DEFAULT_ENTROPY: Final = 32


__rng = _rnd.default_rng()


randbits: Callable[[int], int] = __rng.getrandbits

T_co = TypeVar("T_co", covariant=True)
choice: Callable[[Sequence[T_co]], T_co] = __rng.choice
randbelow: Callable[[int], int] = __rng.randbelow


def token_bytes(nbytes: int = DEFAULT_ENTROPY) -> bytes:
    """Return a random byte string containing `nbytes` number of bytes.

    If `nbytes` is ``None`` or not supplied, a reasonable default is used.

    """
    return cast(bytes, __rng.urandom(nbytes))


def token_hex(nbytes: int = DEFAULT_ENTROPY) -> str:
    """Return a random text string, in hexadecimal."""
    return _binascii.hexlify(token_bytes(nbytes)).decode("ascii")


def token_urlsafe(nbytes: int = DEFAULT_ENTROPY) -> str:
    """Return a random URL-safe string."""
    tok = token_bytes(nbytes)
    return _base64.urlsafe_b64encode(tok).rstrip(b"=").decode("ascii")
