from imp import reload

from django.db.models import signals
from django.test import TestCase

from .. import settings
from .. import commands
from .. import registry
from ..models import Badge, Award
from ..compat import get_user_model

from .recipes import Recipe1, Recipe2


class CommandsTestCase(TestCase):
    """
    Commands test case.
    """

    def setUp(self):
        reload(settings)
        registry.clear()

        self.post_save_count = 0
        self.pre_delete_count = 0

        signals.post_save.connect(self._award_post_save_receiver, sender=Award)
        signals.pre_delete.connect(self._award_pre_delete_receiver, sender=Award)

    def tearDown(self):
        registry.clear()

        signals.post_save.disconnect(self._award_post_save_receiver, sender=Award)
        signals.pre_delete.disconnect(self._award_pre_delete_receiver, sender=Award)

    def _award_post_save_receiver(self, *args, **kwargs):
        self.post_save_count += 1

    def _award_pre_delete_receiver(self, *args, **kwargs):
        self.pre_delete_count += 1

    def test_sync_badges(self):
        registry.register([Recipe1, Recipe2])
        created = commands.sync_badges()
        self.assertEqual(len(created), 2)

    def test_sync_badges_update(self):
        registry.register([Recipe1, Recipe2])
        commands.sync_badges()

        Recipe1.name = 'Howdy'
        commands.sync_badges(update=True)

        self.assertEqual(Badge.objects.get(slug='recipe1').name, 'Howdy')
        Recipe1.name = 'Recipe 1'

    def test_sync_count(self):
        settings.AUTO_DENORMALIZE = False

        user = get_user_model().objects.create_user('user', 'user@example.com', '$ecret')
        registry.register([Recipe1, Recipe2])
        commands.sync_badges()
        updated, unchanged = commands.sync_counts()

        self.assertEqual(len(updated), 0)
        self.assertEqual(len(unchanged), 2)

        Award.objects.create(user=user, badge=Badge.objects.get(slug='recipe1'))
        updated, unchanged = commands.sync_counts()

        self.assertEqual(len(updated), 1)
        self.assertEqual(len(unchanged), 1)

    def test_sync_awards_auto_denormalize_false(self):
        settings.AUTO_DENORMALIZE = False

        user = get_user_model().objects.create_user('user', 'user@example.com', '$ecret')
        registry.register(Recipe1)
        created = commands.sync_badges()
        recipe = registry.get_recipe_instance('recipe1')

        self.assertEqual(len(created), 1)
        self.assertEqual(recipe.badge.users.count(), 0)

        user.love_python = True
        user.save()

        commands.sync_awards()

        self.assertEqual(recipe.badge.users.count(), 1)
        self.assertEqual(recipe.badge.users_count, 0)
        self.assertEqual(self.post_save_count, 1)

    def test_sync_awards_auto_denormalize_true(self):
        settings.AUTO_DENORMALIZE = True

        user = get_user_model().objects.create_user('user1', 'user1@example.com', '$ecret')
        registry.register(Recipe1)
        commands.sync_badges()
        recipe = registry.get_recipe_instance('recipe1')

        user.love_python = True
        user.save()

        commands.sync_awards()

        self.assertEqual(recipe.badge.users.count(), 1)
        self.assertEqual(recipe.badge.users_count, 1)
        self.assertEqual(self.post_save_count, 1)
        self.assertEqual(self.pre_delete_count, 0)

        Award.objects.all().delete()

        self.assertEqual(self.pre_delete_count, 1)
        self.assertEqual(recipe.badge.users.count(), 0)
        self.assertEqual(recipe.badge.users_count, 0)

    def test_sync_awards_disable_signals(self):
        settings.AUTO_DENORMALIZE = True

        user = get_user_model().objects.create_user('user', 'user@example.com', '$ecret')
        registry.register(Recipe1)
        created = commands.sync_badges()
        recipe = registry.get_recipe_instance('recipe1')

        self.assertEqual(len(created), 1)
        self.assertEqual(self.post_save_count, 0)
        self.assertEqual(recipe.badge.users_count, 0)

        user.love_python = True
        user.save()

        commands.sync_awards(**{'disable_signals': True})

        self.assertEqual(recipe.badge.users_count, 0)
        self.assertEqual(self.post_save_count, 0)
