import uuid
from django.contrib.auth.models import AbstractUser, BaseUserManager
from django.db import models
from django.utils.translation import gettext_lazy as _
from model_utils.models import TimeStampedModel, TimeFramedModel

from core.utils import generate_random_string


class MyUserManager(BaseUserManager):
    def create_user(self, email, date_of_birth, password=None):
        """
        Creates and saves a User with the given email, date of
        birth and password.
        """
        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(
            email=self.normalize_email(email),
            date_of_birth=date_of_birth,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, date_of_birth, password=None):
        """
        Creates and saves a superuser with the given email, date of
        birth and password.
        """
        user = self.create_user(
            email,
            password=password,
            date_of_birth=date_of_birth,
        )
        user.is_admin = True
        user.save(using=self._db)
        return user



class User(AbstractUser):
    email = models.EmailField(_("email address"), blank=False, unique=True)
    uid = models.UUIDField(blank=False, null=False, verbose_name=_('UUID'))

    objects = MyUserManager()

    REQUIRED_FIELDS = ['email']

    class Meta:
        verbose_name = _('User')
        verbose_name_plural = _('Users')

    def __str__(self):
        if self.get_full_name():
            return self.get_full_name()
        else:
            return self.email

    def save(self, *args, **kwargs):
        if not self.uid:
            self.uid = uuid.uuid4()
        super(User, self).save(*args, **kwargs)


class ConfirmationCode(TimeStampedModel):
    email = models.EmailField(_("email address"), blank=True, null=True)
    code = models.CharField(max_length=50, blank=False, null=False, unique=True, verbose_name=_('Code'))
    registration_id = models.IntegerField(blank=True, null=True, verbose_name=_('Registration ID'))

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

    def __str__(self):
        return self.code


class SecurityCode(TimeStampedModel):
    email = models.EmailField(_("email address"), unique=True, blank=True, null=True)
    code = models.CharField(max_length=10, blank=False, null=False, unique=True, verbose_name=_('Code'))

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

    def __str__(self):
        return self.email

    def save(self, *args, **kwargs):
        def generate_code():
            # check if code is already in table
            code = generate_random_string(10)
            if SecurityCode.objects.filter(code=code).exists():
                generate_code()

            return code

        if not self.code:
            self.code = generate_code()

        super(SecurityCode, self).save(*args, **kwargs)





def get_or_create_user(email):
    password = None
    try:
        user, created = User.objects.get_or_create(email=email, username=email)
        # if user does not have a password, generate one
        if created:
            password = generate_random_string(8)
            user.set_password(password)
            user.save()
        return user, password
    except User.MultipleObjectsReturned:
        return User.objects.filter(email=email).first(), password
    except Exception as e:
        raise e


