from django.test import Client, TestCase

from dice.models import DieFaceStat

from .models import GameScore


class RollViewTests(TestCase):
    def setUp(self):
        self.client = Client()

    def test_roll_returns_exactly_n_dice_with_valid_values(self):
        response = self.client.get('/yahtzee/roll', {'n': '5'})
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertEqual(len(data['values']), 5)
        self.assertTrue(all(1 <= v <= 6 for v in data['values']))

    def test_roll_guards_n_out_of_range(self):
        response = self.client.get('/yahtzee/roll', {'n': '0'})
        self.assertEqual(response.json()['values'], [])
        response = self.client.get('/yahtzee/roll', {'n': '99'})
        self.assertEqual(len(response.json()['values']), 5)

    def test_roll_increments_shared_dicefacestat(self):
        before = sum(
            row.ever_count for row in DieFaceStat.objects.filter(dice_type='d6'))
        self.client.get('/yahtzee/roll', {'n': '5'})
        after = sum(
            row.ever_count for row in DieFaceStat.objects.filter(dice_type='d6'))
        self.assertEqual(after - before, 5)


class IndexViewTests(TestCase):
    def setUp(self):
        self.client = Client()

    def test_index_renders_score_sheet(self):
        response = self.client.get('/yahtzee/')
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'Score Sheet')
        self.assertContains(response, 'id="yahtzee"')
        self.assertContains(response, '<wa-dialog id="leaderboard"')
        self.assertContains(response, '<wa-switch id="pip_style"')
        self.assertContains(response, '<wa-accordion id="last_rolls"')
        self.assertNotContains(response, '<button')


class SaveScoreViewTests(TestCase):
    def setUp(self):
        self.client = Client()

    def test_save_score_creates_gamescore_and_marks_it_new(self):
        response = self.client.get(
            '/yahtzee/save_score', {'total': '250', 'name': 'Dan'})
        self.assertEqual(response.status_code, 200)
        self.assertEqual(GameScore.objects.count(), 1)
        data = response.json()
        self.assertEqual(data['new_rank'], 1)
        self.assertEqual(len(data['scores']), 1)
        self.assertEqual(data['scores'][0]['total'], 250)
        self.assertEqual(data['scores'][0]['name'], 'Dan')
        self.assertTrue(data['scores'][0]['is_new'])

    def test_save_score_blank_name_defaults_to_anonymous(self):
        response = self.client.get(
            '/yahtzee/save_score', {'total': '50', 'name': '   '})
        self.assertEqual(response.json()['scores'][0]['name'], 'Anonymous')

    def test_save_score_orders_by_total_descending(self):
        GameScore.objects.create(name='a', total=100)
        GameScore.objects.create(name='b', total=300)
        response = self.client.get(
            '/yahtzee/save_score', {'total': '200', 'name': 'c'})
        totals = [row['total'] for row in response.json()['scores']]
        self.assertEqual(totals, [300, 200, 100])

    def test_save_score_list_capped_at_100(self):
        GameScore.objects.bulk_create(
            [GameScore(name='x', total=i) for i in range(150)])
        response = self.client.get(
            '/yahtzee/save_score', {'total': '9999', 'name': 'top'})
        self.assertEqual(len(response.json()['scores']), 100)
