import math
from django.conf import settings
from django.db import models, connection, transaction
from django.utils.translation import ugettext_lazy as _

class Rank(models.Model):
    """
    Misago User Rank
    Ranks are ready style/title pairs that are assigned to users either by admin (special ranks) or as result of user activity.
    """
    name = models.CharField(max_length=255)
    slug = models.CharField(max_length=255, null=True, blank=True)
    description = models.TextField(null=True, blank=True)
    style = models.CharField(max_length=255, null=True, blank=True)
    title = models.CharField(max_length=255, null=True, blank=True)
    special = models.BooleanField(default=False)
    as_tab = models.BooleanField(default=False)
    on_index = models.BooleanField(default=False)
    order = models.IntegerField(default=0)
    criteria = models.CharField(max_length=255, null=True, blank=True)
    roles = models.ManyToManyField('Role')

    class Meta:
        app_label = 'misago'

    def __unicode__(self):
        return unicode(_(self.name))

    def assign_rank(self, users=0, special_ranks=None):
        if not self.criteria or self.special or users == 0:
            # Rank cant be rolled in
            return False

        if self.criteria == "0":
            # Just update all fellows
            User.objects.exclude(rank__in=special_ranks).update(rank=self)
        else:
            # Count number of users to update
            if self.criteria[-1] == '%':
                criteria = int(self.criteria[0:-1])
                criteria = int(math.ceil(float(users / 100.0) * criteria))
            else:
                criteria = int(self.criteria)

            # Join special ranks
            if special_ranks:
                special_ranks = ','.join(special_ranks)

            # Run raw query
            cursor = connection.cursor()
            try:
                # Postgresql
                if (settings.DATABASES['default']['ENGINE'] == 'django.db.backends.postgresql_psycopg2'
                    or settings.DATABASES['default']['ENGINE'] == 'django.db.backends.postgresql'):
                    if special_ranks:
                        cursor.execute('''UPDATE misago_user
                            FROM (
                                SELECT id
                                FROM misago_user
                                WHERE rank_id NOT IN (%s)
                                ORDER BY score DESC LIMIT %s
                                ) AS updateable
                            SET rank_id=%s
                            WHERE id = updateable.id
                            RETURNING *''' % (self.id, special_ranks, criteria))
                    else:
                        cursor.execute('''UPDATE misago_user
                            FROM (
                                SELECT id
                                FROM misago_user
                                ORDER BY score DESC LIMIT %s
                                ) AS updateable
                            SET rank_id=%s
                            WHERE id = updateable.id
                            RETURNING *''', [self.id, criteria])

                # MySQL, SQLite and Oracle
                if (settings.DATABASES['default']['ENGINE'] == 'django.db.backends.mysql'
                    or settings.DATABASES['default']['ENGINE'] == 'django.db.backends.sqlite3'
                    or settings.DATABASES['default']['ENGINE'] == 'django.db.backends.oracle'):
                    if special_ranks:
                        cursor.execute('''UPDATE misago_user
                            SET rank_id=%s
                            WHERE rank_id NOT IN (%s)
                            ORDER BY score DESC
                            LIMIT %s''' % (self.id, special_ranks, criteria))
                    else:
                        cursor.execute('''UPDATE misago_user
                        SET rank_id=%s
                        ORDER BY score DESC
                        LIMIT %s''', [self.id, criteria])
            except Exception as e:
                print 'Error updating users ranking: %s' % e

            transaction.commit_unless_managed()

        return True
