"""Karma logging models."""

from datetime import timedelta
import logging
import pytz

from irc.client import NickMask

from django.conf import settings
from django.db import models
from django.utils import timezone

log = logging.getLogger('karma.models')


def perdelta(start, end, delta):
    curr = start
    while curr < end:
        yield curr
        curr += delta
    yield end


class KarmaKeyManager(models.Manager):

    """Manage handy queries for KarmaKey."""

    def ranked_scored_order(self):
        keys = self.annotate(karma_score=models.Sum('karmalogentry__delta')).order_by('-karma_score')
        return keys

    def ranked_scored_reverse_order(self):
        keys = self.annotate(karma_score=models.Sum('karmalogentry__delta')).order_by('karma_score')
        return keys


class KarmaKey(models.Model):

    """Track a thing being karmaed."""

    key = models.CharField(max_length=200, unique=True)

    objects = KarmaKeyManager()

    def __str__(self):
        """String representation."""

        return "{0:s} ({1:d})".format(self.key, self.score())

    def score(self):
        """Determine the score for this karma entry."""

        return KarmaLogEntry.objects.filter(key=self).aggregate(models.Sum('delta'))['delta__sum']

    def rank(self):
        """Determine the rank of this karma entry relative to the others."""

        sorted_keys = KarmaKey.objects.ranked_scored_order()
        for rank, key in enumerate(sorted_keys):
            if key == self:
                return rank+1
        return None

    def history(self, mode='delta'):
        """Determine the score for this karma entry at every delta."""

        history = []

        if mode == 'delta':
            entries = KarmaLogEntry.objects.filter(key=self).order_by('created')
            for entry in entries:
                timestamp = entry.created
                delta = entry.delta
                score = KarmaLogEntry.objects.filter(key=self).filter(created__lte=entry.created).aggregate(
                    models.Sum('delta'))['delta__sum']

                history.append((timestamp, delta, score))
        elif mode == 'date':
            first_entry = KarmaLogEntry.objects.filter(key=self).order_by('created')[0]
            slice_begin = first_entry.created.date()
            slice_end = timezone.now().date()
            for timeslice in perdelta(slice_begin, slice_end, timedelta(days=1)):
                score = KarmaLogEntry.objects.filter(key=self).filter(
                    created__lte=timeslice+timedelta(days=1)).aggregate(models.Sum('delta'))['delta__sum']
                if not score:
                    score = 0
                try:
                    prev_score = history[-1][2]
                except IndexError:
                    prev_score = 0

                delta = score - prev_score

                history.append((timeslice, delta, score))

        return history


class KarmaLogEntryManager(models.Manager):

    """Manage handy queries for KarmaLogEntry."""

    def optimists(self):
        karmaers = self.values('nickmask').annotate(karma_outlook=models.Sum('delta')).order_by('-karma_outlook')
        return karmaers

    def pessimists(self):
        karmaers = self.values('nickmask').annotate(karma_outlook=models.Sum('delta')).order_by('karma_outlook')
        return karmaers

    def most_opinionated(self):
        karmaers = self.values('nickmask').annotate(karma_count=models.Count('delta')).order_by('-karma_count')
        return karmaers


class KarmaLogEntry(models.Model):

    """Track each karma increment/decrement."""

    key = models.ForeignKey('KarmaKey')
    delta = models.SmallIntegerField()
    nickmask = models.CharField(max_length=200, default='', blank=True)
    created = models.DateTimeField(auto_now_add=True)

    objects = KarmaLogEntryManager()

    class Meta:
        verbose_name_plural = 'karma log entries'

    def __str__(self):
        """String representation."""

        tz = pytz.timezone(settings.TIME_ZONE)
        return "{0:s}{1:s} @ {2:s} by {3:s}".format(self.key.key, '++' if self.delta > 0 else '--',
                                                    self.created.astimezone(tz).strftime('%Y-%m-%d %H:%M:%S %Z'),
                                                    NickMask(self.nickmask).nick)