import secrets
import string

import pyotp

_LOWER = string.ascii_lowercase
_UPPER = string.ascii_uppercase
_DIGITS = string.digits
_SYMBOLS = "!@#$%^&*-_=+"
_PASSWORD_POOL = _LOWER + _UPPER + _DIGITS + _SYMBOLS

_ALIAS_CHARS = string.ascii_letters + string.digits + "_"


def new_password(length: int = 20) -> str:
    if length < 4:
        raise ValueError("length must be >= 4 to fit one of each required class")

    required = [
        secrets.choice(_LOWER),
        secrets.choice(_UPPER),
        secrets.choice(_DIGITS),
        secrets.choice(_SYMBOLS),
    ]
    filler = [secrets.choice(_PASSWORD_POOL) for _ in range(length - len(required))]

    chars = required + filler
    secrets.SystemRandom().shuffle(chars)

    return "".join(chars)


def new_alias() -> str:
    length = secrets.randbelow(14) + 3
    return "".join(secrets.choice(_ALIAS_CHARS) for _ in range(length))


def new_totp_secret() -> str:
    return pyotp.random_base32()


def totp_now(secret: str) -> str:
    return pyotp.TOTP(secret).now()
