from __future__ import unicode_literals

from uuid import uuid4
import datetime

from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.db import models
from timezone_field import TimeZoneField
from django.utils import timezone
from django.core.urlresolvers import reverse
import pytz

from authenticating.email import VerifyUserEmail
from bennedetto.utils import expand_url_path


def get_default_timezone():
    return pytz.timezone('US/Central')


class PasswordsDontMatch(Exception):
    pass


class IncorrectPassword(Exception):
    pass


class UserManager(BaseUserManager):
    def create_user(self, email, password=None):
        user = self.model(email=email)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password):
        user = self.model(email=email)
        user.set_password(password)
        user.is_staff = True
        user.save()
        return user

    def midnight(self, now=None):
        '''
        returns all users that are *currently* experiencing
        the first hour of their day
        '''
        now = now or datetime.datetime.now(pytz.utc)
        zones = [tz for tz in pytz.common_timezones_set
                 if now.astimezone(pytz.timezone(tz)).hour == 0]
        return self.filter(timezone__in=zones)

    def verify(self, key):
        user = self.get(verify_key=key)
        user.verified = True
        user.save()


class User(AbstractBaseUser):
    PasswordsDontMatch = PasswordsDontMatch
    IncorrectPassword = IncorrectPassword

    objects = UserManager()

    id = models.UUIDField(primary_key=True,
                          unique=True,
                          editable=False,
                          default=uuid4)

    email = models.EmailField(unique=True)
    verified = models.BooleanField(default=False)
    verify_key = models.UUIDField(default=uuid4, editable=False, unique=True)
    timezone = TimeZoneField(default=get_default_timezone)
    is_staff = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    def get_full_name(self):
        return self.get_short_name()

    def get_short_name(self):
        return self.email

    def has_perm(self, *args, **kwargs):
        return self.is_staff

    def has_module_perms(self, *args):
        return self.is_staff

    def activate_timezone(self):
        timezone.activate(self.timezone)

    def send_verification_email(self):
        if self.verified:
            return False
        VerifyUserEmail(user=self).send()

    def get_verify_link(self):
        key = str(self.verify_key)
        path = reverse('verify', args=[key])
        return expand_url_path(path)

    def change_password(self, old, new):
        new, new_copy = new
        if not new == new_copy:
            raise self.PasswordsDontMatch

        if not self.check_password(old):
            raise self.IncorrectPassword

        self.set_password(new)

        self.save()
        return self


class FamilyManager(models.Manager):
    def create_from_user(self, user, name):
        family = self.create(name=name)
        membership = Membership.objects.create(user=user,
                                               family=family,
                                               admin=True)
        return membership.save()


class Family(models.Model):
    objects = FamilyManager()

    name = models.CharField(max_length=120)
    members = models.ManyToManyField(User, through='Membership')

    def __unicode__(self):
        return self.name

    def invite_user_to_family(self, email=None):
        user = User.objects.create(email=email, is_active=False)
        Membership(user=user, family=self, admin=False).save()
        return user.save()

    class Meta:
        verbose_name_plural = 'Families'


class Membership(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    family = models.ForeignKey(Family, on_delete=models.CASCADE)
    admin = models.BooleanField(default=False)

    def __unicode__(self):
        return '{0} Membership'.format(self.family.__unicode__())

    @property
    def family_name(self):
        return self.family.name

    @property
    def email(self):
        return self.user.email

    @property
    def verified(self):
        return self.user.verified