import random
import string

from django.db import IntegrityError


def new_uid(max_length, prefix=None,
            chars=string.ascii_letters + string.digits):
    max_generation_attempts = 3
    prefix = prefix or ''
    ln = max_length - len(prefix)
    for i in range(1, max_generation_attempts + 1):
        try:
            # If only digits are used and no prefix specified,
            # ensure that first digit will never be 0
            if not prefix and chars in string.digits and '0' in chars:
                pure_uid = random.choice(str(chars).replace('0', ''))
                pure_uid += ''.join(random.choice(chars) for n in range(ln - 1))
            else:
                pure_uid = ''.join(random.choice(chars) for n in range(ln))

            # UIDs starting from '111' and 'aaa' are system-reserved and
            # should never be generated by application.
            if pure_uid.startswith('111') or pure_uid.lower().startswith('aaa'):
                raise IntegrityError(
                    'Can not generate UIDs starting from "111" or "aaa", '
                    'they are system-reserved.'
                )

            return prefix + pure_uid
        except IntegrityError:
            if i >= max_generation_attempts:
                raise
