from django.test import TestCase
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.core.management import call_command
from django.core.management.base import CommandError

from io import StringIO
from os import devnull

from .models import Corporation, Adhesion


class AdhesionsMixin:
    def setUp(self):
        admin = User.objects.create_user('admin', email='admin@example.net', password='admin', is_superuser=True)
        user = User.objects.create_user('user', first_name='first', last_name='last', email='user@example.net', password='user')
        adh1 = Adhesion.objects.create(adherent_type=ContentType.objects.get_for_model(User), adherent_id=user.pk)
        corp1 = Corporation.objects.create(social_reason='GoodCorp')
        corp1.members.add(user)
        corp2 = Corporation.objects.create(social_reason='EvilCorp')
        adh2 = Adhesion.objects.create(adherent_type=ContentType.objects.get_for_model(Corporation), adherent_id=corp1.pk)


class ViewsTestCase(AdhesionsMixin, TestCase):
    def test_adhesion_backend(self):
        user = User.objects.get(username='user')
        adhesion = user.profile.adhesion
        self.assertFalse(self.client.login(username='%d' % adhesion.pk, password='wrong'))
        self.assertFalse(self.client.login(username='ADT%d' % adhesion.pk, password='wrong'))
        self.assertFalse(self.client.login(username='9999', password='user'))
        self.assertFalse(self.client.login(username='ADT9999', password='user'))
        self.assertTrue(self.client.login(username='%d' % adhesion.pk, password='user'))
        self.assertTrue(self.client.login(username='ADT%d' % adhesion.pk, password='user'))

    def test_user(self):
        response = self.client.get(reverse('adhesion-detail-user'))
        self.assertRedirects(response, reverse('login') + '?next=' + reverse('adhesion-detail-user'))
        self.client.login(username='user', password='user')
        response = self.client.get(reverse('adhesion-detail-user'))
        self.assertEqual(response.status_code, 200)

    def test_corporation(self):
        user = User.objects.get(username='user')
        corp = Corporation.objects.get(social_reason='EvilCorp')
        url = reverse('corporation-detail-user', kwargs={'pk': corp.pk})
        response = self.client.get(url)
        self.assertRedirects(response, reverse('login') + '?next=' + url)
        self.client.login(username='user', password='user')
        response = self.client.get(url)
        self.assertEqual(response.status_code, 403)
        corp.members.add(user)
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, '')

    def test_corporation_menu(self):
        self.client.login(username='user', password='user')
        response = self.client.get('/')
        self.assertContains(response, 'GoodCorp')
        self.assertNotContains(response, 'EvilCorp')

    def test_users_admin(self):
        self.client.login(username='admin', password='admin')
        response = self.client.get(reverse('user-list'))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'admin')
        self.assertContains(response, 'user')
        response = self.client.get(reverse('user-add'))
        self.assertEqual(response.status_code, 200)
        response = self.client.get(reverse('user-detail', kwargs={'pk': 1}))
        self.assertEqual(response.status_code, 200)
        response = self.client.get(reverse('user-edit', kwargs={'pk': 1}))
        self.assertEqual(response.status_code, 200)

    def test_corporations_admin(self):
        self.client.login(username='admin', password='admin')
        response = self.client.get(reverse('corporation-list'))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'GoodCorp')
        self.assertContains(response, 'EvilCorp')
        response = self.client.get(reverse('corporation-add'))
        self.assertEqual(response.status_code, 200)
        response = self.client.get(reverse('corporation-detail', kwargs={'pk': 1}))
        self.assertEqual(response.status_code, 200)
        response = self.client.get(reverse('corporation-edit', kwargs={'pk': 1}))
        self.assertEqual(response.status_code, 200)

    def test_adhesions_admin(self):
        self.client.login(username='admin', password='admin')
        response = self.client.get(reverse('adhesion-list'))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'user')
        response = self.client.get(reverse('adhesion-detail', kwargs={'pk': 1}))
        self.assertEqual(response.status_code, 200)

    def test_adhesion_model(self):
        user = User.objects.get(username='user')
        adh1 = Adhesion.objects.get(adherent_type=ContentType.objects.get_for_model(User), adherent_id=user.pk)
        self.assertEquals(user.profile.adhesion, adh1)
        self.assertTrue(adh1.is_physical())
        self.assertFalse(adh1.is_moral())
        self.assertEquals(adh1.get_adherent_name(), 'first last')
        corp = Corporation.objects.get(social_reason='GoodCorp')
        adh2 = Adhesion.objects.get(adherent_type=ContentType.objects.get_for_model(Corporation), adherent_id=corp.pk)
        self.assertEquals(corp.adhesion, adh2)
        self.assertFalse(adh2.is_physical())
        self.assertTrue(adh2.is_moral())
        self.assertEquals(adh2.get_adherent_name(), 'GoodCorp')

    def test_user_creation(self):
        url = reverse('user-add')
        self.client.login(username='user', password='user')
        response = self.client.get(url)
        self.assertRedirects(response, reverse('login') + '?next=' + url)
        self.client.login(username='admin', password='admin')
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

    def test_user_update(self):
        user = User.objects.get(username='user')
        url = reverse('user-edit', kwargs={'pk': user.pk})
        self.client.login(username='user', password='user')
        response = self.client.get(url)
        self.assertRedirects(response, reverse('login') + '?next=' + url)
        self.client.login(username='admin', password='admin')
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

    def test_corp_creation(self):
        url = reverse('corporation-add')
        self.client.login(username='user', password='user')
        response = self.client.get(url)
        self.assertRedirects(response, reverse('login') + '?next=' + url)
        self.client.login(username='admin', password='admin')
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

    def test_corp_update(self):
        corp = Corporation.objects.get(social_reason='EvilCorp')
        url = reverse('corporation-edit', kwargs={'pk': corp.pk})
        self.client.login(username='user', password='user')
        response = self.client.get(url)
        self.assertRedirects(response, reverse('login') + '?next=' + url)
        self.client.login(username='admin', password='admin')
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)


class CommandsTestCase(AdhesionsMixin, TestCase):
    def test_list(self):
        out = StringIO()
        call_command("adherents", "list", stdout=out)
        result = out.getvalue()
        self.assertNotRegex(result, "admin") # non adhérent
        self.assertRegex(result, "first last")
        self.assertRegex(result, "GoodCorp")
        self.assertNotRegex(result, "EvilCorp") # non adhérent

        out = StringIO()
        call_command("adherents", "list", "--physique", stdout=out)
        result = out.getvalue()
        self.assertRegex(result, "first last")
        self.assertNotRegex(result, "GoodCorp")

        out = StringIO()
        call_command("adherents", "list", "--morale", stdout=out)
        result = out.getvalue()
        self.assertNotRegex(result, "first last")
        self.assertRegex(result, "GoodCorp")

    def test_create_personne_physique(self):
        user = User.objects.first()
        adh = Adhesion.objects.first()
        args = ["adherents", "create", "--id", "%d" % adh.pk, "physique", "--login", "user2", "--firstname", "first2", "--lastname", "last2"]
        kwargs = {'stdout': open(devnull, 'w')}
        self.assertRaisesRegex(CommandError, "numéro .* déjà attribué", call_command, *args, **kwargs)
        args[args.index("--id") + 1] = "1000"
        args[args.index("--login") + 1] = user.username
        self.assertRaisesRegex(CommandError, "nom d’utilisateur .* déjà utilisé", call_command, *args, **kwargs)
        args[args.index("--login") + 1] = "user2"
        call_command(*args, **kwargs)
        user = User.objects.get(username='user2')
        adh = Adhesion.objects.get(adherent_type=ContentType.objects.get_for_model(User), adherent_id=user.pk)
        self.assertEquals(adh.id, 1000)

    def test_create_personne_morale(self):
        corp = Corporation.objects.first()
        adh = Adhesion.objects.first()
        args = ["adherents", "create", "--id", "%d" % adh.pk, "morale", "--name", "NewCorp"]
        kwargs = {'stdout': open(devnull, 'w')}
        self.assertRaisesRegex(CommandError, "numéro .* déjà attribué", call_command, *args, **kwargs)
        args[args.index("--id") + 1] = "1000"
        args[args.index("--name") + 1] = corp.social_reason
        self.assertRaisesRegex(CommandError, "raison sociale .* déjà utilisé", call_command, *args, **kwargs)
        args[args.index("--name") + 1] = "NewCorp"
        call_command(*args, **kwargs)
        corp = Corporation.objects.get(social_reason='NewCorp')
        adh = Adhesion.objects.get(adherent_type=ContentType.objects.get_for_model(Corporation), adherent_id=corp.pk)
        self.assertEquals(adh.id, 1000)