from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models


# Create your models here.


class Topic(models.Model):
    topic = models.CharField(max_length=128, help_text='Topic you are subscribing to.')
    arn = models.CharField(max_length=255, blank=True, null=True, editable=False)

    created = models.DateTimeField(auto_now_add=True, db_index=True)
    modified = models.DateTimeField(auto_now=True, db_index=True)

    class Meta:
        verbose_name = "Topic"
        verbose_name_plural = "Topics"

    def __str__(self):
        return self.topic

    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        try:
            from .topic_providers import MessageWrapper
            mw = MessageWrapper.get('sns')
            arn = mw.create_topic(topic=self.topic)
            self.arn = arn.arn
        except Exception as e:
            pass  # todo: log this issue
        super().save(force_insert, force_update, using, update_fields)


class TopicCallback(models.Model):
    TYPES = (
        ('https', 'HTTPS',),
        ('http', 'HTTP',),
        ('email', 'Email',),
        ('lambda', 'AWS Lambda',),
        ('sqs', 'Amazon SQS',),
    )
    topic = models.ForeignKey(Topic, on_delete=models.SET_NULL, related_name='subscriptions', null=True)
    protocol = models.CharField(max_length=32, choices=TYPES)
    callback = models.URLField(max_length=255, help_text='Fully qualified callback URI that messages for the topic will\
     be pushed to')
    enabled = models.BooleanField(default=True)  # future use to disable the subscription
    arn = models.CharField(max_length=255, blank=True, null=True, editable=False)

    created = models.DateTimeField(auto_now_add=True, db_index=True)
    modified = models.DateTimeField(auto_now=True, db_index=True)

    class Meta:
        verbose_name = "Topic Callback"
        verbose_name_plural = "Topic Callbacks"

    def __str__(self):
        return self.topic.__str__()

    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        try:
            if self.enabled is True:
                from .topic_providers import MessageWrapper
                mw = MessageWrapper.get('sns')
                arn = mw.subscribe(topic=self.topic.topic, protocol=self.protocol, endpoint=self.callback)
                self.arn = arn.arn
        except Exception as e:
            pass  # TODO: Add some kind of logging to make system aware of this failure
        super().save(force_insert, force_update, using, update_fields)


class Message(models.Model):
    topic = models.ForeignKey(Topic, on_delete=models.SET_NULL, null=True, related_name='sent_messages')
    message = models.JSONField()
    subject = models.CharField(max_length=128, blank=True, null=True)
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, related_name='sent_messages', null=True)
    object_id = models.CharField(max_length=128, null=True)
    source = GenericForeignKey('content_type', 'object_id')
    message_id = models.UUIDField(null=True, )

    created = models.DateTimeField(auto_now_add=True, db_index=True)

    class Meta:
        verbose_name = "SentMessage"
        verbose_name_plural = "SentMessages"

    def __str__(self):
        return self.topic.__str__()

    @classmethod
    def publish_message(cls, topic: str, message, subject: str = None, source=None, *args, **kwargs):
        from .topic_providers import MessageWrapper
        mw = MessageWrapper.get('sns')
        topic, created = Topic.objects.get_or_create(topic=topic)
        _message = cls(topic=topic, message=message, subject=subject, source=source)
        try:
            resp = mw.publish(topic, message, subject=subject, *args, **kwargs)
            _message.message_id = resp['MessageId']
        except Exception as e:
            print(e)
            pass  # todo: add some kind of logging for this failure
        _message.save()
