from datetime import datetime
from plone import api
from ploneintranet.testing import temporary_registry_record
from ploneintranet.workspace.tests.base import BaseTestCase


class TestCaseManagerView(BaseTestCase):
    def setUp(self):
        self.portal = self.layer["portal"]
        self.request = self.layer["request"]

    def get_view(self, options={}):
        """Get a fresh @@case-manager view
        adding options to the request
        """
        request = self.request.clone()
        request.form.update(options)
        return api.content.get_view(
            "case-manager", self.portal.apps["case-manager"], request
        )

    def test_review_states_select(self):
        """Check if the review state select is configured properly"""
        case_manager = self.get_view()
        states = case_manager.get_states()
        self.assertEqual(
            list(map(case_manager.get_review_state_title, states)),
            ["New", "Pending/Pending review", "Published", "Rejected", "Frozen"],
        )

    def test_review_states_select_mismatch(self):
        """Check if the review state select still works if states in registry
        and workflow tool don't match
        """
        case_manager = self.get_view()
        with temporary_registry_record(
            "ploneintranet.workspace.case_manager.states",
            ("new", "pending", "proposed", "rejected", "frozen"),
        ):
            states = case_manager.get_states()
            self.assertEqual(
                list(map(case_manager.get_review_state_title, states)),
                [
                    "New",
                    "Pending/Pending review",
                    "proposed",
                    "Rejected",
                    "Frozen",
                ],
            )

    def test_batching(self):
        """Test the case manager batching"""
        case_manager = self.get_view()
        self.assertEqual(case_manager.batch_size, 5)
        self.assertEqual(case_manager.batch_start, 0)
        case_manager.cases = lambda: list(range(4))
        self.assertEqual(case_manager.next_batch_url, "")
        case_manager = self.get_view()
        case_manager.cases = lambda: list(range(5))
        self.assertTrue(
            case_manager.next_batch_url.endswith(
                "/plone/apps/case-manager/@@case-manager?b_start=5"
            )
        )
        case_manager = self.get_view()
        case_manager.cases = lambda: list(range(6))
        self.assertTrue(
            case_manager.next_batch_url.endswith(
                "/plone/apps/case-manager/@@case-manager?b_start=5"
            )
        )

    def test_utf8(self):
        case_manager = self.get_view(
            options={
                "path": "/Plone/workspaces",
                "object_provides": (
                    "ploneintranet.workspace.interfaces." "ICaseManagerAware"
                ),
                "is_archived": False,
                "SearchableText": "St\xc3\xb6rung",
            }
        )
        cases = case_manager.cases()
        self.assertGreaterEqual(len(cases), 0)

    def test_date_query_earliest(self):
        case_manager = self.get_view(options={"earliest_created": "2018-12-18"})
        date_query = case_manager.date_query()
        self.assertEqual(date_query, {"created__gt": datetime(2018, 12, 18, 0, 0)})

    def test_date_query_latest(self):
        case_manager = self.get_view(options={"latest_modified": "2018-12-20"})
        date_query = case_manager.date_query()
        self.assertEqual(date_query, {"modified__lt": datetime(2018, 12, 20, 0, 0)})

    def test_date_query_both(self):
        case_manager = self.get_view(
            options={"earliest_created": "2018-12-18", "latest_created": "2018-12-20"}
        )
        date_query = case_manager.date_query()
        self.assertEqual(
            date_query,
            {
                "created__range": (
                    datetime(2018, 12, 18, 0, 0),
                    datetime(2018, 12, 20, 0, 0),
                )
            },
        )

    def test_do_not_break_when_user_can_search_but_not_view(self):
        """Check that a user that has the Access contents information permission
        but not the View permission does not break the case maanger
        """
        # setup
        case = api.content.create(
            type="ploneintranet.workspace.case",
            id="demo-case",
            container=self.portal.workspaces,
        )
        self.solr_commit()

        # Normally a TeamMember can search and view all the cases
        with api.env.adopt_roles("TeamMember"):
            self.assertTrue(
                api.user.has_permission(
                    obj=case, permission="Access contents information"
                )
            )
            self.assertTrue(api.user.has_permission(obj=case, permission="View"))
            case_manager = self.get_view()
            searchable_cases = list(case_manager.cases())
            self.assertEqual(len(searchable_cases), 1)
            viewable_cases = list(filter(case_manager.brain2view, searchable_cases))
            # In this case the viewable and searchable case are the same
            self.assertListEqual(viewable_cases, searchable_cases)
            case_manager()

        # Now we tweak the wf to allow the TeamMember only to search,
        # but not view the case
        pw = api.portal.get_tool("portal_workflow")
        wf = pw.getWorkflowsFor(case)[0]
        state = wf.states["new"]
        state.permission_roles["View"] = ("Manager",)
        wf.updateRoleMappingsFor(case)
        self.solr_commit()

        with api.env.adopt_roles("TeamMember"):
            self.assertTrue(
                api.user.has_permission(
                    obj=case, permission="Access contents information"
                )
            )
            self.assertFalse(api.user.has_permission(obj=case, permission="View"))
            case_manager = self.get_view()
            searchable_cases = case_manager.cases()
            self.assertEqual(len(searchable_cases), 1)
            viewable_cases = list(filter(case_manager.brain2view, searchable_cases))
            # In this case while we have searchable case we do not have viewable cases
            self.assertListEqual(viewable_cases, [])
            # but the view does not crash
            case_manager()
