"""This module holds the managers and QuerySets for the ``accounts`` app."""

from django.contrib.auth.models import UserManager
from django.db import models

from mtp.apps.sync.managers import SyncableQuerySet

from .constants import (
    GROUPTYPE_BUSINESS_UNIT,
    GROUPTYPE_INTERNAL,
    GROUPTYPE_JOB_PROFILE,
    INTERNAL_GROUP_TRAINER,
    INTERNAL_GROUP_TRAINEE,
    POTENTIAL_DUPLICATE_REASONS,
)


class GroupTypeQuerySet(SyncableQuerySet, models.QuerySet):
    """Base queryset class for ``GroupType``s."""

    def internal(self):
        """Return only internal group types.

        Returns
        -------
        Queryset of ``mtp.apps.accounts.models.GroupType``

        """
        return self.filter(name=GROUPTYPE_INTERNAL)

    def job_profiles(self):
        """Return only group types representing job profiles.

        Returns
        -------
        Queryset of ``mtp.apps.accounts.models.GroupType``

        """
        return self.filter(name=GROUPTYPE_JOB_PROFILE)


class GroupTypeManager(models.Manager):
    pass


class GroupManager(models.Manager):
    """
    The manager for the auth's Group model.

    """

    def get_by_natural_key(self, name):
        return self.get(name=name)


class GroupQuerySet(SyncableQuerySet, models.QuerySet):
    """QuerySet for the ``mtp.apps.accounts.models.Group`` model."""

    def is_training_filter(self):
        """Return only group who can be used as a training filter.

        Returns
        -------
        Queryset of ``mtp.apps.accounts.models.Group``

        """
        return self.filter(type__is_training_filter=True)

    def managed_by(self, user):
        """Filter the groups which are managed by the provided user

        Parameters
        ----------
        user : mtp.apps.accounts.models.MTPUser
            The user for whom we want the managed groups.

        Returns
        -------
        GroupQueryset
            A clone of the original queryset (``self``), annotated.

        """

        from .models import GroupRole

        return self.filter(
            member_roles__role=GroupRole.ROLES.MANAGER,
            member_roles__user=user
        )

    def business_units(self):
        """Return only group who are business units.

        Returns
        -------
        Queryset of ``mtp.apps.accounts.models.Group``

        """
        return self.filter(type__name=GROUPTYPE_BUSINESS_UNIT)

    def job_profiles(self):
        """Return only group who are job profiles.

        Returns
        -------
        Queryset of ``mtp.apps.accounts.models.Group``

        """
        return self.filter(type__name=GROUPTYPE_JOB_PROFILE)


class GroupRoleManager(models.Manager):
    """The manager for the ``GroupRole`` model."""

    pass


class MTPUserQuerySet(SyncableQuerySet, models.QuerySet):
    """QuerySet for the ``mtp.apps.accounts.models.MTPUser`` model."""

    def active(self):
        """Return only users who are active.

        Returns
        -------
        Queryset of ``mtp.apps.accounts.models.MTPUser``

        """

        return self.filter(is_active=True)

    def originals(self):
        """Return only the users who are not flagged as a duplicate

        Returns
        -------
        MTPUserQueryset
            The original QuerySet, filtered.

        """

        from mtp.apps.accounts.models import DuplicatedMTPUser

        duplicate_ids = DuplicatedMTPUser.objects.values_list('duplicate_user_id', flat=True)

        return self.exclude(id__in=duplicate_ids)

    def trainers(self):
        """Return only users who belongs to the trainer group.

        Returns
        -------
        Queryset of ``mtp.apps.accounts.models.MTPUser``

        """

        return self.filter(mgroups__name=INTERNAL_GROUP_TRAINER)

    def trainees(self):
        """Return only users who belongs to the trainee group.

        Returns
        -------
        Queryset of ``mtp.apps.accounts.models.MTPUser``

        """

        return self.filter(mgroups__name=INTERNAL_GROUP_TRAINEE)


class MTPUserManager(UserManager.from_queryset(MTPUserQuerySet)):
    """Manager for the ``mtp.apps.accounts.models.MTPUser`` model."""

    def get_potential_duplicates(self, user):
        """Get the potential duplicates of a given user

        Parameters
        ----------
        user: MTPUser
            The user for whom we want to find the duplicates

        Returns
        -------
        dict
            A dict containing the potential duplicate user as the key,
            and the reason we think this user might be a duplicate.

        """

        potential_duplicate_users = {}

        # Find the users with the same first and last name as our given user
        same_last_and_first_name_users = self.non_deleted().filter(
            first_name__iexact=user.first_name,
            last_name__iexact=user.last_name,
            external_id=''
        ).exclude(
            id=user.id,
        )

        for duser in same_last_and_first_name_users:
            potential_duplicate_users[duser] = POTENTIAL_DUPLICATE_REASONS.SAME_LAST_AND_FIRST_NAME

        # Find the users with a conflicting username
        conflicting_username_users = self.non_deleted().filter(
            old_username=user.username
        )

        for duser in conflicting_username_users:
            potential_duplicate_users[duser] = POTENTIAL_DUPLICATE_REASONS.USERNAME_CONFLICT

        return potential_duplicate_users
