from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.utils.translation import ugettext_lazy as _

from pretalx.mail.models import MailTemplate, QueuedMail
from pretalx.submission.models import Answer, AnswerOption, CfP, Question, Submission

LOG_NAMES = {
    'pretalx.cfp.update': _('The CfP has been modified.'),
    'pretalx.event.create': _('The event has been added.'),
    'pretalx.event.update': _('The event was modified.'),
    'pretalx.event.activate': _('The event was made public.'),
    'pretalx.event.deactivate': _('The event was deactivated.'),
    'pretalx.event.plugins.enabled': _('A plugin was enabled.'),
    'pretalx.event.plugins.disabled': _('A plugin was disabled.'),
    'pretalx.invite.orga.accept': _('The invitation to the event orga was accepted.'),
    'pretalx.invite.orga.retract': _('An invitation to the event orga was retracted.'),
    'pretalx.invite.orga.send': _('An invitation to the event orga was sent.'),
    'pretalx.invite.reviewer.retract': _(
        'The invitation to the review team was retracted.'
    ),
    'pretalx.invite.reviewer.send': _('The invitation to the review team was sent.'),
    'pretalx.event.invite.orga.accept': _(
        'The invitation to the event orga was accepted.'
    ),  # compat
    'pretalx.event.invite.orga.retract': _(
        'An invitation to the event orga was retracted.'
    ),  # compat
    'pretalx.event.invite.orga.send': _(
        'An invitation to the event orga was sent.'
    ),  # compat
    'pretalx.event.invite.reviewer.retract': _(
        'The invitation to the review team was retracted.'
    ),  # compat
    'pretalx.event.invite.reviewer.send': _(
        'The invitation to the review team was sent.'
    ),  # compat
    'pretalx.mail.create': _('An email was modified.'),
    'pretalx.mail.delete': _('A pending email was deleted.'),
    'pretalx.mail.delete_all': _('All pending emails were deleted.'),
    'pretalx.mail.sent': _('An email was sent.'),
    'pretalx.mail.update': _('An email was modified.'),
    'pretalx.mail_template.create': _('A mail template was added.'),
    'pretalx.mail_template.delete': _('A mail template was deleted.'),
    'pretalx.mail_template.update': _('A mail template was modified.'),
    'pretalx.question.create': _('A question was added.'),
    'pretalx.question.delete': _('A question was deleted.'),
    'pretalx.question.update': _('A question was modified.'),
    'pretalx.question.option.create': _('A question option was added.'),
    'pretalx.question.option.delete': _('A question option was deleted.'),
    'pretalx.question.option.update': _('A question option was modified.'),
    'pretalx.room.create': _('A new room was added.'),
    'pretalx.schedule.release': _('A new schedule version was released.'),
    'pretalx.submission.accept': _('The submission was accepted.'),
    'pretalx.submission.cancel': _('The submission was cancelled.'),
    'pretalx.submission.confirm': _('The submission was confirmed.'),
    'pretalx.submission.confirmation': _('The submission was confirmed.'),  # Legacy
    'pretalx.submission.create': _('The submission was added.'),
    'pretalx.submission.deleted': _('The submission was deleted.'),
    'pretalx.submission.reject': _('The submission was rejected.'),
    'pretalx.submission.resource.create': _('A submission resource was added.'),
    'pretalx.submission.resource.delete': _('A submission resource was deleted.'),
    'pretalx.submission.resource.update': _('A submission resource was modified.'),
    'pretalx.submission.speakers.add': _('A speaker was added to the submission.'),
    'pretalx.submission.speakers.invite': _('A speaker was invited to the submission.'),
    'pretalx.submission.speakers.remove': _(
        'A speaker was removed from the submission.'
    ),
    'pretalx.submission.unconfirm': _('The submission was unconfirmed.'),
    'pretalx.submission.update': _('The submission was modified.'),
    'pretalx.submission.withdraw': _('The submission was withdrawn.'),
    'pretalx.submission.answer.update': _('A submission answer was modified.'),
    'pretalx.submission.answerupdate': _('A submission answer was modified.'),  # compat
    'pretalx.submission.answer.create': _('A submission answer was added.'),
    'pretalx.submission.answercreate': _('A submission answer was added.'),
    'pretalx.submission_type.create': _('A submission type was added.'),
    'pretalx.submission_type.delete': _('A submission type was deleted.'),
    'pretalx.submission_type.make_default': _('The submission type was made default.'),
    'pretalx.submission_type.update': _('A submission type was modified.'),
    'pretalx.track.create': _('A track was added.'),
    'pretalx.track.delete': _('A track was deleted.'),
    'pretalx.track.update': _('A track was modified.'),
    'pretalx.speaker.arrived': _('A speaker has been marked as arrived.'),
    'pretalx.speaker.unarrived': _('A speaker has been marked as not arrived.'),
    'pretalx.user.token.reset': _('The API token was reset.'),
    'pretalx.user.password.reset': _('The password was reset.'),
    'pretalx.user.password.update': _('The password was modified.'),
    'pretalx.user.profile.update': _('The profile was modified.'),
}


class ActivityLog(models.Model):
    """This model logs actions within an event.

    It is **not** designed to provide a complete or reliable audit trail."""
    event = models.ForeignKey(
        to='event.Event',
        on_delete=models.PROTECT,
        related_name='log_entries',
        null=True,
        blank=True,
    )
    person = models.ForeignKey(
        to='person.User',
        on_delete=models.PROTECT,
        related_name='log_entries',
        null=True,
        blank=True,
    )
    content_type = models.ForeignKey(to=ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField(db_index=True)
    content_object = GenericForeignKey('content_type', 'object_id')
    timestamp = models.DateTimeField(auto_now_add=True, db_index=True)
    action_type = models.CharField(max_length=200)
    data = models.TextField(null=True, blank=True)
    is_orga_action = models.BooleanField(default=False)

    class Meta:
        ordering = ('-timestamp',)

    def __str__(self):
        """Custom __str__ to help with debugging."""
        event = getattr(self.event, 'slug', 'None')
        person = getattr(self.person, 'name', 'None')
        return f'ActivityLog(event={event}, person={person}, content_object={self.content_object}, action_type={self.action_type})'

    def display(self):
        response = LOG_NAMES.get(self.action_type)
        if response is None:
            import logging

            logger = logging.getLogger(__name__)
            logger.warning(f'Unknown log action "{self.action_type}".')
            return self.action_type
        return response

    def get_public_url(self) -> str:
        """Returns a public URL to the object in question (if any)."""
        if isinstance(self.content_object, Submission):
            return self.content_object.urls.public
        if isinstance(self.content_object, CfP):
            return self.content_object.urls.public
        return ''

    def get_orga_url(self) -> str:
        """Returns an organiser backend URL to the object in question (if any)."""
        if isinstance(self.content_object, Submission):
            return self.content_object.orga_urls.base
        if isinstance(self.content_object, Question):
            return self.content_object.urls.base
        if isinstance(self.content_object, AnswerOption):
            return self.content_object.question.urls.base
        if isinstance(self.content_object, Answer):
            if self.content_object.submission:
                return self.content_object.submission.orga_urls.base
            return self.content_object.question.urls.base
        if isinstance(self.content_object, CfP):
            return self.content_object.urls.text
        if isinstance(self.content_object, (MailTemplate, QueuedMail)):
            return self.content_object.urls.base
        return ''
