# (c) cavaliba.com - test_role_class.py

import yaml
from django.test import TestCase

import app_home.cache as cache
from app_data.loader import load_broker
from app_data.models import DataInstance
from app_data.role import Role
from app_user.models import SirenePermission


class RoleFromTest(TestCase):
    def setUp(self):
        cache.clear()
        datalist = yaml.safe_load("""
            - classname: role
              keyname: role01
              displayname: Role One
            """)
        aaa = {"perms": ["p_role_create"]}
        load_broker(datalist=datalist, aaa=aaa)

    def test_from_keyname(self):
        role = Role.from_keyname(keyname="role01")
        self.assertIsNotNone(role)
        self.assertIsInstance(role, Role)
        self.assertEqual(role.keyname, "role01")

    def test_from_keyname_missing(self):
        role = Role.from_keyname(keyname="does_not_exist")
        self.assertIsNone(role)

    def test_from_id(self):
        ref = Role.from_keyname(keyname="role01")
        role = Role.from_id(id=ref.id)
        self.assertIsNotNone(role)
        self.assertIsInstance(role, Role)
        self.assertEqual(role.keyname, "role01")

    def test_from_id_missing(self):
        role = Role.from_id(id=999999)
        self.assertIsNone(role)

    def test_from_iobj(self):
        iobj = DataInstance.objects.filter(classname="role", keyname="role01").first()
        self.assertIsNotNone(iobj)
        role = Role.from_iobj(iobj=iobj)
        self.assertIsNotNone(role)
        self.assertIsInstance(role, Role)
        self.assertEqual(role.keyname, "role01")

    def test_displayname(self):
        role = Role.from_keyname(keyname="role01")
        self.assertEqual(role.displayname, "Role One")


class RoleCRUDTest(TestCase):
    def setUp(self):
        cache.clear()

    def test_create(self):
        role = Role(keyname="role_create")
        role.displayname = "Create Test"
        result = role.create()
        self.assertTrue(result)
        self.assertTrue(role.is_bound)
        found = Role.from_keyname(keyname="role_create")
        self.assertIsNotNone(found)
        self.assertEqual(found.displayname, "Create Test")

    def test_update(self):
        role = Role(keyname="role_update")
        role.create()
        role.displayname = "Updated Name"
        result = role.update()
        self.assertTrue(result)
        found = Role.from_keyname(keyname="role_update")
        self.assertEqual(found.displayname, "Updated Name")

    def test_delete(self):
        role = Role(keyname="role_delete")
        role.create()
        self.assertTrue(role.is_bound)
        result = role.delete()
        self.assertTrue(result)
        self.assertFalse(role.is_bound)
        found = Role.from_keyname(keyname="role_delete")
        self.assertIsNone(found)

    def test_enable(self):
        role = Role(keyname="role_enable")
        role.is_enabled = False
        role.create()
        result = role.enable()
        self.assertTrue(result)
        self.assertTrue(role.is_enabled)
        found = Role.from_keyname(keyname="role_enable")
        self.assertTrue(found.is_enabled)

    def test_disable(self):
        role = Role(keyname="role_disable")
        role.create()
        self.assertTrue(role.is_enabled)
        result = role.disable()
        self.assertTrue(result)
        self.assertFalse(role.is_enabled)
        found = Role.from_keyname(keyname="role_disable")
        self.assertFalse(found.is_enabled)


class RoleGetPermissionsTest(TestCase):
    """
    role_two    permissions: [perm_read, perm_write]
    role_empty  permissions: (none)
    perm_delete exists but is not assigned to any role.
    """

    def setUp(self):
        cache.clear()
        datalist = yaml.safe_load("""
            - classname: _permission
              keyname: perm_read
              displayname: Perm Read

            - classname: _permission
              keyname: perm_write
              displayname: Perm Write

            - classname: _permission
              keyname: perm_delete
              displayname: Perm Delete

            - classname: role
              keyname: role_two
              displayname: Role Two
              permissions:
                - perm_read
                - perm_write

            - classname: role
              keyname: role_empty
              displayname: Role Empty
            """)
        aaa = {"perms": ["p_permission_create", "p_role_create"]}
        load_broker(datalist=datalist, aaa=aaa)

    def test_returns_list(self):
        role = Role.from_keyname(keyname="role_two")
        self.assertIsInstance(role.get_permissions(), list)

    def test_finds_assigned_permissions(self):
        role = Role.from_keyname(keyname="role_two")
        keynames = {p.keyname for p in role.get_permissions()}
        self.assertIn("perm_read", keynames)
        self.assertIn("perm_write", keynames)

    def test_excludes_unassigned_permission(self):
        role = Role.from_keyname(keyname="role_two")
        keynames = {p.keyname for p in role.get_permissions()}
        self.assertNotIn("perm_delete", keynames)

    def test_empty_role_returns_empty(self):
        role = Role.from_keyname(keyname="role_empty")
        self.assertEqual(role.get_permissions(), [])

    def test_no_duplicates(self):
        role = Role.from_keyname(keyname="role_two")
        keynames = [p.keyname for p in role.get_permissions()]
        self.assertEqual(len(keynames), len(set(keynames)))

    def test_returns_sirenepermission_objects(self):
        role = Role.from_keyname(keyname="role_two")
        for p in role.get_permissions():
            self.assertIsInstance(p, SirenePermission)

    def test_result_cached_on_second_call(self):
        role = Role.from_keyname(keyname="role_two")
        result1 = role.get_permissions()
        result2 = role.get_permissions()
        self.assertIs(result1, result2)

    def test_sets_class_variable(self):
        role = Role.from_keyname(keyname="role_two")
        self.assertIsNone(role.permissions)
        role.get_permissions()
        self.assertIsNotNone(role.permissions)
