import os

from django.utils import timezone
from django.utils.translation import ugettext_lazy as _

from orchestra.apps.orchestration import ServiceController
from orchestra.apps.resources import ServiceMonitor

from . import settings
from .models import Address


class MailSystemUserBackend(ServiceController):
    verbose_name = _("Mail system user")
    model = 'mails.Mailbox'
    # TODO related_models = ('resources__content_type') ??
    
    DEFAULT_GROUP = 'postfix'
    
    def create_user(self, context):
        self.append(
            "if [[ $( id %(username)s ) ]]; then \n"
            "   usermod -p '%(password)s' %(username)s \n"
            "else \n"
            "   useradd %(username)s --password '%(password)s' \\\n"
            "       --shell /dev/null \n"
            "fi" % context
        )
        self.append("mkdir -p %(home)s" % context)
        self.append("chown %(username)s.%(group)s %(home)s" % context)
    
    def generate_filter(self, mailbox, context):
        now = timezone.now().strftime("%B %d, %Y, %H:%M")
        context['filtering'] = (
            "# Sieve Filter\n"
            "# Generated by Orchestra %s\n\n" % now
        )
        if mailbox.use_custom_filtering:
            context['filtering'] += mailbox.custom_filtering
        else:
            context['filtering'] += settings.EMAILS_DEFAUL_FILTERING
        context['filter_path'] = os.path.join(context['home'], '.orchestra.sieve')
        self.append("echo '%(filtering)s' > %(filter_path)s" % context)
    
    def save(self, mailbox):
        context = self.get_context(mailbox)
        self.create_user(context)
        self.generate_filter(mailbox, context)
    
    def delete(self, mailbox):
        context = self.get_context(mailbox)
        self.append("{ sleep 2 && killall -u %(username)s -s KILL; } &" % context)
        self.append("killall -u %(username)s" % context)
        self.append("userdel %(username)s" % context)
        self.append("rm -fr %(home)s" % context)
    
    def get_context(self, mailbox):
        context = {
            'name': mailbox.nam,
            'username': mailbox.name,
            'password': mailbox.password if mailbox.is_active else '*%s' % mailbox.password,
            'group': self.DEFAULT_GROUP
        }
        context['home'] = settings.EMAILS_HOME % context
        return context


class PostfixAddressBackend(ServiceController):
    verbose_name = _("Postfix address")
    model = 'mails.Address'
    
    def include_virtdomain(self, context):
        self.append(
            '[[ $(grep "^\s*%(domain)s\s*$" %(virtdomains)s) ]]'
            '   || { echo "%(domain)s" >> %(virtdomains)s; UPDATED=1; }' % context
        )
    
    def exclude_virtdomain(self, context):
        domain = context['domain']
        if not Address.objects.filter(domain=domain).exists():
            self.append('sed -i "s/^%(domain)s//" %(virtdomains)s' % context)
    
    def update_virtusertable(self, context):
        self.append(
            'LINE="%(email)s\t%(destination)s"\n'
            'if [[ ! $(grep "^%(email)s\s" %(virtusertable)s) ]]; then\n'
            '   echo "$LINE" >> %(virtusertable)s\n'
            '   UPDATED=1\n'
            'else\n'
            '   if [[ ! $(grep "^${LINE}$" %(virtusertable)s) ]]; then\n' 
            '       sed -i "s/^%(email)s\s.*$/${LINE}/" %(virtusertable)s\n'
            '       UPDATED=1\n'
            '   fi\n'
            'fi' % context
        )
    
    def exclude_virtusertable(self, context):
        self.append(
            'if [[ $(grep "^%(email)s\s") ]]; then\n'
            '   sed -i "s/^%(email)s\s.*$//" %(virtusertable)s\n'
            '   UPDATED=1\n'
            'fi'
        )
    
    def save(self, address):
        context = self.get_context(address)
        self.include_virtdomain(context)
        self.update_virtusertable(context)
    
    def delete(self, address):
        context = self.get_context(address)
        self.exclude_virtdomain(context)
        self.exclude_virtusertable(context)
    
    def commit(self):
        context = self.get_context_files()
        self.append('[[ $UPDATED == 1 ]] && { '
                    'postmap %(virtdomains)s;'
                    'postmap %(virtusertable)s;'
                    '}' % context)
    
    def get_context_files(self):
        return {
            'virtdomains': settings.EMAILS_VIRTDOMAINS_PATH,
            'virtusertable': settings.EMAILS_VIRTUSERTABLE_PATH,
        }
    
    def get_context(self, address):
        context = self.get_context_files()
        context.update({
            'domain': address.domain,
            'email': address.email,
            'destination': address.destination,
        })
        return context


class AutoresponseBackend(ServiceController):
    verbose_name = _("Mail autoresponse")
    model = 'mail.Autoresponse'


class MaildirDisk(ServiceMonitor):
    model = 'mails.Mailbox'
    resource = ServiceMonitor.DISK
    verbose_name = _("Maildir disk usage")
    
    def monitor(self, mailbox):
        context = self.get_context(mailbox)
        self.append(
            "SIZE=$(sed -n '2p' %(maildir_path)s | cut -d' ' -f1)\n"
            "echo %(object_id)s ${SIZE:-0}" % context
        )
    
    def get_context(self, mailbox):
        context = MailSystemUserBackend().get_context(mailbox)
        context['home'] = settings.EMAILS_HOME % context
        context['maildir_path'] = os.path.join(context['home'], 'Maildir/maildirsize')
        context['object_id'] = mailbox.pk
        return context
