"""Management command to handle file generation."""

import os
import datetime

from django.core.management.base import BaseCommand
from django.utils import timezone

from modoboa.admin.models import Domain
from modoboa.core.models import User
from modoboa.parameters import tools as param_tools

from ... import models
from ...modo_extension import Radicale


class Command(BaseCommand):
    """Management command to handle file generation."""

    help = "Generate Radicale rights file"

    def add_arguments(self, parser):
        """Add extra arguments to command line."""
        parser.add_argument(
            "--force", action="store_true", default=False,
            help="Force generation of rights file")

    def _generate_acr(self, name, user, collection, perm="rw", comment=None):
        """Write a new access control rule to the config file."""
        if comment is not None:
            self._cfgfile.write("\n# %s" % comment)
        self._cfgfile.write("""
[%s]
user = %s
collection = %s
permissions = %s
""" % (name, user, collection, perm)
        )

    def _user_access_rules(self):
        """Create user access rules."""
        for acr in models.AccessRule.objects.select_related().all():
            section = "%s-to-%s-acr" % (
                acr.mailbox, acr.calendar
            )
            permission = ""
            if acr.read:
                permission += "r"
            if acr.write:
                permission += "w"
            self._generate_acr(
                section, acr.mailbox.full_address, acr.calendar.path,
                permission,
            )

    def _token_access_rules(self):
        """Create token access rules."""
        for model in [models.UserCalendar, models.SharedCalendar]:
            for calendar in model.objects.all():
                section = "token-{}-access".format(calendar._path)
                self._generate_acr(
                    section, calendar.access_token, calendar._path, perm="r",
                    comment="Read-only access using a token"
                )

    def _super_admin_rules(self):
        """Generate access rules for super administrators."""
        for sa in User.objects.filter(is_superuser=True):
            section = "sa-%s-acr" % sa.username
            self._generate_acr(
                section, sa.username, ".*"
            )

    def _domain_admin_rules(self):
        """Generate access rules for domain adminstrators."""
        for da in User.objects.filter(groups__name="DomainAdmins"):
            for domain in Domain.objects.get_for_admin(da):
                section = "da-%s-to-%s-acr" % (da.email, domain.name)
                self._generate_acr(
                    section, da.email, "%s/user/.*" % domain.name
                )

    def _generate_file(self, target):
        """
        A user must not declare a rule for his direct admin!
        """
        self._cfgfile = open(target, "w")
        self._cfgfile.write("""# Rights management file for Radicale
# This file was generated by Modoboa on %s
# DO NOT EDIT MANUALLY!
        """ % datetime.datetime.today())

        allow_calendars_administration = param_tools.get_global_parameter(
            "allow_calendars_administration", app="modoboa_radicale")
        if allow_calendars_administration:
            self._super_admin_rules()
            self._domain_admin_rules()

        # self._generate_acr(
        #     "domain-shared-calendars", r"^(.+)@(.+)$", r"{1}/.+$",
        #     comment="Access rule to domain shared calendars"
        # )
        self._generate_acr(
            "principal", r".+", r"{user}", perm="RW",
            comment="Allow reading and writing principal collection "
            "(same as user name)"
        )
        self._generate_acr(
            "calendars", r".+", r"{user}/[^/]+",
            comment="Allow reading and writing calendars and address books "
            "that are direct children of the principal collection"
        )

        self._user_access_rules()
        self._token_access_rules()
        self._cfgfile.close()

    def handle(self, *args, **options):
        """Command entry point."""
        Radicale().load()
        path = param_tools.get_global_parameter(
            "rights_file_path", app="modoboa_radicale")
        if not options["force"]:
            try:
                mtime = datetime.datetime.fromtimestamp(
                    int(os.path.getmtime(path))
                )
            except OSError:
                pass
            else:
                tz = timezone.get_current_timezone()
                qset = models.AccessRule.objects.filter(
                    last_update__gt=mtime.replace(tzinfo=tz))
                if not qset.exists():
                    return
        self._generate_file(path)
