from .dice import Dice, mod
from .op import Op
from .roll import max_roll, min_roll


def simplify_dice(*expression: Dice) -> list[Dice]:
    """Join adjacent plus and minus mods together.

    :param list[Dice] expression: the dice expression to simplify
    :return: the simplfied dice expression

    >>> from ndice import d6, minus, plus
    >>> simplify_dice(d6, plus(3), minus(1))
    [Dice(1, 6), Dice(2, 1)]
    """
    original_max = max_roll(*expression)
    original_min = min_roll(*expression)

    simplified = []
    mods_found: list[Dice] = []

    def coalesce_mods_found() -> None:
        nonlocal simplified, mods_found
        if mods_found:
            total = max_roll(*mods_found)
            if total:
                simplified.append(mod(total))
            mods_found = []

    for dice in expression:
        if dice.is_mod:
            if Op.TIMES == dice.op:
                coalesce_mods_found()
                simplified.append(dice)
            else:
                mods_found.append(dice)
        else:
            coalesce_mods_found()
            simplified.append(dice)
    coalesce_mods_found()

    assert max_roll(*simplified) == original_max
    assert min_roll(*simplified) == original_min

    return simplified
