# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.contrib.auth import get_user_model
from django.test.client import BOUNDARY, MULTIPART_CONTENT, encode_multipart
from django.urls import reverse

from misago.acl.testutils import override_acl
from misago.categories.models import Category
from misago.markup.mentions import MENTIONS_LIMIT
from misago.threads import testutils
from misago.users.testutils import AuthenticatedUserTestCase


UserModel = get_user_model()


class PostMentionsTests(AuthenticatedUserTestCase):
    def setUp(self):
        super(PostMentionsTests, self).setUp()

        self.category = Category.objects.get(slug='first-category')
        self.thread = testutils.post_thread(category=self.category)
        self.override_acl()

        self.post_link = reverse(
            'misago:api:thread-post-list', kwargs={
                'thread_pk': self.thread.pk,
            }
        )

    def override_acl(self):
        new_acl = self.user.acl_cache
        new_acl['categories'][self.category.pk].update({
            'can_see': 1,
            'can_browse': 1,
            'can_start_threads': 1,
            'can_reply_threads': 1,
            'can_edit_posts': 1,
        })

        override_acl(self.user, new_acl)

    def put(self, url, data=None):
        content = encode_multipart(BOUNDARY, data or {})
        return self.client.put(url, content, content_type=MULTIPART_CONTENT)

    def test_mention_noone(self):
        """endpoint handles no mentions in post"""
        response = self.client.post(
            self.post_link, data={
                'post': "This is test response!",
            }
        )
        self.assertEqual(response.status_code, 200)

        post = self.user.post_set.order_by('id').last()
        self.assertEqual(post.mentions.count(), 0)

    def test_mention_nonexistant(self):
        """endpoint handles nonexistant mention"""
        response = self.client.post(
            self.post_link, data={
                'post': "This is test response, @InvalidUser!",
            }
        )
        self.assertEqual(response.status_code, 200)

        post = self.user.post_set.order_by('id').last()
        self.assertEqual(post.mentions.count(), 0)

    def test_mention_self(self):
        """endpoint mentions author"""
        response = self.client.post(
            self.post_link, data={
                'post': "This is test response, @{}!".format(self.user),
            }
        )
        self.assertEqual(response.status_code, 200)

        post = self.user.post_set.order_by('id').last()

        self.assertEqual(post.mentions.count(), 1)
        self.assertEqual(post.mentions.all()[0], self.user)

    def test_mention_limit(self):
        """endpoint mentions limits mentions to 24 users"""
        users = []

        for i in range(MENTIONS_LIMIT + 5):
            users.append(
                UserModel.objects.
                create_user('Mention{}'.format(i), 'mention{}@bob.com'.format(i), 'pass123')
            )

        mentions = ['@{}'.format(u) for u in users]
        response = self.client.post(
            self.post_link,
            data={
                'post': "This is test response, {}!".format(', '.join(mentions)),
            }
        )
        self.assertEqual(response.status_code, 200)

        post = self.user.post_set.order_by('id').last()

        self.assertEqual(post.mentions.count(), 24)
        self.assertEqual(list(post.mentions.order_by('id')), users[:24])

    def test_mention_update(self):
        """edit post endpoint updates mentions"""
        user_a = UserModel.objects.create_user('Mention', 'mention@test.com', 'pass123')
        user_b = UserModel.objects.create_user('MentionB', 'mentionb@test.com', 'pass123')

        response = self.client.post(
            self.post_link, data={
                'post': "This is test response, @{}!".format(user_a),
            }
        )
        self.assertEqual(response.status_code, 200)

        post = self.user.post_set.order_by('id').last()

        self.assertEqual(post.mentions.count(), 1)
        self.assertEqual(post.mentions.order_by('id')[0], user_a)

        # add mention to post
        edit_link = reverse(
            'misago:api:thread-post-detail', kwargs={
                'thread_pk': self.thread.pk,
                'pk': post.pk,
            }
        )

        self.override_acl()
        response = self.put(
            edit_link,
            data={
                'post': "This is test response, @{} and @{}!".format(user_a, user_b),
            }
        )
        self.assertEqual(response.status_code, 200)

        self.assertEqual(post.mentions.count(), 2)
        self.assertEqual(list(post.mentions.order_by('id')), [user_a, user_b])

        # remove first mention from post - should preserve mentions
        self.override_acl()
        response = self.put(
            edit_link, data={
                'post': "This is test response, @{}!".format(user_b),
            }
        )
        self.assertEqual(response.status_code, 200)

        self.assertEqual(post.mentions.count(), 2)
        self.assertEqual(list(post.mentions.order_by('id')), [user_a, user_b])

        # remove mentions from post - should preserve mentions
        self.override_acl()
        response = self.put(
            edit_link, data={
                'post': "This is test response!",
            }
        )
        self.assertEqual(response.status_code, 200)

        self.assertEqual(post.mentions.count(), 2)
        self.assertEqual(list(post.mentions.order_by('id')), [user_a, user_b])

    def test_mentions_merge(self):
        """posts merge sums mentions"""
        user_a = UserModel.objects.create_user('Mention', 'mention@test.com', 'pass123')
        user_b = UserModel.objects.create_user('MentionB', 'mentionb@test.com', 'pass123')

        response = self.client.post(
            self.post_link, data={
                'post': "This is test response, @{}!".format(user_a),
            }
        )
        self.assertEqual(response.status_code, 200)

        post_a = self.user.post_set.order_by('id').last()

        self.assertEqual(post_a.mentions.count(), 1)
        self.assertEqual(list(post_a.mentions.all()), [user_a])

        # post second reply
        self.user.last_post_on = None
        self.user.save()

        response = self.client.post(
            self.post_link,
            data={
                'post': "This is test response, @{} and @{}!".format(user_a, user_b),
            }
        )
        self.assertEqual(response.status_code, 200)

        post_b = self.user.post_set.order_by('id').last()

        # merge posts and validate that post A has all mentions
        post_b.merge(post_a)

        self.assertEqual(post_a.mentions.count(), 2)
        self.assertEqual(list(post_a.mentions.order_by('id')), [user_a, user_b])
