# pylint: disable=C0330
from django.conf import settings
from django.contrib.auth import models as auth_models
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.template.loader import render_to_string
from django.utils import html
from rest_framework.authtoken.models import Token


class EmailUserManager(auth_models.UserManager):
    """
    An implementation of the UserManager that looks up based on email instead of based on username.
    """

    def _create_user(self, email, password, **extra_fields):  # pylint: disable=W0221
        if not email:
            raise ValueError("The given email must be set")
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_user(self, email, password, **extra_fields):  # pylint: disable=W0221
        extra_fields.setdefault("is_staff", False)
        extra_fields.setdefault("is_superuser", False)
        return self._create_user(email, password, **extra_fields)

    def create_superuser(
        self, email, password, **extra_fields
    ):  # pylint: disable=W0221
        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_superuser", True)
        extra_fields.setdefault("is_active", True)
        return self._create_user(email, password, **extra_fields)


class User(auth_models.AbstractUser):
    """
    A representation of a user within the registration system. Users are uniquely identified by their email,
    and are inactive until they confirm their email.
    """

    objects = EmailUserManager()

    # Set email to the primary lookup field
    email = models.EmailField(unique=True, null=False, blank=False)
    is_active = models.BooleanField(
        "active",
        default=False,
        help_text="Designates whether this user should be treated as active. Unselect "
        "this instead of deleting accounts.",
    )

    # Explicitly delete Django's old fields
    username = None
    first_name = None
    last_name = None

    # Day-of
    team = models.ForeignKey(
        "team.Team",
        null=True,
        blank=True,
        on_delete=models.CASCADE,
        related_name="members",
    )

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = []

    def send_html_email(self, template_name, context, subject):
        """Send an HTML email to the user."""
        html_msg = render_to_string(template_name, context)
        msg = html.strip_tags(html_msg)
        self.email_user(subject, msg, None, html_message=html_msg)


@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(
    sender, instance: User = None, created: bool = False, **kwargs
) -> None:
    """
    Using Django's model signals (https://docs.djangoproject.com/en/2.2/topics/signals/), creates a new Django Rest
    Framework Token for a newly-created user, for later use with Django Rest Framework's TokenAuthentication.
    See https://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication for more details.
    :param sender: The class that triggered this receiver (in this case, our User class)
    :param instance: The specific User that triggered this signal.
    :param created: Whether the user was created (or merely updated)
    :param kwargs: Other keyword arguments. See https://docs.djangoproject.com/en/2.2/topics/signals/ for more details.
    :return: None
    """
    if created:
        # This user was just created, they need a new Token!
        Token.objects.create(user=instance)