# (c) cavaliba.com - tests / pipeline bulk

import yaml
from django.core.cache import cache as cache_django
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 tests import helper


class PipelineBulkTest(TestCase):
    def setUp(self):
        helper.add_admin_user(login="unittest")
        cache.clear()
        cache_django.clear()

        helper.add_schema(
            classname="test",
            field_definition={"mystring": {"dataformat": "string", "displayname": "MyString"}},
        )

        helper.add_instance(
            classname="test",
            keyname="inst01",
            fields={"mystring": "active", "displayname": "inst01"},
        )
        helper.add_instance(
            classname="test",
            keyname="inst02",
            fields={"mystring": "active", "displayname": "inst02"},
        )
        helper.add_instance(
            classname="test",
            keyname="inst03",
            fields={"mystring": "inactive", "displayname": "inst03"},
        )

    def test_pipeline_bulk_disable_on_criteria(self):

        datalist = yaml.safe_load("""
            - classname: _pipeline
              keyname: pipeline_bulk_disable
              displayname: pipeline_bulk_disable
              description: disable instances where mystring=inactive
              is_enabled: True
              content: |
                  tasks:
                  - set_condition: [IS_INACTIVE, field_match, mystring, '^inactive$']
                  - field_set: [IS_INACTIVE, _action, disable]
            """)
        aaa = {"perms": ["p_pipeline_create"]}
        load_broker(datalist=datalist, aaa=aaa)

        aaa = {"perms": ["p_data_admin", "p_pipeline_run"]}
        count_ok, count_discarded, errors = helper.run_pipeline(
            "pipeline_bulk_disable", ["test"], aaa=aaa
        )

        self.assertEqual(errors, [])
        self.assertEqual(count_discarded, 0)
        self.assertEqual(count_ok, 3)

        inst01 = Instance.from_keyname(classname="test", keyname="inst01")
        inst02 = Instance.from_keyname(classname="test", keyname="inst02")
        inst03 = Instance.from_keyname(classname="test", keyname="inst03")

        self.assertTrue(inst01.is_enabled)
        self.assertTrue(inst02.is_enabled)
        self.assertFalse(inst03.is_enabled)


class PipelineBuiltinDisableOutOfSyncTest(TestCase):
    def setUp(self):
        helper.add_admin_user(login="unittest")
        cache.clear()
        cache_django.clear()

        helper.add_schema(
            classname="test",
            field_definition={"last_sync": {"dataformat": "datetime", "displayname": "Last Sync"}},
        )

    def test_bulk_disable_stale_asset(self):

        helper.add_instance(
            classname="test", keyname="stale", fields={"last_sync": "2020-01-01 00:00:00"}
        )

        aaa = {"perms": ["p_data_admin", "p_pipeline_run"]}
        count_ok, count_discarded, errors = helper.run_pipeline(
            "bulk_disable_out_of_sync", ["test"], aaa=aaa
        )

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 1)
        self.assertEqual(count_discarded, 0)

        inst = Instance.from_keyname(classname="test", keyname="stale")
        self.assertFalse(inst.is_enabled)

    def test_bulk_keep_recent_asset(self):

        helper.add_instance(
            classname="test", keyname="recent", fields={"last_sync": "2099-12-31 23:59:59"}
        )

        aaa = {"perms": ["p_data_admin", "p_pipeline_run"]}
        count_ok, count_discarded, errors = helper.run_pipeline(
            "bulk_disable_out_of_sync", ["test"], aaa=aaa
        )

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 0)
        self.assertEqual(count_discarded, 1)

        inst = Instance.from_keyname(classname="test", keyname="recent")
        self.assertTrue(inst.is_enabled)

    def test_bulk_skip_asset_without_last_sync(self):

        helper.add_instance(classname="test", keyname="nosync", fields={})

        aaa = {"perms": ["p_data_admin", "p_pipeline_run"]}
        count_ok, count_discarded, errors = helper.run_pipeline(
            "bulk_disable_out_of_sync", ["test"], aaa=aaa
        )

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 0)
        self.assertEqual(count_discarded, 1)

        inst = Instance.from_keyname(classname="test", keyname="nosync")
        self.assertTrue(inst.is_enabled)

    def test_bulk_mixed_assets(self):

        helper.add_instance(
            classname="test", keyname="stale", fields={"last_sync": "2020-01-01 00:00:00"}
        )
        helper.add_instance(
            classname="test", keyname="recent", fields={"last_sync": "2099-12-31 23:59:59"}
        )
        helper.add_instance(classname="test", keyname="nosync", fields={})

        aaa = {"perms": ["p_data_admin", "p_pipeline_run"]}
        count_ok, count_discarded, errors = helper.run_pipeline(
            "bulk_disable_out_of_sync", ["test"], aaa=aaa
        )

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 1)
        self.assertEqual(count_discarded, 2)

        self.assertFalse(Instance.from_keyname(classname="test", keyname="stale").is_enabled)
        self.assertTrue(Instance.from_keyname(classname="test", keyname="recent").is_enabled)
        self.assertTrue(Instance.from_keyname(classname="test", keyname="nosync").is_enabled)


class PipelineBuiltinDeleteOutOfSyncTest(TestCase):
    def setUp(self):
        helper.add_admin_user(login="unittest")
        cache.clear()
        cache_django.clear()

        helper.add_schema(
            classname="test",
            field_definition={"last_sync": {"dataformat": "datetime", "displayname": "Last Sync"}},
        )

    def test_bulk_delete_disabled_stale_asset(self):

        helper.add_instance(
            classname="test",
            keyname="old_disabled",
            fields={
                "last_sync": "2020-01-01 00:00:00",
                "is_enabled": False,
            },
        )

        aaa = {"perms": ["p_data_admin", "p_pipeline_run"]}
        count_ok, count_discarded, errors = helper.run_pipeline(
            "bulk_delete_out_of_sync", ["test"], aaa=aaa
        )

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 1)
        self.assertEqual(count_discarded, 0)

        inst = Instance.from_keyname(classname="test", keyname="old_disabled")
        self.assertIsNone(inst)

    def test_bulk_keep_enabled_stale_asset(self):

        helper.add_instance(
            classname="test",
            keyname="stale_enabled",
            fields={
                "last_sync": "2020-01-01 00:00:00",
                "is_enabled": True,
            },
        )

        aaa = {"perms": ["p_data_admin", "p_pipeline_run"]}
        count_ok, count_discarded, errors = helper.run_pipeline(
            "bulk_delete_out_of_sync", ["test"], aaa=aaa
        )

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 0)
        self.assertEqual(count_discarded, 1)

        inst = Instance.from_keyname(classname="test", keyname="stale_enabled")
        self.assertIsNotNone(inst)

    def test_bulk_keep_disabled_recent_asset(self):

        helper.add_instance(
            classname="test",
            keyname="disabled_recent",
            fields={
                "last_sync": "2099-12-31 23:59:59",
                "is_enabled": False,
            },
        )

        aaa = {"perms": ["p_data_admin", "p_pipeline_run"]}
        count_ok, count_discarded, errors = helper.run_pipeline(
            "bulk_delete_out_of_sync", ["test"], aaa=aaa
        )

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 0)
        self.assertEqual(count_discarded, 1)

        inst = Instance.from_keyname(classname="test", keyname="disabled_recent")
        self.assertIsNotNone(inst)

    def test_bulk_skip_asset_without_last_sync(self):

        helper.add_instance(
            classname="test",
            keyname="nosync",
            fields={
                "is_enabled": False,
            },
        )

        aaa = {"perms": ["p_data_admin", "p_pipeline_run"]}
        count_ok, count_discarded, errors = helper.run_pipeline(
            "bulk_delete_out_of_sync", ["test"], aaa=aaa
        )

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 0)
        self.assertEqual(count_discarded, 1)

        inst = Instance.from_keyname(classname="test", keyname="nosync")
        self.assertIsNotNone(inst)

    def test_bulk_delete_mixed_assets(self):

        helper.add_instance(
            classname="test",
            keyname="old_disabled",
            fields={
                "last_sync": "2020-01-01 00:00:00",
                "is_enabled": False,
            },
        )
        helper.add_instance(
            classname="test",
            keyname="stale_enabled",
            fields={
                "last_sync": "2020-01-01 00:00:00",
                "is_enabled": True,
            },
        )
        helper.add_instance(
            classname="test",
            keyname="disabled_recent",
            fields={
                "last_sync": "2099-12-31 23:59:59",
                "is_enabled": False,
            },
        )
        helper.add_instance(
            classname="test",
            keyname="nosync",
            fields={
                "is_enabled": False,
            },
        )

        aaa = {"perms": ["p_data_admin", "p_pipeline_run"]}
        count_ok, count_discarded, errors = helper.run_pipeline(
            "bulk_delete_out_of_sync", ["test"], aaa=aaa
        )

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 1)
        self.assertEqual(count_discarded, 3)

        self.assertIsNone(Instance.from_keyname(classname="test", keyname="old_disabled"))
        self.assertIsNotNone(Instance.from_keyname(classname="test", keyname="stale_enabled"))
        self.assertIsNotNone(Instance.from_keyname(classname="test", keyname="disabled_recent"))
        self.assertIsNotNone(Instance.from_keyname(classname="test", keyname="nosync"))


class PipelineBuiltinDeleteAllTest(TestCase):
    def setUp(self):
        helper.add_admin_user(login="unittest")
        cache.clear()
        cache_django.clear()

        helper.add_schema(classname="test")

    def test_bulk_delete_all_removes_all(self):

        helper.add_instance(classname="test", keyname="inst01", fields={})
        helper.add_instance(classname="test", keyname="inst02", fields={})
        helper.add_instance(classname="test", keyname="inst03", fields={})

        aaa = {"perms": ["p_data_admin", "p_pipeline_run"]}
        count_ok, count_discarded, errors = helper.run_pipeline(
            "bulk_delete_all", ["test"], aaa=aaa
        )

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 3)
        self.assertEqual(count_discarded, 0)

        self.assertIsNone(Instance.from_keyname(classname="test", keyname="inst01"))
        self.assertIsNone(Instance.from_keyname(classname="test", keyname="inst02"))
        self.assertIsNone(Instance.from_keyname(classname="test", keyname="inst03"))

    def test_bulk_delete_all_empty_schema(self):

        aaa = {"perms": ["p_data_admin", "p_pipeline_run"]}
        count_ok, count_discarded, errors = helper.run_pipeline(
            "bulk_delete_all", ["test"], aaa=aaa
        )

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 0)
        self.assertEqual(count_discarded, 0)


class PipelineBuiltinRefreshTest(TestCase):
    def setUp(self):
        helper.add_admin_user(login="unittest")
        cache.clear()
        cache_django.clear()

        helper.add_schema(
            classname="test",
            field_definition={"mystring": {"dataformat": "string", "displayname": "MyString"}},
        )

    def test_bulk_refresh_all_instances(self):

        helper.add_instance(classname="test", keyname="inst01", fields={"mystring": "hello"})
        helper.add_instance(classname="test", keyname="inst02", fields={"mystring": "world"})

        aaa = {"perms": ["p_data_admin", "p_pipeline_run"]}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_refresh", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 2)
        self.assertEqual(count_discarded, 0)

        self.assertIsNotNone(Instance.from_keyname(classname="test", keyname="inst01"))
        self.assertIsNotNone(Instance.from_keyname(classname="test", keyname="inst02"))

    def test_bulk_refresh_empty_schema(self):

        aaa = {"perms": ["p_data_admin", "p_pipeline_run"]}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_refresh", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 0)
        self.assertEqual(count_discarded, 0)

    def test_bulk_noop(self):

        aaa = {"perms": ["p_data_admin", "p_pipeline_run"]}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_noop", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 0)
        self.assertEqual(count_discarded, 0)
