# (c) cavaliba.com - test_data

import yaml
from django.test import TestCase

import app_home.cache as cache
from app_data.data import Instance
from app_data.loader import load_broker
from app_data.models import DataClass, DataInstance, DataSchema
from tests import helper


class TestDataClass(TestCase):
    def setUp(self):
        cache.clear()
        helper.add_schema(
            classname="test0",
            field_definition={
                "mystring": {"dataformat": "string", "displayname": "MyString"},
            },
        )
        helper.add_instance(
            classname="test0",
            keyname="test0-01",
            fields={
                "displayname": "test0-01",
                "mystring": "data for test0-01",
            },
        )
        helper.add_schema(
            classname="test1",
            options={
                "p_create": "p_test1_create",
                "p_read": "p_test1_read",
                "p_update": "p_test1_update",
                "p_delete": "p_test1_delete",
                "p_admin": "p_test1_admin",
            },
        )
        helper.add_instance(classname="test1", keyname="test1-01")
        helper.add_schema(classname="test2")
        helper.add_schema(classname="test3")
        helper.add_schema(classname="test4")

    def test_has_apikey(self):
        classobj = DataClass.objects.get(keyname="_apikey")
        self.assertIsNotNone(classobj)
        self.assertEqual(classobj.is_enabled, True)

    def test_has_enumerate(self):
        classobj = DataClass.objects.get(keyname="_enumerate")
        self.assertIsNotNone(classobj)
        self.assertEqual(classobj.is_enabled, True)

    def test_has_pipeline(self):
        classobj = DataClass.objects.get(keyname="_pipeline")
        self.assertIsNotNone(classobj)
        self.assertEqual(classobj.is_enabled, True)

    def test_has_dataview(self):
        classobj = DataClass.objects.get(keyname="_dataview")
        self.assertIsNotNone(classobj)
        self.assertEqual(classobj.is_enabled, True)

    def test_has_site(self):
        classobj = DataClass.objects.get(keyname="site")
        self.assertIsNotNone(classobj)
        self.assertEqual(classobj.is_enabled, True)

    def test_has_app(self):
        classobj = DataClass.objects.get(keyname="app")
        self.assertIsNotNone(classobj)
        self.assertEqual(classobj.is_enabled, True)

    def test_has_sitegroup(self):
        classobj = DataClass.objects.get(keyname="sitegroup")
        self.assertIsNotNone(classobj)
        self.assertEqual(classobj.is_enabled, True)

    def test_has_sirene(self):
        classobj = DataClass.objects.get(keyname="sirene_template")
        self.assertIsNotNone(classobj)
        self.assertEqual(classobj.is_enabled, True)
        classobj = DataClass.objects.get(keyname="sirene_public")
        self.assertIsNotNone(classobj)
        self.assertEqual(classobj.is_enabled, True)
        classobj = DataClass.objects.get(keyname="sirene_message")
        self.assertIsNotNone(classobj)
        self.assertEqual(classobj.is_enabled, True)

    def test_has_schema_test1(self):
        classobj = DataClass.objects.get(keyname="test1")
        self.assertIsNotNone(classobj)
        self.assertEqual(classobj.is_enabled, True)

    def test_has_schema_test2(self):
        classobj = DataClass.objects.get(keyname="test2")
        self.assertIsNotNone(classobj)
        self.assertEqual(classobj.is_enabled, True)

    def test_has_schema_test3(self):
        classobj = DataClass.objects.get(keyname="test3")
        self.assertIsNotNone(classobj)
        self.assertEqual(classobj.is_enabled, True)

    def test_has_schema_test4(self):
        classobj = DataClass.objects.get(keyname="test4")
        self.assertIsNotNone(classobj)
        self.assertEqual(classobj.is_enabled, True)

    def test_schema_delete_allowed(self):
        datalist = yaml.safe_load("""
            - classname: _schema
              keyname: test1
              _action: delete
            """)
        aaa = {"perms": ["p_schema_write"]}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = DataClass.objects.filter(keyname="test1").first()
        self.assertIsNone(classobj)

    def test_schema_delete_not_allowed(self):
        datalist = yaml.safe_load("""
            - classname: _schema
              keyname: test1
              _action: delete
            """)
        aaa = {"perms": ["p_unknown_permission"]}
        _ = load_broker(datalist=datalist, aaa=aaa)

        classobj = DataClass.objects.filter(keyname="test1").first()
        self.assertIsNotNone(classobj)

    def test_schema_disable_enable_allowed(self):
        datalist = yaml.safe_load("""
            - classname: _schema
              keyname: test1
              _action: disable
            """)
        aaa = {"perms": ["p_schema_write"]}

        load_broker(datalist=datalist, aaa=aaa)
        classobj = DataClass.objects.filter(keyname="test1").first()
        self.assertEqual(classobj.is_enabled, False)

        datalist = yaml.safe_load("""
            - classname: _schema
              keyname: test1
              _action: enable
            """)
        load_broker(datalist=datalist, aaa=aaa)
        classobj = DataClass.objects.filter(keyname="test1").first()
        self.assertEqual(classobj.is_enabled, True)

    def test_schema_disable_enable_not_allowed(self):
        datalist = yaml.safe_load("""
            - classname: _schema
              keyname: test1
              _action: disable
            """)
        aaa = {"perms": ["p_schema_read"]}
        load_broker(datalist=datalist, aaa=aaa)

        classobj = DataClass.objects.filter(keyname="test1").first()
        self.assertEqual(classobj.is_enabled, True)

    def test_schemafield_delete_allowed(self):
        datalist = yaml.safe_load("""
            - classname: _schema
              keyname: test0
              mystring:
                  _action: delete
            """)
        aaa = {"perms": ["p_schema_write"]}
        _ = load_broker(datalist=datalist, aaa=aaa)

        obj = DataSchema.objects.filter(classname="test0", keyname="mystring").first()
        self.assertIsNone(obj)

        instance = Instance(classname="test0")
        self.assertNotIn("mystring", instance.fields)

    def test_schemafield_delete_not_allowed(self):
        datalist = yaml.safe_load("""
            - classname: _schema
              keyname: test0
              mystring:
                  _action: delete
            """)
        aaa = {"perms": ["p_unknown_permission"]}
        _ = load_broker(datalist=datalist, aaa=aaa)

        instance = Instance.from_keyname(classname="test0", keyname="test0-01")
        self.assertIn("mystring", instance.fields)

    def test_instance_read_allowed_class(self):
        instance = Instance.from_keyname(classname="test1", keyname="test1-01")
        aaa = {"perms": ["p_test1_read"]}
        r = instance.has_read_permission(aaa=aaa)
        self.assertTrue(r)

    def test_instance_read_allowed_allclass(self):
        instance = Instance.from_keyname(classname="test0", keyname="test0-01")
        self.assertEqual(instance.displayname, "test0-01")
        aaa = {"perms": ["p_data_read"]}
        r = instance.has_read_permission(aaa=aaa)
        self.assertTrue(r)

    def test_instance_read_allowed_admin(self):
        instance = Instance.from_keyname(classname="test1", keyname="test1-01")
        aaa = {"perms": ["p_data_admin"]}
        r = instance.has_read_permission(aaa=aaa)
        self.assertTrue(r)

    def test_instance_read_not_allowed(self):
        instance = Instance.from_keyname(classname="test1", keyname="test1-01")
        aaa = {"perms": ["p_test1_read2"]}
        r = instance.has_read_permission(aaa=aaa)
        self.assertFalse(r)

    def test_instance_delete_allowed(self):
        datalist = yaml.safe_load("""
            - classname: test1
              keyname: 'test1-01'
              _action: delete
            """)
        aaa = {"perms": ["p_test1_delete"]}
        load_broker(datalist=datalist, aaa=aaa)

        classobj = DataClass.objects.filter(keyname="test1").first()
        iobj = DataInstance.objects.filter(classname=classobj.keyname, keyname="test1-01").first()
        self.assertIsNone(iobj)

        instance = Instance.from_keyname(classname="test1", keyname="test1-01")
        self.assertIsNone(instance)

    def test_instance_delete_not_allowed(self):
        datalist = yaml.safe_load("""
            - classname: test1
              keyname: 'test1-01'
              _action: delete
            """)
        aaa = {"perms": ["p_test1_delete2"]}
        load_broker(datalist=datalist, aaa=aaa)

        classobj = DataClass.objects.filter(keyname="test1").first()
        iobj = DataInstance.objects.filter(classname=classobj.keyname, keyname="test1-01").first()
        self.assertIsNotNone(iobj)

        instance = Instance.from_keyname(classname="test1", keyname="test1-01")
        self.assertTrue(instance.is_bound)

    def test_instance_enable_allowed(self):
        datalist = yaml.safe_load("""
            - classname: test1
              keyname: 'test1-01'
              _action: disable
            """)
        aaa = {"perms": ["p_test1_update"]}
        load_broker(datalist=datalist, aaa=aaa)
        instance = Instance.from_keyname(classname="test1", keyname="test1-01")
        self.assertFalse(instance.is_enabled)

        datalist = yaml.safe_load("""
            - classname: test1
              keyname: 'test1-01'
              _action: enable
            """)
        aaa = {"perms": ["p_test1_update"]}
        load_broker(datalist=datalist, aaa=aaa)
        instance = Instance.from_keyname(classname="test1", keyname="test1-01")
        self.assertTrue(instance.is_enabled)

    def test_instance_enable_not_allowed(self):
        datalist = yaml.safe_load("""
            - classname: test1
              keyname: 'test1-01'
              _action: disable
            """)
        aaa = {"perms": ["p_test1_update"]}
        load_broker(datalist=datalist, aaa=aaa)
        instance = Instance.from_keyname(classname="test1", keyname="test1-01")
        self.assertFalse(instance.is_enabled)

        datalist = yaml.safe_load("""
            - classname: test1
              keyname: 'test1-01'
              _action: enable
            """)
        aaa = {"perms": ["p_test1_update2"]}
        load_broker(datalist=datalist, aaa=aaa)
        instance = Instance.from_keyname(classname="test1", keyname="test1-01")
        self.assertFalse(instance.is_enabled)

    def test_instance_disable_not_allowed(self):
        datalist = yaml.safe_load("""
            - classname: test1
              keyname: 'test1-01'
              _action: disable
            """)
        aaa = {"perms": ["p_test1_update2"]}
        load_broker(datalist=datalist, aaa=aaa)

        instance = Instance.from_keyname(classname="test1", keyname="test1-01")
        self.assertTrue(instance.is_enabled)


class InstanceExistsTest(TestCase):
    def setUp(self):
        cache.clear()
        helper.add_schema(classname="testexists")
        helper.add_instance(classname="testexists", keyname="obj01")

    def test_exists_returns_true(self):
        self.assertTrue(Instance.exists(classname="testexists", keyname="obj01"))

    def test_exists_returns_false_unknown_keyname(self):
        self.assertFalse(Instance.exists(classname="testexists", keyname="no_such_key"))

    def test_exists_returns_false_unknown_classname(self):
        self.assertFalse(Instance.exists(classname="no_such_class", keyname="obj01"))

    def test_exists_returns_false_none_keyname(self):
        self.assertFalse(Instance.exists(classname="testexists", keyname=None))

    def test_exists_returns_false_none_classname(self):
        self.assertFalse(Instance.exists(classname=None, keyname="obj01"))

    def test_exists_subclass_uses_classname(self):
        helper.add_user(login="userexists01")
        from app_data.user import User

        self.assertTrue(User.exists(keyname="userexists01"))
        self.assertFalse(User.exists(keyname="no_such_user"))
