# -*- coding: utf-8 -*-


import re
import warnings

from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import Q
from django.db.models.expressions import RawSQL
from django.utils.translation import gettext_lazy

from .abstract_applicationkeyvalue import AbstractApplicationKeyValue
from .abstract_is_admin import AbstractIsAdmin
from devilry.devilry_account.models import User
from .period import Period
from . import period_tag


class BulkCreateFromEmailsResult(object):
    """
    Return value of :meth:`.AbstractRelatedUserManager.bulk_create_from_emails`.

    .. attribute:: created_relatedusers_queryset

        Queryset with all the created related users.

    .. attribute:: existing_relateduser_emails_set

        Set of the email of related users that was NOT created.

    .. attribute:: created_users_queryset

        Queryset with all the created users. Warning: this
        **is not** the created **related** users, it is the
        :class:`devilry.devilry_account.User` objects that was
        created.

    .. attribute:: existing_user_emails_set

        Set of the email of the :class:`~devilry.devilry_account.User` objects
        that was NOT created. If all the users already had a User object,
        this will include all the email addresses provided to the method.

    """

    def __init__(self, modelclass, created_users_queryset, existing_user_emails_set,
                 created_relatedusers_queryset,
                 existing_relateduser_emails_set):
        self.__modelclass = modelclass
        self.created_users_queryset = created_users_queryset
        self.existing_user_emails_set = existing_user_emails_set
        self.created_relatedusers_queryset = created_relatedusers_queryset
        self.existing_relateduser_emails_set = existing_relateduser_emails_set

    def new_users_was_created(self):
        return self.created_users_queryset.exists()

    def new_relatedusers_was_created(self):
        return self.created_relatedusers_queryset.exists()

        # def get_existing_relatedusers_queryset(self):
        #     return self.__modelclass.objects.filter(
        #         user__useremail__email__in=self.existing_relateduser_emails_set).distinct()


class BulkCreateFromUsernamesResult(object):
    """
    Return value of :meth:`.AbstractRelatedUserManager.bulk_create_from_usernames`.

    .. attribute:: created_relatedusers_queryset

        Queryset with all the created related users.

    .. attribute:: existing_relateduser_usernames_set

        Set of the username of related users that was NOT created.

    .. attribute:: created_users_queryset

        Queryset with all the created users. Warning: this
        **is not** the created **related** users, it is the
        :class:`devilry.devilry_account.User` objects that was
        created.

    .. attribute:: existing_user_usernames_set

        Set of the username of the :class:`~devilry.devilry_account.User` objects
        that was NOT created. If all the users already had a User object,
        this will include all the username addresses provided to the method.

    """

    def __init__(self, modelclass, created_users_queryset, existing_user_usernames_set,
                 created_relatedusers_queryset,
                 existing_relateduser_usernames_set):
        self.__modelclass = modelclass
        self.created_users_queryset = created_users_queryset
        self.existing_user_usernames_set = existing_user_usernames_set
        self.created_relatedusers_queryset = created_relatedusers_queryset
        self.existing_relateduser_usernames_set = existing_relateduser_usernames_set

    def new_users_was_created(self):
        return self.created_users_queryset.exists()

    def new_relatedusers_was_created(self):
        return self.created_relatedusers_queryset.exists()

        # def get_existing_relatedusers_queryset(self):
        #     return self.__modelclass.objects.filter(
        #         user__username__username__in=self.existing_relateduser_usernames_set).distinct()


class AbstractRelatedUserManager(models.Manager):
    """
    Base class for the managers for related users.
    """

    def bulk_create_from_emails(self, period, emails):
        """
        Bulk create related student/examiner for all the emails in the given ``emails`` iterator.

        Uses :meth:`devilry.devilry_account.models.UserManager.bulk_create_from_emails`
        to create any non-existing users.

        Raises:
            devilry_account.exceptions.IllegalOperationError: If the
                ``CRADMIN_LEGACY_USE_EMAIL_AUTH_BACKEND``-setting is ``False``.

        Returns:
            :class:`.BulkCreateFromEmailsResult` object with detailed information about
            the created users, created related users, and the users and related users
            that was not created.
        """
        existing_relateduser_emails_set = set(self.model.objects.filter(
            period=period,
            user__useremail__email__in=emails).values_list('user__useremail__email', flat=True))
        all_relateduser_emails_set = set(emails)
        new_relateduser_emails_set = all_relateduser_emails_set.difference(existing_relateduser_emails_set)

        created_users_queryset, existing_user_emails_set = get_user_model().objects.bulk_create_from_emails(
            new_relateduser_emails_set)

        new_relateduser_objects = []
        new_relateduser_users_queryset = get_user_model().objects.filter_by_emails(new_relateduser_emails_set)
        for user in new_relateduser_users_queryset:
            new_relateduser = self.model(period=period, user=user)
            new_relateduser_objects.append(new_relateduser)
        self.model.objects.bulk_create(new_relateduser_objects)
        created_relatedusers_queryset = self.model.objects.filter(
            period=period,
            user__in=new_relateduser_users_queryset)

        return BulkCreateFromEmailsResult(
            modelclass=self.model,
            created_users_queryset=created_users_queryset,
            existing_user_emails_set=existing_user_emails_set,
            created_relatedusers_queryset=created_relatedusers_queryset,
            existing_relateduser_emails_set=existing_relateduser_emails_set)

    def bulk_create_from_usernames(self, period, usernames):
        """
        Bulk create related student/examiner for all the usernames in the given ``usernames`` iterator.

        Uses :meth:`devilry.devilry_account.models.UserManager.bulk_create_from_usernames`
        to create any non-existing users.

        Raises:
            devilry_account.exceptions.IllegalOperationError: If the
                ``CRADMIN_LEGACY_USE_EMAIL_AUTH_BACKEND``-setting is ``True``.

        Returns:
            :class:`.BulkCreateFromUsernamesResult` object with detailed information about
            the created users, created related users, and the users and related users
            that was not created.
        """
        existing_relateduser_usernames_set = set(self.model.objects.filter(
            period=period,
            user__username__username__in=usernames).values_list('user__username__username', flat=True))
        all_relateduser_usernames_set = set(usernames)
        new_relateduser_usernames_set = all_relateduser_usernames_set.difference(
            existing_relateduser_usernames_set)

        created_users_queryset, existing_user_usernames_set = get_user_model().objects \
            .bulk_create_from_usernames(
            new_relateduser_usernames_set)

        new_relateduser_objects = []