from rest_framework import serializers

from django.contrib.auth import get_user_model
from django.core.exceptions import PermissionDenied
from django.utils import six
from django.utils.translation import ugettext as _
from django.utils.translation import ungettext

from misago.categories import PRIVATE_THREADS_ROOT_NAME
from misago.threads.participants import add_participants, set_owner
from misago.threads.permissions import allow_message_user

from . import PostingEndpoint, PostingMiddleware


UserModel = get_user_model()


class ParticipantsMiddleware(PostingMiddleware):
    def use_this_middleware(self):
        if self.mode == PostingEndpoint.START:
            return self.tree_name == PRIVATE_THREADS_ROOT_NAME
        return False

    def get_serializer(self):
        return ParticipantsSerializer(data=self.request.data, context={'user': self.user})

    def save(self, serializer):
        set_owner(self.thread, self.user)
        add_participants(self.request, self.thread, serializer.users_cache)


class ParticipantsSerializer(serializers.Serializer):
    to = serializers.ListField(child=serializers.CharField(), required=True)

    def validate_to(self, usernames):
        clean_usernames = self.clean_usernames(usernames)
        self.users_cache = self.get_users(clean_usernames)

    def clean_usernames(self, usernames):
        clean_usernames = []
        for name in usernames:
            clean_name = name.strip().lower()

            if clean_name == self.context['user'].slug:
                raise serializers.ValidationError(
                    _("You can't include yourself on the list of users to invite to new thread.")
                )

            if clean_name and clean_name not in clean_usernames:
                clean_usernames.append(clean_name)

        if not clean_usernames:
            raise serializers.ValidationError(_("You have to enter user names."))

        max_participants = self.context['user'].acl_cache['max_private_thread_participants']
        if max_participants and len(clean_usernames) > max_participants:
            message = ungettext(
                "You can't add more than %(users)s user to private thread (you've added %(added)s).",
                "You can't add more than %(users)s users to private thread (you've added %(added)s).",
                max_participants,
            )
            raise serializers.ValidationError(
                message % {
                    'users': max_participants,
                    'added': len(clean_usernames),
                }
            )

        return list(set(clean_usernames))

    def get_users(self, usernames):
        users = []
        for user in UserModel.objects.filter(slug__in=usernames):
            try:
                allow_message_user(self.context['user'], user)
            except PermissionDenied as e:
                raise serializers.ValidationError(six.text_type(e))
            users.append(user)

        if len(usernames) != len(users):
            invalid_usernames = set(usernames) - set([u.slug for u in users])
            sorted_usernames = sorted(invalid_usernames)

            message = _("One or more users could not be found: %(usernames)s")
            raise serializers.ValidationError(message % {'usernames': ', '.join(sorted_usernames)})

        return users