import random
from typing import Optional
import uuid

DEFAULT_RANDOM_SEED = 42
READABLE_RAND_CHARS = "23456789abcdefghjkmnprstuvwxyz"


def gen_uuid(n: int = 8):
    # e.g. '161b58a4d8'
    return str(uuid.uuid4()).replace("-", "")[:n]


def gen_readable_rand_id(n: int = 7, valid: Optional[list | str] = None):
    # build an N-digit random string with letters or numbers
    # excluding o,0,i,1,l,q (too similar to g) for easy reading
    #
    # this isn't officially a UUID
    if valid is None:
        valid = READABLE_RAND_CHARS
    return "".join([random.choice(valid) for _ in range(n)])


def assert_valid_readable_rand_id(
    id_: str, nchars: Optional[int] = None, valid_chars: Optional[str] = None
):
    """
    Check if ID_ is a valid readable random id, as generated by GEN_READABLE_UUID.
    """
    assert id_, "id_ cannot be empty"
    if nchars is not None:
        assert len(id_) == nchars, f"len({id_}) != {nchars}"
    if valid_chars is None:
        valid_chars = READABLE_RAND_CHARS
    assert all([c in valid_chars for c in id_]), f"Invalid character in {id_}"


def shuffle_copy(lst):
    lst2 = lst.copy()
    random.shuffle(lst2)
    return lst2


def set_seeds(seed: int = DEFAULT_RANDOM_SEED):
    # TODO if SEED is None, make it dynamic
    random.seed(seed)

    try:
        import numpy as np

        np.random.seed(seed)
    except ImportError:
        pass

    try:
        import torch  # type: ignore

        torch.manual_seed(seed)
        torch.cuda.manual_seed(seed)
        torch.cuda.manual_seed_all(seed)
        # If you are using cudnn (a GPU-accelerated library for deep neural networks)
        torch.backends.cudnn.deterministic = True

    except ImportError:
        pass
