from collections import OrderedDict
from datetime import timedelta

from django.conf import settings
from django.db import models
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _

from misago.core import threadstore
from misago.core.cache import cache
from misago.core.utils import time_amount


__all__ = [
    'RESTRICT_NO', 'RESTRICT_MODERATOR_REVIEW', 'RESTRICT_DISALLOW',
    'RESTRICTIONS_CHOICES', 'WarningLevel', 'UserWarning'
]


CACHE_NAME = 'misago_warning_levels'

RESTRICT_NO = 0
RESTRICT_MODERATOR_REVIEW = 1
RESTRICT_DISALLOW = 2


RESTRICTIONS_CHOICES = (
    (RESTRICT_NO, _("No restrictions")),
    (RESTRICT_MODERATOR_REVIEW, _("Review by moderator")),
    (RESTRICT_DISALLOW, _("Disallowed")),
)


class WarningLevelManager(models.Manager):
    def dict(self):
        return self.get_levels_from_threadstore()

    def get_levels_from_threadstore(self):
        levels = threadstore.get(CACHE_NAME, 'nada')
        if levels == 'nada':
            levels = self.get_levels_from_cache()
            threadstore.set(CACHE_NAME, levels)
        return levels

    def get_levels_from_cache(self):
        levels = cache.get(CACHE_NAME, 'nada')
        if levels == 'nada':
            levels = self.get_levels_from_database()
            cache.set(CACHE_NAME, levels)
        return levels

    def get_levels_from_database(self):
        levels = [(0, None)]
        for level, obj in enumerate(self.order_by('level')):
            levels.append((level + 1, obj))
        return OrderedDict(levels)


class WarningLevel(models.Model):
    name = models.CharField(max_length=255)
    level = models.PositiveIntegerField(default=1, db_index=True)
    length_in_minutes = models.PositiveIntegerField(default=0)
    restricts_posting_replies = models.PositiveIntegerField(
        default=RESTRICT_NO)
    restricts_posting_threads = models.PositiveIntegerField(
        default=RESTRICT_NO)

    objects = WarningLevelManager()

    def __unicode__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.pk:
            self.set_level()

        super(WarningLevel, self).save(*args, **kwargs)
        cache.delete(CACHE_NAME)

    def delete(self, *args, **kwargs):
        super(WarningLevel, self).delete(*args, **kwargs)
        cache.delete(CACHE_NAME)

    @property
    def length(self):
        if self.length_in_minutes:
            return time_amount(self.length_in_minutes * 60)
        else:
            return _("permanent")

    @property
    def has_restrictions(self):
        return self.restricts_posting_replies or self.restricts_posting_threads

    @property
    def is_replying_moderated(self):
        return self.restricts_posting_replies == RESTRICT_MODERATOR_REVIEW

    @property
    def is_replying_disallowed(self):
        return self.restricts_posting_replies == RESTRICT_DISALLOW

    @property
    def is_starting_threads_moderated(self):
        return self.restricts_posting_threads == RESTRICT_MODERATOR_REVIEW

    @property
    def is_starting_threads_disallowed(self):
        return self.restricts_posting_threads == RESTRICT_DISALLOW

    def set_level(self):
        try:
            self.level = WarningLevel.objects.latest('level').level + 1
        except WarningLevel.DoesNotExist:
            self.level = 1


class UserWarning(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             related_name="warnings")
    reason = models.TextField(null=True, blank=True)
    given_on = models.DateTimeField(default=timezone.now)
    giver = models.ForeignKey(settings.AUTH_USER_MODEL,
                              null=True, blank=True,
                              on_delete=models.SET_NULL,
                              related_name="warnings_given")
    giver_username = models.CharField(max_length=255)
    giver_slug = models.CharField(max_length=255)
    is_canceled = models.BooleanField(default=False)
    canceled_on = models.DateTimeField(null=True, blank=True)
    canceler = models.ForeignKey(settings.AUTH_USER_MODEL,
                                 null=True, blank=True,
                                 on_delete=models.SET_NULL,
                                 related_name="warnings_canceled")
    canceler_username = models.CharField(max_length=255)
    canceler_slug = models.CharField(max_length=255)

    def cancel(self, canceler):
        self.is_canceled = True
        self.canceled_on = timezone.now()
        self.canceler = canceler
        self.canceler_username = canceler.username
        self.canceler_slug = canceler.slug

        self.save(update_fields=(
            'is_canceled',
            'canceled_on',
            'canceler',
            'canceler_username',
            'canceler_slug',
        ))

    def is_expired(self, valid_for):
        return timezone.now() > self.given_on + timedelta(minutes=valid_for)