"""Unique permutations is used to calculate the unique permutations of a list/vector and their count."""

from dataclasses import dataclass


@dataclass
class UniqueElement:
    """Class for unique elements to keep track of occurrences."""

    value: int
    occurrences: int


def unique_perms(elements: list[int]):
    r"""Determine the number of unique permutations of a list.

    Examples
    ==========

    Consider the following vector

    .. math::
        \left[1, 1, 2, 2, 1, 2, 1, 3, 3, 3\right].

    The number of possible permutations possible with the above vector is :math:`4200`. This can be
    obtained using the :code:`|toqito⟩` package as follows.

    .. jupyter-execute::

     from toqito.perms import unique_perms

     vec_nums = [1, 1, 2, 2, 1, 2, 1, 3, 3, 3]

     len(list(unique_perms(vec_nums)))



    :param elements: List of integers.
    :return: The number of possible permutations possible.

    """
    elem_set = set(elements)
    list_unique = [UniqueElement(value=i, occurrences=elements.count(i)) for i in elem_set]
    len_elems = len(elements)

    return perm_unique_helper(list_unique, [0] * len_elems, len_elems - 1)


def perm_unique_helper(list_unique: list[UniqueElement], result_list: list[int], elem_d: int):
    """Provide helper function for unique_perms.

    :param list_unique:
    :param result_list:
    :param elem_d:
    :return:
    """
    if elem_d < 0:
        yield tuple(result_list)
    else:
        for i in list_unique:
            if i.occurrences > 0:
                result_list[elem_d] = i.value
                i.occurrences -= 1
                yield from perm_unique_helper(list_unique, result_list, elem_d - 1)
                i.occurrences += 1
