def trimmer(
    scores: list,
    counts: list,
    direction: int = 0,
    threshold: int = 3,
    frac_retain: float = 0.9,
) -> int:
    """
    Trimmer takes scores and direction as input and returns the position where
    the sequence has to be trimmed in that direction

    Parameters
    ---------
    scores : list
        List of scores for each baseid. Scores are 'good', 'warning' or 'failure'
    counts : list
        Number of sequences used to calculate scores for each baseid
    direction : {0, 1}, optional
        The direction for trimming. 0 is left, 1 is right
        Default value is 0
    threshold : int, optional
        The minimum number of good bases that need to appear in sequence to stop trimming
        Default value is 5
    frac_retain : float, optional
        The minimum fraction of sequences that need to be retained after trimming

    Returns
    ------
    int
        The position where the sequence is to be trimmed in the given direction
    """
    ord_scores = scores if direction == 0 else scores[::-1]
    nseqs = counts[0]
    count_fracs = [c / nseqs for c in counts]
    try:
        retain_fail_pos = next(
            ind for ind, c in enumerate(count_fracs) if c < frac_retain
        )
    except StopIteration:
        retain_fail_pos = len(scores)
    stop_flag = 0
    pos = len(scores)
    for i, score in enumerate(ord_scores):
        if stop_flag <= -threshold:
            stop_flag = 0
        if stop_flag >= threshold:
            pos = i - threshold
            break
        elif score == "good":
            stop_flag += 1
        elif score == "warning":
            stop_flag += 0
        elif score == "failure":
            stop_flag -= 1
    direct_pos = pos if direction == 0 else len(scores) - pos
    return direct_pos if direction == 0 else min(direct_pos, retain_fail_pos)