import json

from rest_framework.test import APITestCase

from vbv_lernwelt.core.admin import User
from vbv_lernwelt.core.tests.factories import UserFactory
from vbv_lernwelt.notify.models import Notification, NotificationType
from vbv_lernwelt.notify.tests.factories import NotificationFactory


class TestNotificationApi(APITestCase):
    def setUp(self) -> None:
        alice = UserFactory(username="Alice", email="alice@gmail.com")
        john = UserFactory(username="John Doe", email="john.doe@gmail.com")

        self.user = User.objects.get(username="Alice")
        self.client.login(username="Alice", password="pw")
        self.alice = alice
        self.john = john

    def create_default_notifications(self):
        NotificationFactory(
            recipient=self.john, verb="{} hat einen neuen Beitrag erfasst"
        )
        NotificationFactory(
            recipient=self.john,
            actor=self.alice,
            verb="hat einen Tranverauftrag erstellt",
        )
        NotificationFactory(
            recipient=self.alice,
            actor=self.john,
            verb="{} hat deinen Beitrag kommentiert",
            unread=False,
        )
        NotificationFactory(
            recipient=self.alice,
            actor=self.john,
            verb="{} ist ganz klein geworden",
            unread=True,
        )

    def test_get_all_only_returns_logged_in_user_notification(self):
        self.create_default_notifications()
        response = self.client.get("/notifications/api/all_list/")

        self.assertEqual(response.status_code, 200)
        data = response.json()

        self.assertTrue(data["all_count"] < Notification.objects.count())
        self.assertEqual(2, data["all_count"])
        self.assertTrue(
            all(
                [
                    self.alice.id == notification["recipient"]
                    for notification in data["all_list"]
                ]
            )
        )
        self.assertEqual("John Doe", data["all_list"][0]["actor"])

    def test_get_all_pagination(self):
        num_notifications = 322
        for i in range(num_notifications):
            NotificationFactory(
                recipient=self.alice,
                actor=self.john,
                verb="{} ist ganz klein geworden",
                unread=True,
            )

        response = self.client.get("/notifications/api/all_list/?max=10")
        data = response.json()

        self.assertEqual(num_notifications, data["all_count"])
        self.assertEqual(len(data["all_list"]), 10)

    def test_get_unread_pagination(self):
        unread_notifications = 120
        for i in range(unread_notifications):
            NotificationFactory(
                recipient=self.alice,
                actor=self.john,
                verb="{} ist ganz klein geworden",
                unread=True,
            )

        while unread_notifications > 0:
            to_read_at_once = 12
            # Read to_read_at_once unread notifications at a time
            data = self.client.get(
                f"/notifications/api/unread_list/?max={to_read_at_once}&mark_as_read=true"
            ).json()
            self.assertEqual(len(data["unread_list"]), to_read_at_once)
            unread_notifications -= to_read_at_once

            response = self.client.get("/notifications/api/unread_count/")
            unread_count = response.json()["unread_count"]
            self.assertEqual(unread_count, unread_notifications)

    def test_unread_count(self):
        self.create_default_notifications()
        response = self.client.get("/notifications/api/unread_count/")
        unread_count = response.json()["unread_count"]
        self.assertEqual(unread_count, 1)


class TestNotificationSettingsApi(APITestCase):
    def setUp(self) -> None:
        username = "Alice"
        UserFactory(username=username, email="alice@gmail.com")

        self.user = User.objects.get(username=username)
        self.client.login(username=username, password="pw")

    def test_store_retrieve_settings(self):
        notification_settings = json.dumps(
            [NotificationType.INFORMATION, NotificationType.PROGRESS]
        )

        api_path = "/api/notify/email_notification_settings/"
        response = self.client.post(
            api_path,
            notification_settings,
            format="json",
        )
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json(), notification_settings)
        self.user.refresh_from_db()
        self.assertEqual(
            self.user.additional_json_data["email_notification_types"],
            notification_settings,
        )

        response = self.client.get(
            api_path,
            format="json",
        )
        self.assertEqual(response.json(), notification_settings)
