import re
import operator


def extract_emails(smtp, required=True, count=None, one=False, regex=False, **kwargs):
    """Extract emails from an smtp outbox.

    :param smtp: The `smtp` fixture from the testcase
    :param required: Fail if no matching emails were found
    :param count: Require exactly `count` emails to be found
    :param one: Require exactly one email to be found
    :param kwargs: Header values to match against
    :return: list of emails, unless `one` is true in which
             case the matching email or `None` is returned
    """
    if one:
        if count is not None:
            raise ValueError('Cannot specify both `count` and `one`')
        count = 1
    compare = re.search if regex else operator.eq
    found = []
    for mail in smtp.outbox:
        for header, value in kwargs.items():
            if not compare(value, mail[header]):
                break
        else:  # everything matched
            found.append(mail)
    found_set = set(found)
    smtp.outbox = [mail for mail in smtp.outbox if mail not in found_set]
    __tracebackhide__ = True
    if required:
        assert found, 'No matching emails found'
    if count is not None:
        assert len(found) == count, 'Expected {} emails, got {}'.format(count, len(found))
    if one:
        return found[0] if found else None
    return found