"""This module holds the api-related views of the ``accounts`` app"""

from django.conf import settings
from django.contrib.auth import authenticate, get_user_model, login, logout
from django.http import Http404
from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext
from django.views.generic import View
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST

from rest_framework.response import Response
from rest_framework.views import APIView

from mtp.apps.api.constants import BAD_REQUEST_HTTP_RESPONSE, EMPTY_HTTP_RESPONSE
from mtp.apps.common.utils import strip_accents
from mtp.apps.common.views_utils import CrsfExemptMixin
from mtp.apps.trainings.models import TrainingSession

from ..forms import AvatarForm
from ..models import (
    Group,
    GroupRole,
    MTPUser
)

from .serializers import UserSerializer


@csrf_exempt
def do_login(request):
    try:
        username = request.POST['login']
        password = request.POST['pass']
    except KeyError:
        return BAD_REQUEST_HTTP_RESPONSE

    try:
        _user = get_user_model().objects.get(username=username)

        # if not _user.is_staff:
        #     _user.set_password(password)
        #     _user.save()

    # TODO: Except what ?
    except:

        # _user = get_user_model().objects.create_user(username, '', password)

        return BAD_REQUEST_HTTP_RESPONSE

    user_obj = authenticate(username=username, password=password)
    if user_obj is not None:
        login(request, user_obj)
    else:
        return BAD_REQUEST_HTTP_RESPONSE

    return render_to_response(
        'api/json/login.json', dict(locals(), user=user_obj),
        content_type='application/json',
        context_instance=RequestContext(request),
    )


class LogoutView(CrsfExemptMixin, View):
    """API view to logout the current user"""

    def post(self, request, *args, **kwargs):  # pylint: disable=unused-argument
        """Logout the user and return an empty response

        For the parameters, see ``django.views.generic.View``

        Notes
        -----
        Django ``logout`` method don't throw any exception if the user
        wasn't actually authenticated (ex: AnonymousUser).

        """

        logout(request)

        return EMPTY_HTTP_RESPONSE


@csrf_exempt
def user(request, user_uuid, session_uuid=None):
    user_obj = get_user_model().objects.get(id=user_uuid)

    if request.method == 'POST':
        if 'first_name' in request.POST:
            first_name = request.POST['first_name']
            user_obj.first_name = first_name
        if 'last_name' in request.POST:
            last_name = request.POST['last_name']
            user_obj.last_name = last_name
        if 'mail' in request.POST:
            mail = request.POST['mail']
            user_obj.email = mail

        if 'business' in request.POST:
            business = request.POST['business']
            user_obj.business = business
        if 'dr' in request.POST:
            user_obj.dr = request.POST['dr']

        avatarForm = AvatarForm(request.POST, request.FILES)

        if avatarForm.is_valid():
            new_photo = avatarForm.save()
            user_obj.photo = new_photo
            user_obj.photos.add(new_photo)

        user_obj.save()

    if session_uuid is not None:
        session = get_object_or_404(TrainingSession, pk=session_uuid)
        notes = user_obj.note_set.filter(training_session=session)
    else:
        notes = user_obj.note_set.all()

    return render_to_response(
        'api/json/user.json', dict(locals(), user=user_obj),
        content_type='application/json',
        context_instance=RequestContext(request),
    )


@require_POST
@csrf_exempt
def users_list(request):
    """Register a user, possibly adding them to a training session."""

    username = 'login' in request.POST and request.POST['login'] or None
    if username:
        username = strip_accents(username.lower())

    first_name = request.POST['first_name']
    last_name = request.POST['last_name']
    password = request.POST['pass']
    email = 'mail' in request.POST and request.POST['mail'] or None

    try:

        # If the user already exists, there is nothing to do.
        user_obj = get_user_model().objects.get(
            username=username or strip_accents((
                '%s%s' % (first_name[:1], last_name)
            ).lower())
        )
        return BAD_REQUEST_HTTP_RESPONSE

    except:

        # Otherwise, we create the user.
        user_obj = get_user_model().objects.create_user(
            username or strip_accents((
                '%s%s' % (first_name[:1], last_name)
            ).lower()),
            email or None,
            password
        )

        user_obj.first_name = first_name
        user_obj.last_name = last_name

        if settings.INSTANCE_IS_SLAVE:
            user_obj.created_from = MTPUser.ORIGINS.SLAVE_REGISTRATION
        else:
            user_obj.created_from = MTPUser.ORIGINS.MASTER_REGISTRATION

        user_obj.save()

        # We try to fetch the session to which we want to add them.
        training_session = None
        training_session_id = request.POST.get('session_id', None)
        try:
            training_session = TrainingSession.objects.get(pk=training_session_id)
        except TrainingSession.DoesNotExist:

            # If we can't find the session, that's fine. We won't block the user creation.
            pass

        # We register the new user in the proper groups.
        GroupRole.objects.create(user=user_obj, group=Group.objects.get(name='trainee'))
        GroupRole.objects.create(user=user_obj, group=Group.objects.get(name='whoswho'))
        if training_session is not None:
            for group in training_session.training.default_group_set.\
                    mgroups.exclude(members=user_obj):
                GroupRole.objects.create(user=user_obj, group=group)

        # We log the user in.
        user_obj = authenticate(
            username=username or strip_accents((
                '%s%s' % (first_name[:1], last_name)
            ).lower()),
            password=password
        )
        login(request, user_obj)

        # We register the user in the specified training session, if requested.
        if training_session is not None:
            training_session.users.add(user_obj)
            training_session.save()

    return render_to_response(
        'api/json/user.json', dict(locals(), user=user_obj),
        content_type='application/json',
        context_instance=RequestContext(request),
    )


class TrainerList(APIView):
    """
    List all trainers.
    """

    # pylint: disable=unused-argument,redefined-builtin
    def get(self, request, format=None):
        trainers = get_user_model().objects.filter(
            is_staff=True, is_superuser=False, is_deleted=False)

        serializer = UserSerializer(trainers, many=True)
        return Response(serializer.data)


class TraineeList(APIView):
    """
    List all trainees, or create a new trainee.
    """

    # pylint: disable=unused-argument,redefined-builtin
    def get(self, request, format=None):
        users = get_user_model().objects.filter(
            is_staff=False, is_superuser=False, is_deleted=False)

        serializer = UserSerializer(users, many=True)
        return Response(serializer.data)


class UserList(APIView):
    """
    List all Users.
    """

    # pylint: disable=unused-argument,redefined-builtin
    def get(self, request, format=None):
        users = get_user_model().objects.filter(is_superuser=False, is_deleted=False)

        serializer = UserSerializer(users, many=True)
        return Response(serializer.data)


class UserDetail(APIView):
    """Retrieve a single user instance"""

    def get_user(self, pk):
        """Retrieve the user from his PK

        Parameters
        ----------
        pk: str
            The PK of the user to retrieve

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

        Raises
        ------
        Http404
            If the user cannot be found

        """

        try:
            return get_user_model().objects.non_deleted().get(pk=pk)
        except get_user_model().DoesNotExist:
            raise Http404

    # pylint: disable=unused-argument,redefined-builtin
    def get(self, request, user_uuid, format=None):
        """Serialize the user and return it

        For the parameters, see ``rest_framework.views.APIView``"""

        mtp_user = self.get_user(user_uuid)
        serializer = UserSerializer(mtp_user)

        return Response(serializer.data)
