# -*- coding: utf-8 -*-
# Copyright (C) 2016 by the Free Software Foundation, Inc.
#
# This file is part of Postorius.
#
# Postorius is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
# Postorius is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# Postorius.  If not, see <http://www.gnu.org/licenses/>.

from __future__ import absolute_import, print_function, unicode_literals

from datetime import datetime, timedelta
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.core import mail
from django.test.client import RequestFactory
from django.test.utils import override_settings

from postorius.forms import AddressActivationForm
from postorius.models import AddressConfirmationProfile
from postorius.tests.utils import ViewTestCase



class TestAddressActivationForm(ViewTestCase):
    """
    Test the activation form.
    """

    def setUp(self):
        super(TestAddressActivationForm, self).setUp()
        # Create a user and profile.
        self.user = User.objects.create_user('testuser', 'les@example.org', 'testpass')
        self.profile = AddressConfirmationProfile.objects.create(email='les2@example.org',
                                                                         user=self.user)
        self.expired = AddressConfirmationProfile.objects.create(email='expired@example.org',
                                                                         user=self.user)
        self.expired.created -= timedelta(weeks=100)
        self.expired.save()
        self.mm_user = self.mm_client.create_user('subscribed@example.org', 'password')

    def tearDown(self):
        self.profile.delete()
        self.expired.delete()
        self.user.delete()
        self.mm_user.delete()

    def test_valid_email_is_valid(self):
        form = AddressActivationForm({'email': 'very_new_email@example.org',})
        self.assertTrue(form.is_valid())

    def test_email_used_by_django_auth_is_invalid(self):
        # No need for cassette because we should check mailman last since it's the most expensive
        form = AddressActivationForm({'email': 'les@example.org',})
        self.assertFalse(form.is_valid())

    def test_invalid_email_is_not_valid(self):
        # No need for cassette because we should check mailman last since it's the most expensive
        form = AddressActivationForm({'email': 'les@example',})
        self.assertFalse(form.is_valid())

    def test_email_used_by_expired_confirmation_profile_is_valid(self):
        form = AddressActivationForm({'email': 'expired@example.org',})
        self.assertTrue(form.is_valid())

    def test_email_used_by_mailman_is_invalid(self):
        form = AddressActivationForm({'email': 'subscribed@example.org',})
        self.assertFalse(form.is_valid())


class TestAddressConfirmationProfile(ViewTestCase):
    """
    Test the confirmation of an email address activation (validating token,
    expiration, Mailman API calls etc.).
    """

    def setUp(self):
        super(TestAddressConfirmationProfile, self).setUp()
        # Create a user and profile.
        self.user = User.objects.create_user(
            username=u'ler_mm', email=u'ler@mailman.mostdesirable.org',
            password=u'pwd')
        self.profile = AddressConfirmationProfile.objects.create(email=u'les@example.org',
                                                                 user=self.user)
        # Create a test request object
        self.request = RequestFactory().get('/')

    def tearDown(self):
        self.profile.delete()
        self.user.delete()
        mail.outbox = []

    def test_profile_creation(self):
        # Profile is created and has all necessary properties.
        self.assertEqual(self.profile.email, u'les@example.org')
        self.assertEqual(len(self.profile.activation_key), 32)
        self.assertTrue(type(self.profile.created), datetime)

    def test_unicode_representation(self):
        # Correct unicode representation?
        self.assertEqual(unicode(self.profile),
                         'Address Confirmation Profile for les@example.org')

    def test_profile_not_expired_default_setting(self):
        # A profile created less then a day ago is not expired by default.
        delta = timedelta(hours=23)
        now = datetime.now()
        self.profile.created = now - delta
        self.assertFalse(self.profile.is_expired)

    def test_profile_is_expired_default_setting(self):
        # A profile older than 1 day is expired by default.
        delta = timedelta(days=1, hours=1)
        now = datetime.now()
        self.profile.created = now - delta
        self.assertTrue(self.profile.is_expired)

    def test_profile_is_updated_on_save(self):
        key = self.profile.activation_key
        created = self.profile.created
        self.profile.save()
        self.assertNotEqual(self.profile.activation_key, key)
        self.assertNotEqual(self.profile.created, created)

    @override_settings(
        EMAIL_CONFIRMATION_EXPIRATION_DELTA=timedelta(hours=5))
    def test_profile_not_expired(self):
        # A profile older than the timedelta set in the settings is
        # expired.
        delta = timedelta(hours=6)
        now = datetime.now()
        self.profile.created = now - delta
        self.assertTrue(self.profile.is_expired)

    @override_settings(
        EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend',
        EMAIL_CONFIRMATION_FROM='mailman@mostdesirable.org')
    def test_confirmation_link(self):
        # The profile obj can send out a confirmation email.
        # Simulate a VirtualHost with a different name
        self.request.META["HTTP_HOST"] = "another-virtualhost"
        # Now send the email
        self.profile.send_confirmation_link(self.request)
        self.assertEqual(mail.outbox[0].to[0], u'les@example.org')
        self.assertEqual(mail.outbox[0].subject, u'Confirmation needed')
        self.assertIn(self.profile.activation_key, mail.outbox[0].body)
        self.assertIn("another-virtualhost", mail.outbox[0].body)


class TestAddressActivationLinkSuccess(ViewTestCase):
    """
    This tests the activation link view if the key is valid and the profile is
    not expired.
    """

    def setUp(self):
        super(TestAddressActivationLinkSuccess, self).setUp()
        self.user = User.objects.create_user(
            username='ler', email=u'ler@example.org',
            password='pwd')
        self.mm_user = self.mm_client.create_user('ler@example.org', None)
        self.profile = AddressConfirmationProfile.objects.create(email=u'les@example.org', user=self.user)
        self.profile.save()

    def tearDown(self):
        self.profile.delete()
        self.user.delete()
        self.mm_user.delete()

    def test_add_address(self):
        # An activation key pointing to a valid profile adds the address
        # to the user.
        self.client.login(username='ler', password='pwd')
        url = reverse('address_activation_link',
                      args=[self.profile.activation_key])
        response = self.client.get(url)
        self.assertRedirects(response, reverse('user_profile'))
        self.assertHasSuccessMessage(response)
        self.assertEqual(
            set([a.email for a in self.mm_user.addresses]),
            set(['ler@example.org', 'les@example.org']))
        logged_in_user = response.wsgi_request.user
        self.assertEqual(logged_in_user.other_emails, ['les@example.org'])
