# coding: utf-8
from hashlib import md5

from django.db import models
from django.utils import timezone
from django.contrib.auth.models import UserManager
from django.contrib.auth.models import (AbstractBaseUser, PermissionsMixin)
from django.utils.translation import ugettext_lazy as _


class User(AbstractBaseUser,
           PermissionsMixin):
    """

    """
    MALE = 'male'
    FEMALE = 'female'
    GENDER_CHOICES = (
        (MALE, _('Male')),
        (FEMALE, _('Female'))
    )

    @property
    def avatar(self):
        avatar = '{}{}?s=300'.format(
            'https://www.gravatar.com/avatar/',
            md5(self.email.lower()).hexdigest()
        )
        return avatar

    email = models.EmailField(
        verbose_name=_('Email address'),
        max_length=255,
        unique=True,
        db_index=True,
        help_text=_('An user email that should be verified.')
    )

    username = models.CharField(
        verbose_name=_('Username'),
        max_length=128,
        unique=True,
        db_index=True,
    )

    # personal info
    first_name = models.CharField(
        verbose_name=_('First name'),
        max_length=80, blank=True, default='',
    )

    last_name = models.CharField(
        verbose_name=_('Last name'),
        max_length=80, blank=True, default='',
    )

    birthdate = models.DateField(
        verbose_name=_('Birthdate'),
        null=True,
        blank=True,
        default=None,
    )

    gender = models.CharField(
        verbose_name=_('Gender'),
        max_length=80,
        choices=GENDER_CHOICES,
        blank=True,
        default=''
    )

    date_joined = models.DateTimeField(
        verbose_name=_('Date joined'),
        auto_now_add=True,
        editable=False,
    )

    is_active = models.BooleanField(
        verbose_name=_('Active status'),
        default=True,
        help_text=_('Designates whether this user should be treated as '
                    'active. Unselect this instead of deleting accounts.')
    )

    is_staff = models.BooleanField(
        verbose_name=_('Staff status'),
        default=False,
        help_text=_('Designates whether the user can log into this admin '
                    'site.')
    )

    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ('email',)

    # Access codes / Invitations
    access_code = models.ForeignKey('account.AccessCode',
                                    null=True, blank=True,
                                    related_name='used_by')

    objects = UserManager()

    class Meta:
        verbose_name = _('User')

    def __unicode__(self):
        return unicode(self.username) or unicode(self.email)

    @property
    def is_confirmed(self):
        return self.CONFIRMED == self.status

    @property
    def full_name(self):
        return '{first_name} {last_name}'.format(
            first_name=self.first_name.strip(),
            last_name=self.last_name.strip()
        )

    @property
    def age(self):
        """Age of the user

        Returns the age of the user if she has a defined birthdate.
        """
        if self.birthdate is None:
            return None
        else:
            today = timezone.now()
            birthdate = self.birthdate
            try:
                birthdate.replace(year=today.year)
            except ValueError:
                # Raises only with 29th February and current not leap year
                birthdate_day = 28
            else:
                birthdate_day = birthdate.day
            return today.year - birthdate.year - (
                (today.month, today.day) < (birthdate.month, birthdate_day)
            )


class AccessCode(models.Model):
    code = models.CharField(_('Code'), max_length=128)
    max_uses = models.IntegerField(_('Number of uses'), default=1)
    user = models.ForeignKey(User, null=True, blank=True,
                             related_name='access_codes')
    expiration = models.DateTimeField(_('Expires'), null=True, blank=True,
                                      default=None)
    active = models.BooleanField(_('Active'), default=True)

    class Meta:
        verbose_name = _('Access code')
        verbose_name_plural = _('Access codes')

    def __unicode__(self):
        return self.code

    @property
    def uses(self):
        return self.used_by.count()

    @property
    def usable(self):
        # Check if active
        if not self.active:
            return False

        # Check if expired
        if self.expiration and (timezone.now() >= self.expiration):
            return False

        # Check if it someone already used it
        if self.used_by.count() == self.max_uses:
            return False

        return True
