import re
import time
from poplib import POP3

from EmailLibrary.base import LibraryComponent, keyword


class ReceiveKeywords(LibraryComponent):
    time_out = 300

    def __init__(self, ctx):
        LibraryComponent.__init__(self, ctx)

    @keyword
    def listen_to_mail_account(self, account_id=None):
        account = self.account(account_id)

        pop_client = POP3(account.pop3_host, account.pop3_port)
        pop_client.user(account.login_name)
        pop_client.pass_(account.login_pass)

        stat = pop_client.stat()
        pop_client.quit()
        account.set_pop_listener(stat)

    @keyword
    def exist_new_mail_with_subject(self, subject, account_id=None):
        def check_func(content):
            return len(re.findall(subject, content)) > 0
        mail_index = self.exist_new_mail_with_header(account_id, check_func)
        self.info('Find mail at index {}.'.format(mail_index))

    @keyword
    def exist_new_mail_with_message_id(self, message_id, account_id=None):
        def check_func(content):
            return len(re.findall(message_id, content)) > 0
        mail_index = self.exist_new_mail_with_header(account_id, check_func)
        self.info('Find mail at index {}.'.format(mail_index))

    def exist_new_mail_with_header(self, account_id, check_func):
        account = self.account(account_id)
        listen_start = account.pop3_listener
        time_start = time.time()
        time_end = time_start + self.time_out

        pop_client = POP3(account.pop3_host, account.pop3_port)
        pop_client.user(account.login_name)
        pop_client.pass_(account.login_pass)

        while True:
            if time.time() > time_end:
                break

            listen_end = pop_client.stat()[0]
            for i in range(listen_start, listen_end + 1):
                headers = pop_client.top(i, 0)[1]
                for header in headers:
                    if check_func(header):
                        return i
            listen_start = listen_end

        raise AssertionError('No corresponding mail received.')
