import json

from django.test import TestCase
from django.urls import reverse

from newsreader.accounts.tests.factories import UserFactory
from newsreader.news.collection.tests.factories import FeedFactory
from newsreader.news.core.tests.factories import CategoryFactory, FeedPostFactory


class CategoryDetailViewTestCase(TestCase):
    def setUp(self):
        self.user = UserFactory(password="test")
        self.client.force_login(self.user)

    def test_simple(self):
        category = CategoryFactory(user=self.user)

        response = self.client.get(
            reverse("api:news:core:categories-detail", args=[category.pk])
        )
        data = response.json()

        self.assertEquals(response.status_code, 200)
        self.assertTrue("id" in data)
        self.assertTrue("name" in data)

    def test_not_known(self):
        response = self.client.get(
            reverse("api:news:core:categories-detail", args=[100])
        )
        data = response.json()

        self.assertEquals(response.status_code, 404)
        self.assertEquals(data["detail"], "No Category matches the given query.")

    def test_post(self):
        category = CategoryFactory(user=self.user)

        response = self.client.post(
            reverse("api:news:core:categories-detail", args=[category.pk])
        )
        data = response.json()

        self.assertEquals(response.status_code, 405)
        self.assertEquals(data["detail"], 'Method "POST" not allowed.')

    def test_patch(self):
        category = CategoryFactory(name="Clickbait", user=self.user)

        response = self.client.patch(
            reverse("api:news:core:categories-detail", args=[category.pk]),
            data=json.dumps({"name": "Interesting posts"}),
            content_type="application/json",
        )
        data = response.json()

        self.assertEquals(response.status_code, 200)
        self.assertEquals(data["name"], "Interesting posts")

    def test_identifier_cannot_be_changed(self):
        category = CategoryFactory(user=self.user)

        response = self.client.patch(
            reverse("api:news:core:categories-detail", args=[category.pk]),
            data=json.dumps({"id": 44}),
            content_type="application/json",
        )
        data = response.json()

        self.assertEquals(response.status_code, 200)
        self.assertEquals(data["id"], category.pk)

    def test_put(self):
        category = CategoryFactory(name="Clickbait", user=self.user)

        response = self.client.put(
            reverse("api:news:core:categories-detail", args=[category.pk]),
            data=json.dumps({"name": "Interesting posts"}),
            content_type="application/json",
        )
        data = response.json()

        self.assertEquals(response.status_code, 200)
        self.assertEquals(data["name"], "Interesting posts")

    def test_delete(self):
        category = CategoryFactory(user=self.user)

        response = self.client.delete(
            reverse("api:news:core:categories-detail", args=[category.pk])
        )

        self.assertEquals(response.status_code, 204)

    def test_category_with_unauthenticated_user(self):
        self.client.logout()

        category = CategoryFactory(user=self.user)

        response = self.client.get(
            reverse("api:news:core:categories-detail", args=[category.pk])
        )

        self.assertEquals(response.status_code, 403)

    def test_category_with_unauthorized_user(self):
        other_user = UserFactory()
        category = CategoryFactory(user=other_user)

        response = self.client.get(
            reverse("api:news:core:categories-detail", args=[category.pk])
        )

        self.assertEquals(response.status_code, 403)

    def test_read_count(self):
        category = CategoryFactory(user=self.user)
        unread_rule = FeedFactory(category=category)
        read_rule = FeedFactory(category=category)

        FeedPostFactory.create_batch(size=20, read=False, rule=unread_rule)
        FeedPostFactory.create_batch(size=20, read=True, rule=read_rule)

        response = self.client.get(
            reverse("api:news:core:categories-detail", args=[category.pk])
        )
        data = response.json()

        self.assertEquals(response.status_code, 200)
        self.assertEquals(data["unread"], 20)


class CategoryReadTestCase(TestCase):
    def setUp(self):
        self.user = UserFactory(password="test")
        self.client.force_login(self.user)

    def test_category_read(self):
        category = CategoryFactory(user=self.user)
        rules = FeedFactory.create_batch(size=5, category=category)

        for rule in rules:
            FeedPostFactory.create_batch(size=5, read=False, rule=rule)

        response = self.client.post(
            reverse("api:news:core:categories-read", args=[category.pk])
        )

        data = response.json()

        self.assertEquals(response.status_code, 201)
        self.assertEquals(data["unread"], 0)
        self.assertEquals(data["id"], category.pk)

    def test_category_unknown(self):
        response = self.client.post(
            reverse("api:news:core:categories-read", args=[101])
        )

        self.assertEquals(response.status_code, 404)

    def test_unauthenticated_user(self):
        self.client.logout()

        category = CategoryFactory(user=self.user)
        rules = FeedFactory.create_batch(size=5, category=category, user=self.user)

        for rule in rules:
            FeedPostFactory.create_batch(size=5, read=False, rule=rule)

        response = self.client.post(
            reverse("api:news:core:categories-read", args=[category.pk])
        )

        self.assertEquals(response.status_code, 403)

    def test_unauthorized_user(self):
        other_user = UserFactory()
        category = CategoryFactory(user=other_user)
        rules = FeedFactory.create_batch(size=5, category=category, user=other_user)

        for rule in rules:
            FeedPostFactory.create_batch(size=5, read=False, rule=rule)

        response = self.client.post(
            reverse("api:news:core:categories-read", args=[category.pk])
        )

        self.assertEquals(response.status_code, 403)

    def test_get(self):
        category = CategoryFactory(name="Clickbait", user=self.user)

        response = self.client.get(
            reverse("api:news:core:categories-read", args=[category.pk])
        )

        self.assertEquals(response.status_code, 405)

    def test_patch(self):
        category = CategoryFactory(name="Clickbait", user=self.user)

        response = self.client.patch(
            reverse("api:news:core:categories-read", args=[category.pk]),
            data=json.dumps({"name": "Not possible"}),
            content_type="application/json",
        )

        self.assertEquals(response.status_code, 405)

    def test_put(self):
        category = CategoryFactory(name="Clickbait", user=self.user)

        response = self.client.put(
            reverse("api:news:core:categories-read", args=[category.pk]),
            data=json.dumps({"name": "Not possible"}),
            content_type="application/json",
        )

        self.assertEquals(response.status_code, 405)

    def test_delete(self):
        category = CategoryFactory(name="Clickbait", user=self.user)

        response = self.client.delete(
            reverse("api:news:core:categories-read", args=[category.pk])
        )

        self.assertEquals(response.status_code, 405)
