import random


def generate_chunks(total, min_val, max_val, num_chunks=-1):
    """
    Randomly generate a list of integers l such that sum(l) = total and for each x in l, min_val <= x <= max_val.
    If num_chunks > 0, it is guaranteed that the list contains exactly num_chunks elements.
    """

    if num_chunks <= 0:
        chunks = []
        while total > 0:
            next_chunk_size = random.randint(min(total, min_val), min(total, max_val))
            if 0 < total - next_chunk_size < min_val:
                continue
            total -= next_chunk_size
            chunks.append(next_chunk_size)
        return chunks
    else:
        if total < num_chunks * min_val:
            raise ValueError('Total ({}) must be >= num_chunks * min_val ({}*{})'.format(total, num_chunks, min_val))

        if total > num_chunks * max_val:
            raise ValueError('Total ({}) must be <= num_chunks * max_val ({}*{})'.format(total, num_chunks, max_val))

        total -= num_chunks * min_val
        chunks = None
        while not chunks or any([x > max_val for x in chunks]):
            split_points = [0, total]
            for _ in range(num_chunks - 1):
                split_points.append(random.randint(0, total))
            split_points.sort()
            chunks = [split_points[i + 1] - split_points[i] + min_val for i in range(len(split_points) - 1)]

        return chunks