from django.contrib.auth.models import Group
from django.db import models
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _

from mayan.apps.databases.model_mixins import ExtraDataModelMixin
from mayan.apps.events.decorators import method_event
from mayan.apps.events.event_managers import EventManagerSave

from .events import event_role_created, event_role_edited
from .managers import RoleManager, StoredPermissionManager
from .model_mixins import (
    RoleBusinessLogicMixin, StoredPermissionBusinessLogicMixin
)


class Role(ExtraDataModelMixin, RoleBusinessLogicMixin, models.Model):
    """
    This model represents a Role. Roles are permission units. They are the
    only object to which permissions can be granted. They are themselves
    containers too, containing Groups, which are organization units. Roles
    are the basic method to grant a permission to a group. Permissions granted
    to a group using a role, are granted for the entire system.
    """
    label = models.CharField(
        help_text=_('A short text describing the role.'), max_length=128,
        unique=True, verbose_name=_('Label')
    )
    permissions = models.ManyToManyField(
        related_name='roles', to='StoredPermission',
        verbose_name=_('Permissions')
    )
    groups = models.ManyToManyField(
        related_name='roles', to=Group, verbose_name=_('Groups')
    )

    objects = RoleManager()

    class Meta:
        ordering = ('label',)
        verbose_name = _('Role')
        verbose_name_plural = _('Roles')

    def __str__(self):
        return self.label

    def get_absolute_url(self):
        return reverse(viewname='permissions:role_list')

    def natural_key(self):
        return (self.label,)
    natural_key.dependencies = ['auth.Group', 'permissions.StoredPermission']

    @method_event(
        event_manager_class=EventManagerSave,
        created={
            'event': event_role_created,
            'target': 'self',
        },
        edited={
            'event': event_role_edited,
            'target': 'self',
        }
    )
    def save(self, *args, **kwargs):
        return super().save(*args, **kwargs)


class StoredPermission(StoredPermissionBusinessLogicMixin, models.Model):
    """
    This model is the counterpart of the permissions.classes.Permission
    class. Allows storing a database counterpart of a permission class.
    It is used to store the permissions help by a role or in an ACL.
    """
    namespace = models.CharField(
        max_length=64, verbose_name=_('Namespace')
    )
    name = models.CharField(
        max_length=64, verbose_name=_('Name')
    )

    objects = StoredPermissionManager()

    class Meta:
        ordering = ('namespace',)
        unique_together = ('namespace', 'name')
        verbose_name = _('Permission')
        verbose_name_plural = _('Permissions')

    def __str__(self):
        return str(self.label)

    def get_absolute_url(self):
        return reverse(
            viewname='permissions:stored_permission_detail', kwargs={
                'stored_permission_id': self.pk
            }
        )

    def natural_key(self):
        return (self.namespace, self.name)
