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.models import Post
from newsreader.news.core.tests.factories import CategoryFactory, FeedPostFactory


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

    def test_simple(self):
        rule = FeedFactory(user=self.user)

        response = self.client.get(
            reverse("api:news:collection:rules-detail", args=[rule.pk])
        )
        data = response.json()

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

        self.assertTrue("name" in data)
        self.assertTrue("url" in data)
        self.assertTrue("favicon" in data)
        self.assertTrue("category" in data)
        self.assertTrue("type" in data)

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

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

    def test_post(self):
        rule = FeedFactory(user=self.user)

        response = self.client.post(
            reverse("api:news:collection:rules-detail", args=[rule.pk])
        )
        data = response.json()

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

    def test_patch(self):
        rule = FeedFactory(name="BBC", user=self.user)

        response = self.client.patch(
            reverse("api:news:collection:rules-detail", args=[rule.pk]),
            data=json.dumps({"name": "The guardian"}),
            content_type="application/json",
        )
        data = response.json()

        self.assertEquals(response.status_code, 200)
        self.assertEquals(data["name"], "The guardian")

    def test_identifier_cannot_be_changed(self):
        rule = FeedFactory(user=self.user)

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

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

    def test_category_change(self):
        rule = FeedFactory(user=self.user)
        category = CategoryFactory(user=self.user)

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

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

    def test_put(self):
        rule = FeedFactory(name="BBC", user=self.user)

        response = self.client.put(
            reverse("api:news:collection:rules-detail", args=[rule.pk]),
            data=json.dumps({"name": "BBC", "url": "https://www.bbc.co.uk"}),
            content_type="application/json",
        )
        data = response.json()

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

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

        rule = FeedFactory(name="BBC", user=self.user)

        response = self.client.patch(
            reverse("api:news:collection:rules-detail", args=[rule.pk]),
            data=json.dumps({"name": "The guardian"}),
            content_type="application/json",
        )

        self.assertEquals(response.status_code, 403)

    def test_rule_with_unauthorized_user(self):
        other_user = UserFactory()
        rule = FeedFactory(name="BBC", user=other_user)

        response = self.client.patch(
            reverse("api:news:collection:rules-detail", args=[rule.pk]),
            data=json.dumps({"name": "The guardian"}),
            content_type="application/json",
        )

        self.assertEquals(response.status_code, 403)

    def test_read_count(self):
        rule = FeedFactory(user=self.user)

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

        response = self.client.get(
            reverse("api:news:collection:rules-detail", args=[rule.pk])
        )
        data = response.json()

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


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

    def test_rule_read(self):
        rule = FeedFactory(user=self.user)

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

        response = self.client.post(
            reverse("api:news:collection:rules-read", args=[rule.pk])
        )
        data = response.json()

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

    def test_rule_unknown(self):
        response = self.client.post(
            reverse("api:news:collection:rules-read", args=[101])
        )

        self.assertEquals(response.status_code, 404)

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

        rule = FeedFactory(user=self.user)

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

        response = self.client.post(
            reverse("api:news:collection:rules-read", args=[rule.pk])
        )

        self.assertEquals(response.status_code, 403)

    def test_unauthorized_user(self):
        other_user = UserFactory()
        rule = FeedFactory(user=other_user)

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

        response = self.client.post(
            reverse("api:news:collection:rules-read", args=[rule.pk])
        )

        self.assertEquals(response.status_code, 403)
        self.assertEquals(Post.objects.filter(read=False).count(), 20)

    def test_get(self):
        rule = FeedFactory(user=self.user)

        response = self.client.get(
            reverse("api:news:collection:rules-read", args=[rule.pk])
        )

        self.assertEquals(response.status_code, 405)

    def test_patch(self):
        rule = FeedFactory(name="BBC", user=self.user)

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

        self.assertEquals(response.status_code, 405)

    def test_put(self):
        rule = FeedFactory(name="BBC", user=self.user)

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

        self.assertEquals(response.status_code, 405)

    def test_delete(self):
        rule = FeedFactory(user=self.user)

        response = self.client.delete(
            reverse("api:news:collection:rules-read", args=[rule.pk])
        )

        self.assertEquals(response.status_code, 405)
