from django.utils import timezone

from ichec_django_core.models import Member

from ichec_django_core.test import (
    AuthAPITestCase,
    add_group_permissions,
    setup_default_users_and_groups,
)

from marinerg_test_access.models import AccessCall
from marinerg_test_access.test import setup_default_access_calls


class TestAccessCallView(AuthAPITestCase):

    template = {
        "title": "My Access Call",
        "description": "Description of my access call",
        "coordinator": "",
        "board_chair": "",
        "board_members": [],
        "closing_date": str(timezone.now()),
        "form": {
            "groups": [
                {
                    "fields": [
                        {
                            "label": "Requires Support",
                            "key": "requires_support",
                            "description": "Do you require facility support?",
                            "field_type": "BOOLEAN",
                        }
                    ]
                }
            ]
        },
    }

    update_template = {"description": "Modified description of my access call"}

    def setUp(self):
        self.url = "/api/access_calls/"

        setup_default_users_and_groups()
        add_group_permissions(
            "admins",
            AccessCall,
            [
                "view_accesscall",
                "change_accesscall",
                "add_accesscall",
                "delete_accesscall",
            ],
        )
        add_group_permissions("members", AccessCall, ["view_accesscall"])

        self.internal, self.public, self.inactive = setup_default_access_calls()

    def get_template(self, username: str = "admin_user") -> dict:
        template = self.template
        template["coordinator"] = self.get_member_url(username)
        template["board_chair"] = self.get_member_url(username)
        return template

    def check_response(self, returned, expected, skip_keys: tuple = ()):
        for key, expected_value in expected.items():

            if key in skip_keys:
                continue

            returned_value = returned[key]
            if isinstance(expected_value, dict):
                self.compare_dicts(returned_value, expected_value, skip_keys)
            elif isinstance(expected_value, list):
                self.assertEqual(len(expected_value), len(returned_value))
            else:
                self.assertEqual(returned_value, expected_value)

    def test_list_access(self):

        scenarios = (
            ["", 1, 200, "Public can list public items"],
            ["regular_user", 1, 200, "Registered can list public items"],
            ["member", 2, 200, "Member can list all items"],
            ["coordinator", 2, 200, "Coordinator can list item"],
            ["reviewer1", 2, 200, "Reviewer can list item"],
            ["chair", 2, 200, "Chair can list item"],
        )
        for user, count, status, msg in scenarios:
            if user:
                items = self.assert_status(self.auth_list(user), status, msg)
            else:
                items = self.assert_status(self.public_list(), status, msg)

            self.assertEqual(items["count"], count, msg)

    def test_detail_access(self):

        public = self.public.id
        internal = self.internal.id
        scenarios = (
            ["", public, 200, "Public can view public item"],
            ["", internal, 404, "Public can't view internal item"],
            ["regular_user", public, 200, "Registered can view public item"],
            ["regular_user", internal, 404, "Registered can't view internal item"],
            ["member", public, 200, "Member can view public item"],
            ["member", internal, 200, "Member can view internal item"],
            ["coordinator", internal, 200, "Coordinator can view internal item"],
            ["chair", internal, 200, "Chair can view internal item"],
            ["reviewer1", internal, 200, "Reviewer can view internal item"],
        )

        for user, item, status, msg in scenarios:
            if user:
                self.assert_status(self.auth_detail(user, item), status, msg)
            else:
                self.assert_status(self.detail(item), status, msg)

    def test_create_permissions(self):

        scenarios = (
            ["", 401, "Public can't create, no auth"],
            ["regular_user", 403, "Registered can't create, no perm"],
            ["member", 403, "Member can't create, no perm"],
            ["admin_user", 201, "Admin can create"],
        )

        for user, status, msg in scenarios:
            if user:
                self.assert_status(
                    self.auth_create(user, self.get_template()), status, msg
                )
            else:
                self.assert_status(self.create(self.get_template()), status, msg)

    def test_update_consortium_admin(self):
        created = self.assert_201(self.auth_create("admin_user", self.get_template()))

        for key, value in self.update_template.items():
            created[key] = value

        created["form"]["groups"][0]["fields"].append(
            {
                "label": "Requires More Support",
                "key": "requires_more_support",
                "description": "Do you require more facility support?",
                "field_type": "BOOLEAN",
            }
        )

        updated = self.assert_200(
            self.auth_update("admin_user", created["id"], created)
        )
        self.assertTrue(
            updated["description"] == "Modified description of my access call"
        )
        self.assertTrue(len(updated["form"]["groups"][0]["fields"]) == 2)
