""" test for app action functionality """
import os
import json
from unittest.mock import patch

from django.contrib.auth.models import Group
from django.core.files.uploadedfile import SimpleUploadedFile
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory

from bookwyrm import forms, models, views
from bookwyrm.management.commands import initdb
from bookwyrm.tests.validate_html import validate_html


class FederationViews(TestCase):
    """every response to a get request, html or json"""

    @classmethod
    def setUpTestData(self):  # pylint: disable=bad-classmethod-argument
        """we need basic test data and mocks"""
        with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
            "bookwyrm.activitystreams.populate_stream_task.delay"
        ), patch("bookwyrm.lists_stream.populate_lists_task.delay"):
            self.local_user = models.User.objects.create_user(
                "mouse@local.com",
                "mouse@mouse.mouse",
                "password",
                local=True,
                localname="mouse",
            )
        with patch("bookwyrm.models.user.set_remote_server.delay"):
            self.remote_user = models.User.objects.create_user(
                "rat",
                "rat@rat.com",
                "ratword",
                local=False,
                remote_id="https://example.com/users/rat",
                inbox="https://example.com/users/rat/inbox",
                outbox="https://example.com/users/rat/outbox",
            )
        initdb.init_groups()
        initdb.init_permissions()
        group = Group.objects.get(name="moderator")
        self.local_user.groups.set([group])

        models.SiteSettings.objects.create()

    def setUp(self):
        """individual test setup"""
        self.factory = RequestFactory()

    def test_federation_page(self):
        """there are so many views, this just makes sure it LOADS"""
        view = views.Federation.as_view()
        request = self.factory.get("")
        request.user = self.local_user

        result = view(request)
        self.assertIsInstance(result, TemplateResponse)
        validate_html(result.render())
        self.assertEqual(result.status_code, 200)

    def test_instance_page(self):
        """there are so many views, this just makes sure it LOADS"""
        server = models.FederatedServer.objects.create(server_name="hi.there.com")
        view = views.FederatedServer.as_view()
        request = self.factory.get("")
        request.user = self.local_user

        result = view(request, server.id)
        self.assertIsInstance(result, TemplateResponse)
        validate_html(result.render())
        self.assertEqual(result.status_code, 200)

    def test_server_page_block(self):
        """block a server"""
        server = models.FederatedServer.objects.create(
            server_name="hi.there.com", application_type="bookwyrm"
        )
        connector = models.Connector.objects.get(
            identifier="hi.there.com",
        )
        self.remote_user.federated_server = server
        self.remote_user.save(update_fields=["federated_server"])

        self.assertEqual(server.status, "federated")

        view = views.block_server
        request = self.factory.post("")
        request.user = self.local_user

        with patch("bookwyrm.suggested_users.bulk_remove_instance_task.delay") as mock:
            view(request, server.id)
        self.assertEqual(mock.call_count, 1)

        server.refresh_from_db()
        self.remote_user.refresh_from_db()
        self.assertEqual(server.status, "blocked")

        # and the user was deactivated
        self.assertFalse(self.remote_user.is_active)
        self.assertEqual(self.remote_user.deactivation_reason, "domain_block")

        # and the connector was disabled
        connector.refresh_from_db()
        self.assertFalse(connector.active)
        self.assertEqual(connector.deactivation_reason, "domain_block")

    def test_server_page_unblock(self):
        """unblock a server"""
        server = models.FederatedServer.objects.create(
            server_name="hi.there.com", status="blocked", application_type="bookwyrm"
        )
        connector = models.Connector.objects.get(
            identifier="hi.there.com",
        )
        connector.active = False
        connector.deactivation_reason = "domain_block"
        connector.save()

        self.remote_user.federated_server = server
        self.remote_user.is_active = False
        self.remote_user.deactivation_reason = "domain_block"
        self.remote_user.save(
            update_fields=["federated_server", "is_active", "deactivation_reason"]
        )

        request = self.factory.post("")
        request.user = self.local_user

        with patch("bookwyrm.suggested_users.bulk_add_instance_task.delay") as mock:
            views.unblock_server(request, server.id)
        self.assertEqual(mock.call_count, 1)
        self.assertEqual(mock.call_args[0][0], server.id)

        server.refresh_from_db()
        self.remote_user.refresh_from_db()
        self.assertEqual(server.status, "federated")

        # and the user was re-activated
        self.assertTrue(self.remote_user.is_active)
        self.assertIsNone(self.remote_user.deactivation_reason)

        # and the connector was re-enabled
        connector.refresh_from_db()
        self.assertTrue(connector.active)
        self.assertIsNone(connector.deactivation_reason)

    def test_add_view_get(self):
        """there are so many views, this just makes sure it LOADS"""
        # create mode
        view = views.AddFederatedServer.as_view()
        request = self.factory.get("")
        request.user = self.local_user

        result = view(request)
        self.assertIsInstance(result, TemplateResponse)
        validate_html(result.render())
        self.assertEqual(result.status_code, 200)

    def test_add_view_post_create(self):
        """create a server entry"""
        form = forms.ServerForm()
        form.data["server_name"] = "remote.server"
        form.data["application_type"] = "coolsoft"
        form.data["status"] = "blocked"

        view = views.AddFederatedServer.as_view()
        request = self.factory.post("", form.data)
        request.user = self.local_user

        view(request)
        server = models.FederatedServer.objects.get()
        self.assertEqual(server.server_name, "remote.server")
        self.assertEqual(server.application_type, "coolsoft")
        self.assertEqual(server.status, "blocked")

    # pylint: disable=consider-using-with
    def test_import_blocklist(self):
        """load a json file with a list of servers to block"""
        server = models.FederatedServer.objects.create(server_name="hi.there.com")
        self.remote_user.federated_server = server
        self.remote_user.save(update_fields=["federated_server"])

        data = [
            {"instance": "server.name", "url": "https://explanation.url"},  # new server
            {"instance": "hi.there.com", "url": "https://explanation.url"},  # existing
            {"a": "b"},  # invalid
        ]
        json.dump(data, open("file.json", "w"))  # pylint: disable=unspecified-encoding

        view = views.ImportServerBlocklist.as_view()
        request = self.factory.post(
            "",
            {
                "json_file": SimpleUploadedFile(
                    "file.json", open("file.json", "rb").read()
                )
            },
        )
        request.user = self.local_user

        view(request)
        server.refresh_from_db()
        self.remote_user.refresh_from_db()

        self.assertEqual(models.FederatedServer.objects.count(), 2)
        self.assertEqual(server.status, "blocked")
        self.assertFalse(self.remote_user.is_active)
        created = models.FederatedServer.objects.get(server_name="server.name")
        self.assertEqual(created.status, "blocked")
        self.assertEqual(created.notes, "https://explanation.url")

        # remove file.json after test
        os.remove("file.json")
