"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".

Replace this with more appropriate tests for your application.
"""
import random

from django.test import TestCase
from mahjong_ranking.models import Hanchan, KyuDanRanking


class KyuDanTest(TestCase):
    """
    Unittest to check if the hanchan calculation works against the rulebook.
    """
    equal_attrs = ('dan', 'dan_points', 'kyu', 'kyu_points', 'good_hanchans',
                   'won_hanchans', 'hanchan_count')

    fixtures = [
        'test_membership.json',
        'test_events.json',
        'test_hanchans.json',
        'test_event_rankings.json',
        'test_kyu_dan_rankings.json'
    ]

    def _test_recalc(self):
        """
        Test if a Kyu/Dan Ranking recalculation gives the same result as stored.

        :return:
        """

        for ranking in KyuDanRanking.objects.all():
            original = {a: getattr(ranking, a) for a in self.equal_attrs}
            ranking.calculate()
            for attr in self.equal_attrs:
                self.assertEqual(
                    original[attr],
                    getattr(ranking, attr),
                    "Recalculation was different! user: {user}, attribute: "
                    "{attr}, original: {original}, recalc: {recalc}".format(
                        user=ranking.user, attr=attr, original=original[attr],
                        recalc=getattr(ranking, attr))
                )

    def test_partial_recalc(self):
        """
        Test if partial recalclulation gives the same results.

        :return:
        """

        for ranking in KyuDanRanking.objects.all():
            original = {a: getattr(ranking, a) for a in self.equal_attrs}
            confirmed_hanchans = Hanchan.objects.confirmed(
                user=ranking.user,
                since=ranking.legacy_date
            )
            if not confirmed_hanchans.count():
                continue
            rnd = random.randrange(confirmed_hanchans.count())
            since = confirmed_hanchans[rnd].start
            ranking.calculate(since=since)
            for attr in self.equal_attrs:
                self.assertEqual(
                    original[attr],
                    getattr(ranking, attr),
                    "partial Recalculation was different! user: {user},  "
                    "attribute: {attr}, original: {original}, recalc: "
                    "{recalc}".format(
                        user=ranking.user, attr=attr, original=original[attr],
                        recalc=getattr(ranking, attr))
                )

    def test_points_sum(self):
        """
        Test if the sum of the kyu / dan points equals the value in the Ranking.

        :return: None
        """
        for ranking in KyuDanRanking.objects.all():
            dan_kyu = 'dan_points' if ranking.dan else 'kyu_points'
            points = {
                'dan_points': ranking.legacy_dan_points or 0,
                'kyu_points': ranking.legacy_kyu_points or 0
            }
            confirmed_hanchans = Hanchan.objects.confirmed(
                user=ranking.user,
                since=ranking.legacy_date
            )
            for hanchan in confirmed_hanchans:
                hanchan.get_playerdata(ranking.user)
                points[dan_kyu] += getattr(hanchan, dan_kyu) or 0

            self.assertEqual(
                points[dan_kyu],
                getattr(ranking, dan_kyu),
                "{dan_kyu} for {player} won't compute! ranking: {ranking}, sum: {sum}".format(
                    dan_kyu=dan_kyu, player=ranking.user,
                    ranking=getattr(ranking, dan_kyu), sum=points[dan_kyu])
            )
