from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission

from ..models import Account


User = get_user_model()


def _create_user_and_account(user_attrs, account_attrs, perms=None):
    """
    Create a user and its account, and assign permissions to this user.

    Arguments
        user_attrs (dict): User data (first name, last name, password...).
        account_attrs (dict): Account data (department, kfet password...).
        perms (list of str: 'app.perm'): These permissions will be assigned to
            the created user. No permission are assigned by default.

    If 'password' is not given in 'user_attrs', username is used as password.

    If 'kfet.is_team' is in 'perms' and 'password' is not in 'account_attrs',
    the account password is 'kfetpwd_<user pwd>'.

    """
    user_pwd = user_attrs.pop('password', user_attrs['username'])
    user = User.objects.create(**user_attrs)
    user.set_password(user_pwd)
    user.save()

    account_attrs['cofprofile'] = user.profile
    kfet_pwd = account_attrs.pop('password', 'kfetpwd_{}'.format(user_pwd))

    account = Account.objects.create(**account_attrs)

    if perms is not None:
        user = user_add_perms(user, perms)

        if 'kfet.is_team' in perms:
            account.change_pwd(kfet_pwd)
            account.save()

    return user


def create_user(username='user', trigramme='000', **kwargs):
    """
    Create a user without any permission and its kfet account.

    username and trigramme are accepted as arguments (defaults to 'user' and
    '000').

    user_attrs, account_attrs and perms can be given as keyword arguments to
    customize the user and its kfet account.

    # Default values

    User
        * username: user
        * password: user
        * first_name: first
        * last_name: last
        * email: mail@user.net
    Account
        * trigramme: 000

    """
    user_attrs = kwargs.setdefault('user_attrs', {})

    user_attrs.setdefault('username', username)
    user_attrs.setdefault('first_name', 'first')
    user_attrs.setdefault('last_name', 'last')
    user_attrs.setdefault('email', 'mail@user.net')

    account_attrs = kwargs.setdefault('account_attrs', {})
    account_attrs.setdefault('trigramme', trigramme)

    return _create_user_and_account(**kwargs)


def create_team(username='team', trigramme='100', **kwargs):
    """
    Create a user, member of the kfet team, and its kfet account.

    username and trigramme are accepted as arguments (defaults to 'team' and
    '100').

    user_attrs, account_attrs and perms can be given as keyword arguments to
    customize the user and its kfet account.

    # Default values

    User
        * username: team
        * password: team
        * first_name: team
        * last_name: member
        * email: mail@team.net
    Account
        * trigramme: 100
        * kfet password: kfetpwd_team

    """
    user_attrs = kwargs.setdefault('user_attrs', {})

    user_attrs.setdefault('username', username)
    user_attrs.setdefault('first_name', 'team')
    user_attrs.setdefault('last_name', 'member')
    user_attrs.setdefault('email', 'mail@team.net')

    account_attrs = kwargs.setdefault('account_attrs', {})
    account_attrs.setdefault('trigramme', trigramme)

    perms = kwargs.setdefault('perms', [])
    perms.append('kfet.is_team')

    return _create_user_and_account(**kwargs)


def create_root(username='root', trigramme='200', **kwargs):
    """
    Create a superuser and its kfet account.

    username and trigramme are accepted as arguments (defaults to 'root' and
    '200').

    user_attrs, account_attrs and perms can be given as keyword arguments to
    customize the user and its kfet account.

    # Default values

    User
        * username: root
        * password: root
        * first_name: super
        * last_name: user
        * email: mail@root.net
        * is_staff, is_superuser: True
    Account
        * trigramme: 200
        * kfet password: kfetpwd_root

    """
    user_attrs = kwargs.setdefault('user_attrs', {})

    user_attrs.setdefault('username', username)
    user_attrs.setdefault('first_name', 'super')
    user_attrs.setdefault('last_name', 'user')
    user_attrs.setdefault('email', 'mail@root.net')
    user_attrs['is_superuser'] = user_attrs['is_staff'] = True

    account_attrs = kwargs.setdefault('account_attrs', {})
    account_attrs.setdefault('trigramme', trigramme)

    return _create_user_and_account(**kwargs)


def get_perms(*labels):
    """Return Permission instances from a list of '<app>.<perm_codename>'."""
    perms = {}
    for label in set(labels):
        app_label, codename = label.split('.', 1)
        perms[label] = Permission.objects.get(
            content_type__app_label=app_label,
            codename=codename,
        )
    return perms


def user_add_perms(user, perms_labels):
    """
    Add perms to a user.

    Args:
        user (User instance)
        perms (list of str 'app.perm_name')

    Returns:
        The same user (refetched from DB to avoid missing perms)

    """
    perms = get_perms(*perms_labels)
    user.user_permissions.add(*perms.values())

    # If permissions have already been fetched for this user, we need to reload
    # it to avoid using of the previous permissions cache.
    # https://docs.djangoproject.com/en/1.11/topics/auth/default/#permission-caching
    return User.objects.get(pk=user.pk)
