from core.utils.common import load_func
from core.validators import JSONSchemaValidator
from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import gettext_lazy as _
from labels_manager.models import LabelLink
from projects.models import Project
from tasks.models import Annotation, Task

# from labels_manager.serializers import LabelLinkSerializer, LabelSerializer
from .serializers_for_hooks import (
    OnlyIDWebhookSerializer,
)

HEADERS_SCHEMA = {
    'type': 'object',
    'patternProperties': {
        '^[a-zA-Z0-9-_]+$': {'type': 'string'},
    },
    'maxProperties': 10,
    'additionalProperties': False,
}


class Webhook(models.Model):
    """Model of webhooks.

    If webhook has not null project field -- it's project webhook
    """

    organization = models.ForeignKey('organizations.Organization', on_delete=models.CASCADE, related_name='webhooks')

    project = models.ForeignKey(
        'projects.Project', null=True, on_delete=models.CASCADE, related_name='webhooks', default=None
    )

    url = models.URLField(_('URL of webhook'), max_length=2048, help_text=_('URL of webhook'))

    send_payload = models.BooleanField(
        _('does webhook send the payload'),
        default=True,
        help_text=('If value is False send only action'),
    )

    send_for_all_actions = models.BooleanField(
        _('Use webhook for all actions'),
        default=True,
        help_text='If value is False - used only for actions from WebhookAction',
    )

    headers = models.JSONField(
        _('request extra headers of webhook'),
        validators=[JSONSchemaValidator(HEADERS_SCHEMA)],
        default=dict,
        help_text='Key Value Json of headers',
    )

    is_active = models.BooleanField(
        _('is webhook active'),
        default=True,
        help_text=('If value is False the webhook is disabled'),
    )

    created_at = models.DateTimeField(_('created at'), auto_now_add=True, help_text=_('Creation time'), db_index=True)
    updated_at = models.DateTimeField(_('updated at'), auto_now=True, help_text=_('Last update time'), db_index=True)

    def get_actions(self):
        return WebhookAction.objects.filter(webhook=self).values_list('action', flat=True)

    def validate_actions(self, actions):
        actions_meta = [WebhookAction.ACTIONS[action] for action in actions]
        if self.project and any((meta.get('organization-only') for meta in actions_meta)):
            raise ValidationError("Project webhook can't contain organization-only action.")
        return actions

    def set_actions(self, actions):
        if not actions:
            actions = set()
        actions = set(actions)
        old_actions = set(self.get_actions())

        for new_action in list(actions - old_actions):
            WebhookAction.objects.create(webhook=self, action=new_action)

        WebhookAction.objects.filter(webhook=self, action__in=(old_actions - actions)).delete()

    def has_permission(self, user):
        user.project = self.project  # link for activity log
        return self.organization.has_user(user)

    class Meta:
        db_table = 'webhook'


class WebhookAction(models.Model):
    PROJECT_CREATED = 'PROJECT_CREATED'
    PROJECT_UPDATED = 'PROJECT_UPDATED'
    PROJECT_DELETED = 'PROJECT_DELETED'

    TASKS_CREATED = 'TASKS_CREATED'
    TASKS_DELETED = 'TASKS_DELETED'

    ANNOTATION_CREATED = 'ANNOTATION_CREATED'
    ANNOTATIONS_CREATED = 'ANNOTATIONS_CREATED'
    ANNOTATION_UPDATED = 'ANNOTATION_UPDATED'
    ANNOTATIONS_DELETED = 'ANNOTATIONS_DELETED'

    LABEL_LINK_CREATED = 'LABEL_LINK_CREATED'
    LABEL_LINK_UPDATED = 'LABEL_LINK_UPDATED'
    LABEL_LINK_DELETED = 'LABEL_LINK_DELETED'

    ACTIONS = {
        PROJECT_CREATED: {
            'name': _('Project created'),
            'description': _(''),
            'key': 'project',
            'many': False,
            'model': Project,
            'serializer': load_func(settings.WEBHOOK_SERIALIZERS['project']),
            'organization-only': True,
        },
        PROJECT_UPDATED: {
            'name': _('Project updated'),
            'description': _(''),
            'key': 'project',
            'many': False,
            'model': Project,
            'serializer': load_func(settings.WEBHOOK_SERIALIZERS['project']),
            'project-field': '__self__',
        },
        PROJECT_DELETED: {
            'name': _('Project deleted'),
            'description': _(''),
            'key': 'project',
            'many': False,
            'model': Project,
            'serializer': OnlyIDWebhookSerializer,
            'organization-only': True,
        },
        TASKS_CREATED: {
            'name': _('Task created'),
            'description': _(''),
            'key': 'tasks',
            'many': True,
            'model': Task,
            'serializer': load_func(settings.WEBHOOK_SERIALIZERS['task']),
            'project-field': 'project',
        },
        TASKS_DELETED: {
            'name': _('Task deleted'),
            'description': _(''),
            'key': 'tasks',
            'many': True,
            'model': Task,
            'serializer': OnlyIDWebhookSerializer,
            'project-field': 'project',
        },
        ANNOTATION_CREATED: {
            'name': _('Annotation created'),
            'description': _(''),
            'key': 'annotation',
            'many': False,
            'model': Annotation,
            'serializer': load_func(settings.WEBHOOK_SERIALIZERS['annotation']),
            'project-field': 'project',
            'nested-fields': {
                'task': {
                    'serializer': load_func(settings.WEBHOOK_SERIALIZERS['task']),
                    'many': False,
                    'field': 'task',
                },
            },
        },
        ANNOTATIONS_CREATED: {
            'name': _('Annotations created'),
            'description': _(''),
            'key': 'annotation',
            'many': True,
            'model': Annotation,
            'serializer': load_func(settings.WEBHOOK_SERIALIZERS['annotation']),
            'project-field': 'project',
            'nested-fields': {
                'task': {
                    'serializer': load_func(settings.WEBHOOK_SERIALIZERS['task']),
                    'many': True,
                    'field': 'task',
                },
            },
        },
        ANNOTATION_UPDATED: {
            'name': _('Annotation updated'),
            'description': _(''),
            'key': 'annotation',
            'many': False,
            'model': Annotation,
            'serializer': load_func(settings.WEBHOOK_SERIALIZERS['annotation']),
            'project-field': 'project',
            'nested-fields': {
                'task': {
                    'serializer': load_func(settings.WEBHOOK_SERIALIZERS['task']),
                    'many': False,
                    'field': 'task',
                },
            },
        },
        ANNOTATIONS_DELETED: {
            'name': _('Annotation deleted'),
            'description': _(''),
            'key': 'annotations',
            'many': True,
            'model': Annotation,
            'serializer': OnlyIDWebhookSerializer,
            'project-field': 'project',
        },
        LABEL_LINK_CREATED: {
            'name': _('Label link created'),
            'description': _(''),
            'key': 'label_link',
            'many': True,
            'model': LabelLink,
            'serializer': load_func(settings.WEBHOOK_SERIALIZERS['label_link']),
            'project-field': 'project',
        },
        LABEL_LINK_UPDATED: {
            'name': _('Label link updated'),
            'description': _(''),
            'key': 'label_link',
            'many': False,
            'model': LabelLink,
            'serializer': load_func(settings.WEBHOOK_SERIALIZERS['label_link']),
            'project-field': 'project',
            'nested-fields': {
                'label': {
                    'many': False,
                    'field': 'label',
                    'serializer': load_func(settings.WEBHOOK_SERIALIZERS['label']),
                },
            },
        },
        LABEL_LINK_DELETED: {
            'name': _('Label link deleted'),
            'description': _(''),
            'key': 'label_link',
            'many': False,
            'model': LabelLink,
            'serializer': OnlyIDWebhookSerializer,
            'project-field': 'project',
        },
    }

    webhook = models.ForeignKey(Webhook, on_delete=models.CASCADE, related_name='actions')

    action = models.CharField(
        _('action of webhook'),
        choices=[[key, value['name']] for key, value in ACTIONS.items()],
        max_length=128,
        db_index=True,
        help_text=_('Action value'),
    )

    class Meta:
        db_table = 'webhook_action'
        unique_together = [['webhook', 'action']]
