"""Unit tests for the reports routes."""

from unittest.mock import patch

from routes import get_reports_overview, post_reports_overview_attribute
from routes.plugins.auth_plugin import EDIT_ENTITY_PERMISSION, EDIT_REPORT_PERMISSION

from tests.base import DataModelTestCase


class ReportsOverviewTest(DataModelTestCase):
    """Unit tests for the reports overview routes."""

    def setUp(self):
        """Extend to set up the database contents."""
        super().setUp()
        self.email = "jenny@example.org"
        self.other_mail = "john@example.org"
        self.database.sessions.find_one.return_value = {"user": "jenny", "email": self.email}
        self.database.reports_overviews.find_one.return_value = {"_id": "id", "title": "Reports", "subtitle": ""}

    def assert_change_description(self, attribute: str, old_value=None, new_value=None) -> None:
        """Assert that a change description is added to the new reports overview."""
        inserted = self.database.reports_overviews.insert_one.call_args_list[0][0][0]
        delta = f" from '{old_value}' to '{new_value}'" if old_value and new_value else ""
        description = f"jenny changed the {attribute} of the reports overview{delta}."
        self.assertEqual({"email": self.email, "description": description, "uuids": []}, inserted["delta"])

    @patch("bottle.request")
    def test_change_title(self, request):
        """Test that a reports overview title can be changed."""
        request.json = {"title": "All the reports"}
        self.assertEqual({"ok": True}, post_reports_overview_attribute("title", self.database))
        self.assert_change_description("title", "Reports", "All the reports")

    @patch("bottle.request")
    def test_change_title_unchanged(self, request):
        """Test that the reports overview title is not changed if the new value is equal to the old value."""
        request.json = {"title": "Reports"}
        self.assertEqual({"ok": True}, post_reports_overview_attribute("title", self.database))
        self.database.reports_overviews.insert_one.assert_not_called()

    @patch("bottle.request")
    def test_post_unsafe_comment(self, request):
        """Test that comments are sanitized, since they are displayed as inner HTML in the frontend."""
        request.json = {"comment": 'Comment with script<script type="text/javascript">alert("Danger")</script>'}
        self.assertEqual({"ok": True}, post_reports_overview_attribute("comment", self.database))
        self.assert_change_description("comment", "None", "Comment with script")

    @patch("bottle.request")
    def test_change_layout(self, request):
        """Test that a reports overview layout can be changed."""
        request.json = {"layout": [{"x": 1, "y": 2}]}
        self.assertEqual({"ok": True}, post_reports_overview_attribute("layout", self.database))
        self.assert_change_description("layout")

    @patch("bottle.request")
    def test_change_permission(self, request):
        """Test that the editors can be changed."""
        request.json = {"permissions": {EDIT_ENTITY_PERMISSION: [self.other_mail]}}
        self.assertEqual({"ok": True}, post_reports_overview_attribute("permissions", self.database))
        self.assert_change_description("permissions", "None", f"{{'{EDIT_ENTITY_PERMISSION}': ['{self.other_mail}']}}")

    @patch("bottle.request")
    def test_clear_permissions(self, request):
        """Test that the editors can be cleared."""
        self.database.reports_overviews.find_one.return_value = {
            "_id": "id",
            "title": "Reports",
            "subtitle": "",
            "permissions": {
                EDIT_REPORT_PERMISSION: [self.other_mail, self.email],
                EDIT_ENTITY_PERMISSION: [self.email],
            },
        }
        request.json = {"permissions": {}}
        self.assertEqual({"ok": True}, post_reports_overview_attribute("permissions", self.database))

        old_string = (
            f"{{'{EDIT_REPORT_PERMISSION}': ['{self.other_mail}', '{self.email}'], "
            f"'{EDIT_ENTITY_PERMISSION}': ['{self.email}']}}"
        )
        self.assert_change_description("permissions", old_string, "{}")

    @patch("bottle.request")
    def test_remove_permissions(self, request):
        """Test that other editors can be removed from the editors."""
        self.database.reports_overviews.find_one.return_value = {
            "_id": "id",
            "title": "Reports",
            "subtitle": "",
            "permissions": {EDIT_REPORT_PERMISSION: [self.other_mail, self.email]},
        }
        request.json = {"permissions": {EDIT_REPORT_PERMISSION: [self.email]}}
        self.assertEqual({"ok": True}, post_reports_overview_attribute("permissions", self.database))
        self.assert_change_description(
            "permissions",
            f"{{'{EDIT_REPORT_PERMISSION}': ['{self.other_mail}', '{self.email}']}}",
            f"{{'{EDIT_REPORT_PERMISSION}': ['{self.email}']}}",
        )

    @patch("bottle.request")
    def test_cannot_remove_own_permission(self, request):
        """Test that other editors can be removed from the editors."""
        self.database.reports_overviews.find_one.return_value = {
            "_id": "id",
            "title": "Reports",
            "subtitle": "",
            "permissions": {EDIT_REPORT_PERMISSION: [self.other_mail, self.email]},
        }
        request.json = {"permissions": {EDIT_REPORT_PERMISSION: [self.other_mail]}}
        self.assertEqual({"ok": True}, post_reports_overview_attribute("permissions", self.database))
        self.assert_change_description(
            "permissions",
            f"{{'{EDIT_REPORT_PERMISSION}': ['{self.other_mail}', '{self.email}']}}",
            f"{{'{EDIT_REPORT_PERMISSION}': ['{self.other_mail}', 'jenny']}}",
        )

    @patch("bottle.request")
    def test_can_remove_own_edit_entity_permission(self, request):
        """Test that editors can remove their entity edit permission."""
        self.database.reports_overviews.find_one.return_value = {
            "_id": "id",
            "title": "Reports",
            "subtitle": "",
            "permissions": {EDIT_ENTITY_PERMISSION: [self.other_mail, self.email]},
        }
        request.json = {"permissions": {EDIT_ENTITY_PERMISSION: [self.other_mail]}}
        self.assertEqual({"ok": True}, post_reports_overview_attribute("permissions", self.database))
        self.assert_change_description(
            "permissions",
            f"{{'{EDIT_ENTITY_PERMISSION}': ['{self.other_mail}', '{self.email}']}}",
            f"{{'{EDIT_ENTITY_PERMISSION}': ['{self.other_mail}']}}",
        )

    def test_get_reports_overview(self):
        """Test that a report can be retrieved and credentials are hidden."""
        self.assertEqual({"_id": "id", "title": "Reports", "subtitle": ""}, get_reports_overview(self.database))
