from __future__ import absolute_import

from fnmatch import fnmatch as glob
import logging
import re
import shlex
import uuid

from celery import shared_task
from django.utils.timezone import now
from django_mailbox.models import Message

from .context_managers import git_checkpoint

logger = logging.getLogger(__name__)


@shared_task(
    bind=True,
    soft_time_limit=30,
    time_limit=45,
    default_retry_delay=60,
    max_retries=2,
    ignore_result=True,
)
def sync_repository(self, store_id, debounce_id=None):
    from .models import TaskStore
    store = TaskStore.objects.get(pk=store_id)
    try:
        store.sync(
            async=False,
            function='tasks.sync_repository',
            args=(store_id, ),
            kwargs={'debounce_id': debounce_id},
        )
    except:
        if self.retries == 2:
            store.log_error(
                "An unexpected error was encountered while synchronizing "
                "your tasks with the taskd server. Synchronization has been "
                "temporarily disabled for your account, and an administrator "
                "has been notified."
            )
            store.sync_enabled = False
            store.save()
        raise


@shared_task(
    bind=True,
    soft_time_limit=30,
    time_limit=45,
    ignore_result=True,
)
def process_email_message(self, message_id):
    from .models import TaskStore

    def get_secret_id_and_args(address):
        inbox_id = address[0:36]
        args = []

        arg_string = address[36:]
        for arg in re.split('__|\+', arg_string):
            if not arg:
                continue
            if '=' in arg:
                args.append(
                    '%s:"%s"' % tuple(arg.split('='))
                )
            else:
                args.append('+%s' % arg)

        return inbox_id, args

    message = Message.objects.get(pk=message_id)
    message.read = now()
    message.save()

    store = None
    additional_args = []
    for address in message.to_addresses:
        try:
            inbox_id, additional_args = get_secret_id_and_args(
                address.split('@')[0]
            )

            store = TaskStore.objects.get(
                secret_id=inbox_id
            )
            break
        except (TaskStore.DoesNotExist, IndexError):
            pass

    if store is None:
        logger.error(
            "Could not find task store for e-mail message (ID %s) addressed "
            "to %s",
            message.pk,
            message.to_addresses
        )
        return

    allowed = False
    for address in store.email_whitelist.split('\n'):
        if glob(message.from_address[0], address):
            allowed = True

    if not allowed:
        log_args = (
            "Incoming task creation e-mail (ID: %s) from '%s' "
            "does not match email whitelist and was ignored." % (
                message.pk,
                message.from_address[0]
            ),
        )
        logger.info(*log_args)
        store.log_message(*log_args)
        return

    if (
        not message.subject
        or message.subject.lower() in ['add', 'create', 'new'],
    ):
        task_id = str(uuid.uuid4())
        with git_checkpoint(store, 'Incoming E-mail'):
            task_args = [
                'add',
                'uuid:%s' % task_id,
                'intheamoriginalemailsubject:"%s"' % message.subject,
                'intheamoriginalemailid:%s' % message.pk,
            ] + additional_args + shlex.split(message.text)

        stdout, stderr = store.client._execute_safe(*task_args)

        log_args = (
            "Added task %s via e-mail %s from %s." % (
                task_id,
                message.pk,
                message.from_address[0]
            ),
        )
        logger.info(*log_args)
        store.log_message(*log_args)
    else:
        log_args = (
            "Unable to process e-mail %s from %s; unknown subject '%s'" % (
                message.pk,
                message.from_address[0],
                message.subject,
            ),
        )
        logger.info(*log_args)
        store.log_message(*log_args)

@@ -421,27 +421,8 @@
 60,%0A
-    max_retries=2,%0A
     
@@ -437,24 +437,24 @@
 esult=True,%0A
+
 )%0Adef sync_r
@@ -779,16 +779,31 @@
   except
+ Exception as e
 :%0A      
@@ -820,17 +820,17 @@
 retries 
-=
+%3E
 = 2:%0A   
@@ -1214,13 +1214,49 @@
     
-raise
+else:%0A            raise self.retry(exc=e)
 %0A%0A%0A@

Handle retries in a much more reasonable way.