from django.test import TestCase
from django.core.urlresolvers import reverse

from ..forms import ComposeForm, FolderForm
from ..models import Message, Recipient, Discussion, Folder
from ..compat import User


class DiscussionsViewsTests(TestCase):
    fixtures = ['users.json', 'messages.json']

    def _test_login(self, named_url, **kwargs):
        """ Test that the view requires login """
        response = self.client.get(reverse(named_url, **kwargs))
        self.assertEqual(response.status_code, 302)

    def test_compose(self):
        """ A ``GET`` to the compose view """
        # Login is required.
        self._test_login('discussions_compose')

        # Sign in
        self.client.login(username='thoas', password='$ecret')
        response = self.client.get(reverse('discussions_compose'))

        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response,
                                'discussions/form.html')

        self.failUnless(isinstance(response.context['form'],
                                   ComposeForm))

    def test_compose_post(self):
        """ ``POST`` to the compose view """
        self.client.login(username='thoas', password='$ecret')

        valid_data = {'to': 'ampelmann',
                      'body': 'Hi mister',
                      'subject': 'Hi'}

        response = self.client.post(reverse('discussions_compose'),
                                    data=valid_data)

        self.assertEqual(response.status_code, 200)

        valid_data['submit'] = 'submit'

        response = self.client.post(reverse('discussions_compose'),
                                    data=valid_data)

        self.assertRedirects(response,
                             reverse('discussions_detail',
                                     kwargs={'discussion_id': 3}))

        # Check for a requested redirect
        valid_data['next'] = reverse('discussions_compose')
        response = self.client.post(reverse('discussions_compose'),
                                    data=valid_data)
        self.assertRedirects(response,
                             valid_data['next'])

    def test_compose_recipients_get(self):
        """ A ``GET`` to the compose view with recipients """
        self.client.login(username='thoas', password='$ecret')

        valid_recipients = "thoas+oleiade"

        # Test valid recipients
        response = self.client.get(reverse('discussions_compose',
                                           kwargs={'recipients': valid_recipients}))

        self.assertEqual(response.status_code, 200)

        # Test the users
        oleiade = User.objects.get(username='oleiade')
        thoas = User.objects.get(username='thoas')
        self.assertEqual(response.context['recipients'][0], oleiade)
        self.assertEqual(response.context['recipients'][1], thoas)

        # Test that the initial data of the form is set.
        self.assertEqual(response.context['form'].initial['to'],
                         [oleiade, thoas])

    def test_compose_recipients_post(self):
        """ A ``POST`` to the compose view with recipients """
        self.client.login(username='thoas', password='$ecret')

        valid_recipients = "thoas+oleiade"

        # Test valid recipients
        response = self.client.post(reverse('discussions_compose'), data={
            'recipients': valid_recipients
        })

        self.assertEqual(response.status_code, 200)

        # Test the users
        oleiade = User.objects.get(username='oleiade')
        thoas = User.objects.get(username='thoas')
        self.assertEqual(response.context['recipients'][0], oleiade)
        self.assertEqual(response.context['recipients'][1], thoas)

        # Test that the initial data of the form is set.
        self.assertEqual(response.context['form'].initial['to'],
                         [oleiade, thoas])

    def test_discussion_detail(self):
        """ A ``GET`` to the detail view """
        self._test_login('discussions_detail',
                         kwargs={'discussion_id': 2})

        # Sign in
        self.client.login(username='ampelmann', password='$ecret')
        response = self.client.get(reverse('discussions_detail',
                                   kwargs={'discussion_id': 1}))

        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response,
                                'discussions/detail.html')

        # Test that the message is read.
        ampelmann = User.objects.get(pk=2)
        mr = Recipient.objects.get(discussion=Discussion.objects.get(pk=1),
                                   user=ampelmann)
        self.failUnless(mr.read_at)

    def test_discussion_detail_new_message(self):
        self.client.login(username='ampelmann', password='$ecret')
        discussion = Discussion.objects.get(pk=1)

        response = self.client.post(discussion.get_absolute_url(),
                                    data={
                                        'body': 'My reply'
                                    })
        self.assertRedirects(response, discussion.get_absolute_url())

        self.assertEqual(discussion.messages.count(), 2)

        ampelmann = User.objects.get(username='ampelmann')

        message = discussion.messages.get(sender=ampelmann)

        self.assertEqual(message.body, 'My reply')

    def test_valid_discussion_move(self):
        """ ``POST`` to move a discussion into a folder """
        # Test that sign in is required

        folder = Folder.objects.get(pk=1)

        url = reverse('discussions_move', kwargs={
            'folder_id': folder.pk
        })
        response = self.client.post(url)
        self.assertEqual(response.status_code, 302)

        # Sign in
        self.client.login(username='thoas', password='$ecret')

        # Test that only posts are allowed
        response = self.client.get(url)
        self.assertEqual(response.status_code, 405)

        response = self.client.post(url,
                                    data={'discussion_ids': '1'})
        self.assertRedirects(response,
                             reverse('discussions_list'))

        user = User.objects.get(username='thoas')

        recipient = Recipient.objects.get(discussion=1, user=user)

        self.assertEqual(recipient.folder, folder)

    def test_invalid_discussion_move(self):
        folder = Folder.objects.get(pk=1)

        url = reverse('discussions_move', kwargs={
            'folder_id': folder.pk
        })

        self.client.login(username='ampelmann', password='$ecret')

        response = self.client.post(url,
                                    data={'discussion_ids': '1'})

        self.assertEqual(response.status_code, 404)

    def test_valid_discussion_read(self):
        """ ``POST`` to remove a discussion """
        # Test that sign in is required
        response = self.client.post(reverse('discussions_read'))
        self.assertEqual(response.status_code, 302)

        # Sign in
        self.client.login(username='thoas', password='$ecret')

        # Test that only posts are allowed
        response = self.client.get(reverse('discussions_read'))
        self.assertEqual(response.status_code, 405)

        response = self.client.post(reverse('discussions_read'),
                                    data={'discussion_ids': '1'})
        self.assertRedirects(response,
                             reverse('discussions_list'))

        recipient = Discussion.objects.get(pk=1).recipient_set.get(user=User.objects.get(pk=1))

        self.assertTrue(recipient.is_read())

    def test_valid_discussion_remove(self):
        """ ``POST`` to remove a discussion """
        # Test that sign in is required
        response = self.client.post(reverse('discussions_remove'))
        self.assertEqual(response.status_code, 302)

        # Sign in
        self.client.login(username='thoas', password='$ecret')

        # Test that only posts are allowed
        response = self.client.get(reverse('discussions_remove'))
        self.assertEqual(response.status_code, 405)

        response = self.client.post(reverse('discussions_remove'),
                                    data={'discussion_ids': '1'})
        self.assertRedirects(response,
                             reverse('discussions_list'))
        d = Discussion.objects.get(pk=1)
        self.failUnless(d.sender_deleted_at)

        self.client.login(username='ampelmann', password='$ecret')
        response = self.client.post(reverse('discussions_remove'),
                                    data={'discussion_ids': '1',
                                          'next': reverse('discussions_list')})
        self.assertRedirects(response,
                             reverse('discussions_list'))
        ampelmann = User.objects.get(username='ampelmann')
        dr = d.recipient_set.get(user=ampelmann,
                                 discussion=d)
        self.failUnless(dr.deleted_at)

    def test_invalid_discussion_remove(self):
        """ ``POST`` to remove an invalid discussion """
        # Sign in
        self.client.login(username='thoas', password='$ecret')

        bef_len = Message.objects.filter(sender_deleted_at__isnull=False).count()
        response = self.client.post(reverse('discussions_remove'),
                                    data={'discussion_ids': ['a', 'b']})

        # The program should play nice, nothing happened.
        af_len = Message.objects.filter(sender_deleted_at__isnull=False).count()
        self.assertRedirects(response,
                             reverse('discussions_list'))
        self.assertEqual(bef_len, af_len)

    def test_valid_discussion_remove_multiple(self):
        """ ``POST`` to remove multiple messages """
        # Sign in
        self.client.login(username='thoas', password='$ecret')
        response = self.client.post(reverse('discussions_remove'),
                                    data={'discussion_ids': [1, 2]})
        self.assertRedirects(response,
                             reverse('discussions_list'))

        discussion_list = Discussion.objects.filter(pk__in=['1', '2'],
                                                    sender_deleted_at__isnull=False)

        # thoas has created only one discussion (see fixtures)
        self.assertEqual(discussion_list.count(), 1)

    def test_discussion_unremove(self):
        """ Unremove a discussion """
        self.client.login(username='thoas', password='$ecret')

        # Delete a discussion as owner
        response = self.client.post(reverse('discussions_unremove'),
                                    data={'discussion_pks': [1, ]})

        self.assertRedirects(response,
                             reverse('discussions_list'))

        # Delete the message as a recipient
        response = self.client.post(reverse('discussions_unremove'),
                                    data={'discussion_pks': [2, ]})

        self.assertRedirects(response,
                             reverse('discussions_list'))

    def test_discussion_list(self):
        """ ``GET`` the discussion list for a user """
        self._test_login("discussions_list")

        self.client.login(username='thoas', password='$ecret')
        response = self.client.get(reverse('discussions_list'))
        self.assertEqual(response.status_code, 200)

        self.assertTemplateUsed(response, 'discussions/list.html')

    def test_discussion_sent(self):
        """ ``GET`` the message list for a user """
        self._test_login("discussions_sent")

        self.client.login(username='thoas', password='$ecret')
        response = self.client.get(reverse('discussions_sent'))
        self.assertEqual(response.status_code, 200)

        self.assertTemplateUsed(response, 'discussions/sent.html')

    def test_discussion_deleted(self):
        """ ``GET`` the message list for a user """
        self._test_login("discussions_deleted")

        self.client.login(username='thoas', password='$ecret')
        response = self.client.get(reverse('discussions_deleted'))
        self.assertEqual(response.status_code, 200)

        self.assertTemplateUsed(response, 'discussions/deleted.html')

    def test_discussion_unread(self):
        """ ``GET`` the message list for a user """
        self._test_login("discussions_unread")

        self.client.login(username='thoas', password='$ecret')
        response = self.client.get(reverse('discussions_unread'))
        self.assertEqual(response.status_code, 200)

        self.assertTemplateUsed(response, 'discussions/unread.html')

    def test_discussion_detail_between_two_users(self):
        """ ``GET`` to a detail page between two users """
        self._test_login('discussions_list',
                         kwargs={'username': 'oleiade'})
        self.client.login(username='thoas', password='$ecret')

        response = self.client.get(reverse('discussions_list',
                                           kwargs={'username': 'oleiade'}))

        self.assertEqual(response.status_code, 200)

        self.assertTemplateUsed(response, 'discussions/list.html')

        # Check that all the messages are marked as read.
        thoas = User.objects.get(pk=1)
        oleiade = User.objects.get(pk=3)
        unread_messages = Recipient.objects.filter(user=thoas,
                                                   discussion__sender=oleiade,
                                                   read_at__isnull=True)

        self.assertEqual(len(unread_messages), 0)

    def test_folder_create(self):
        self._test_login('discussions_folder_create')

        self.client.login(username='thoas', password='$ecret')

        response = self.client.get(reverse('discussions_folder_create'))

        self.assertEqual(response.status_code, 200)

        self.failUnless(isinstance(response.context['form'], FolderForm))
        self.assertTemplateUsed(response,
                                'discussions/folder/create.html')

        data = {
            'name': 'My folder'
        }

        response = self.client.post(reverse('discussions_folder_create'), data=data)

        self.assertEqual(Folder.objects.count(), 2)

        folder = Folder.objects.get(pk=2)

        self.assertEqual(folder.name, data['name'])

        self.assertRedirects(response,
                             reverse('discussions_folder_detail', kwargs={
                                 'folder_id': folder.pk
                             }))

    def test_folder_update(self):
        folder = Folder.objects.get(pk=1)

        self._test_login('discussions_folder_update', kwargs={
            'folder_id': folder.pk
        })

        self.client.login(username='thoas', password='$ecret')

        response = self.client.get(reverse('discussions_folder_update', kwargs={
            'folder_id': folder.pk
        }))

        self.assertEqual(response.status_code, 200)

        self.failUnless(isinstance(response.context['form'], FolderForm))
        self.assertTemplateUsed(response,
                                'discussions/folder/update.html')

        data = {
            'name': 'My folder new name'
        }

        response = self.client.post(reverse('discussions_folder_update', kwargs={
            'folder_id': folder.pk
        }), data=data)

        folder = Folder.objects.get(pk=1)

        self.assertEqual(folder.name, data['name'])

        self.assertRedirects(response,
                             reverse('discussions_folder_update', kwargs={
                                 'folder_id': folder.pk
                             }))
