import os
import omni.kit.test
import omni.graph.core as og
import omni.graph.core.tests as ogts
from omni.graph.core.tests.omnigraph_test_utils import _TestGraphAndNode
from omni.graph.core.tests.omnigraph_test_utils import _test_clear_scene
from omni.graph.core.tests.omnigraph_test_utils import _test_setup_scene
from omni.graph.core.tests.omnigraph_test_utils import _test_verify_scene


class TestOgn(ogts.OmniGraphTestCase):

    TEST_DATA = [
        {
            'inputs': [
                ['inputs:a_bool', False, False],
            ],
            'outputs': [
                ['outputs:a_bool', True, False],
            ],
        },
        {
            'inputs': [
                ['inputs:a_bool', True, False],
            ],
            'outputs': [
                ['outputs:a_bool', False, False],
                ['outputs:a_a_boolUiName', "Simple Boolean Input", False],
                ['outputs:a_nodeTypeUiName', "Tutorial Python Node: Attributes With Simple Data", False],
            ],
        },
        {
            'inputs': [
                ['inputs:a_path', "/World/Domination", False],
            ],
            'outputs': [
                ['outputs:a_path', "/World/Domination/Child", False],
            ],
        },
        {
            'inputs': [
                ['inputs:a_bool', False, False],
                ['inputs:a_double', 1.1, False],
                ['inputs:a_float', 3.3, False],
                ['inputs:a_half', 5.0, False],
                ['inputs:a_int', 7, False],
                ['inputs:a_int64', 9, False],
                ['inputs:a_token', "helloToken", False],
                ['inputs:a_string', "helloString", False],
                ['inputs:a_objectId', 10, False],
                ['inputs:a_uchar', 11, False],
                ['inputs:a_uint', 13, False],
                ['inputs:a_uint64', 15, False],
            ],
            'outputs': [
                ['outputs:a_bool', True, False],
                ['outputs:a_double', 2.1, False],
                ['outputs:a_float', 4.3, False],
                ['outputs:a_half', 6.0, False],
                ['outputs:a_int', 8, False],
                ['outputs:a_int64', 10, False],
                ['outputs:a_token', "worldToken", False],
                ['outputs:a_string', "worldString", False],
                ['outputs:a_objectId', 11, False],
                ['outputs:a_uchar', 12, False],
                ['outputs:a_uint', 14, False],
                ['outputs:a_uint64', 16, False],
            ],
        },
    ]

    async def test_generated(self):
        test_info = _TestGraphAndNode()
        controller = og.Controller()
        for i, test_run in enumerate(self.TEST_DATA):
            await _test_clear_scene(self, test_run)
            test_info = await _test_setup_scene(self, controller, "/TestGraph", "TestNode_omni_graph_tutorials_SimpleDataPy", "omni.graph.tutorials.SimpleDataPy", test_run, test_info)
            await controller.evaluate(test_info.graph)
            _test_verify_scene(self, controller, test_run, test_info, f"omni.graph.tutorials.SimpleDataPy User test case #{i+1}")

    async def test_vectorized_generated(self):
        test_info = _TestGraphAndNode()
        controller = og.Controller()
        for i, test_run in enumerate(self.TEST_DATA):
            await _test_clear_scene(self, test_run)
            test_info = await _test_setup_scene(self, controller, "/TestGraph", "TestNode_omni_graph_tutorials_SimpleDataPy","omni.graph.tutorials.SimpleDataPy", test_run, test_info, 16)
            await controller.evaluate(test_info.graph)
            _test_verify_scene(self, controller, test_run, test_info, f"omni.graph.tutorials.SimpleDataPy User test case #{i+1}", 16)

    async def test_data_access(self):
        from omni.graph.tutorials.ogn.OgnTutorialSimpleDataPyDatabase import OgnTutorialSimpleDataPyDatabase
        test_file_name = "OgnTutorialSimpleDataPyTemplate.usda"
        usd_path = os.path.join(os.path.dirname(__file__), "usd", test_file_name)
        if not os.path.exists(usd_path):
            self.assertTrue(False, f"{usd_path} not found for loading test")
        (result, error) = await ogts.load_test_file(usd_path)
        self.assertTrue(result, f'{error} on {usd_path}')
        test_node = og.Controller.node("/TestGraph/Template_omni_graph_tutorials_SimpleDataPy")
        database = OgnTutorialSimpleDataPyDatabase(test_node)
        self.assertTrue(test_node.is_valid())
        node_type_name = test_node.get_type_name()
        self.assertEqual(og.GraphRegistry().get_node_type_version(node_type_name), 1)

        def _attr_error(attribute: og.Attribute, usd_test: bool) -> str:
            test_type = "USD Load" if usd_test else "Database Access"
            return f"{node_type_name} {test_type} Test - {attribute.get_name()} value error"


        self.assertTrue(test_node.get_attribute_exists("inputs:a_constant_input"))
        attribute = test_node.get_attribute("inputs:a_constant_input")
        db_value = database.inputs.a_constant_input
        expected_value = 0
        actual_value = og.Controller.get(attribute)
        ogts.verify_values(expected_value, actual_value, _attr_error(attribute, True))
        ogts.verify_values(expected_value, db_value, _attr_error(attribute, False))

        self.assertTrue(test_node.get_attribute_exists("inputs:a_double"))
        attribute = test_node.get_attribute("inputs:a_double")
        db_value = database.inputs.a_double
        expected_value = 0
        actual_value = og.Controller.get(attribute)
        ogts.verify_values(expected_value, actual_value, _attr_error(attribute, True))
        ogts.verify_values(expected_value, db_value, _attr_error(attribute, False))

        self.assertTrue(test_node.get_attribute_exists("inputs:a_float"))
        attribute = test_node.get_attribute("inputs:a_float")
        db_value = database.inputs.a_float
        expected_value = 0
        actual_value = og.Controller.get(attribute)
        ogts.verify_values(expected_value, actual_value, _attr_error(attribute, True))
        ogts.verify_values(expected_value, db_value, _attr_error(attribute, False))

        self.assertTrue(test_node.get_attribute_exists("inputs:a_half"))
        attribute = test_node.get_attribute("inputs:a_half")
        db_value = database.inputs.a_half
        expected_value = 0.0
        actual_value = og.Controller.get(attribute)
        ogts.verify_values(expected_value, actual_value, _attr_error(attribute, True))
        ogts.verify_values(expected_value, db_value, _attr_error(attribute, False))

        self.assertTrue(test_node.get_attribute_exists("inputs:a_int"))
        attribute = test_node.get_attribute("inputs:a_int")
        db_value = database.inputs.a_int
        expected_value = 0
        actual_value = og.Controller.get(attribute)
        ogts.verify_values(expected_value, actual_value, _attr_error(attribute, True))
        ogts.verify_values(expected_value, db_value, _attr_error(attribute, False))

        self.assertTrue(test_node.get_attribute_exists("inputs:a_int64"))
        attribute = test_node.get_attribute("inputs:a_int64")
        db_value = database.inputs.a_int64
        expected_value = 0
        actual_value = og.Controller.get(attribute)
        ogts.verify_values(expected_value, actual_value, _attr_error(attribute, True))
        ogts.verify_values(expected_value, db_value, _attr_error(attribute, False))

        self.assertTrue(test_node.get_attribute_exists("inputs:a_objectId"))
        attribute = test_node.get_attribute("inputs:a_objectId")
        db_value = database.inputs.a_objectId
        expected_value = 0
        actual_value = og.Controller.get(attribute)
        ogts.verify_values(expected_value, actual_value, _attr_error(attribute, True))
        ogts.verify_values(expected_value, db_value, _attr_error(attribute, False))

        self.assertTrue(test_node.get_attribute_exists("inputs:a_path"))
        attribute = test_node.get_attribute("inputs:a_path")
        db_value = database.inputs.a_path
        expected_value = ""
        actual_value = og.Controller.get(attribute)
        ogts.verify_values(expected_value, actual_value, _attr_error(attribute, True))
        ogts.verify_values(expected_value, db_value, _attr_error(attribute, False))

        self.assertTrue(test_node.get_attribute_exists("inputs:a_string"))
        attribute = test_node.get_attribute("inputs:a_string")
        db_value = database.inputs.a_string
        expected_value = "helloString"
        actual_value = og.Controller.get(attribute)
        ogts.verify_values(expected_value, actual_value, _attr_error(attribute, True))
        ogts.verify_values(expected_value, db_value, _attr_error(attribute, False))

        self.assertTrue(test_node.get_attribute_exists("inputs:a_token"))
        attribute = test_node.get_attribute("inputs:a_token")
        db_value = database.inputs.a_token
        expected_value = "helloToken"
        actual_value = og.Controller.get(attribute)
        ogts.verify_values(expected_value, actual_value, _attr_error(attribute, True))
        ogts.verify_values(expected_value, db_value, _attr_error(attribute, False))

        self.assertTrue(test_node.get_attribute_exists("inputs:a_uchar"))
        attribute = test_node.get_attribute("inputs:a_uchar")
        db_value = database.inputs.a_uchar
        expected_value = 0
        actual_value = og.Controller.get(attribute)
        ogts.verify_values(expected_value, actual_value, _attr_error(attribute, True))
        ogts.verify_values(expected_value, db_value, _attr_error(attribute, False))

        self.assertTrue(test_node.get_attribute_exists("inputs:a_uint"))
        attribute = test_node.get_attribute("inputs:a_uint")
        db_value = database.inputs.a_uint
        expected_value = 0
        actual_value = og.Controller.get(attribute)
        ogts.verify_values(expected_value, actual_value, _attr_error(attribute, True))
        ogts.verify_values(expected_value, db_value, _attr_error(attribute, False))

        self.assertTrue(test_node.get_attribute_exists("inputs:a_uint64"))
        attribute = test_node.get_attribute("inputs:a_uint64")
        db_value = database.inputs.a_uint64
        expected_value = 0
        actual_value = og.Controller.get(attribute)
        ogts.verify_values(expected_value, actual_value, _attr_error(attribute, True))
        ogts.verify_values(expected_value, db_value, _attr_error(attribute, False))

        self.assertTrue(test_node.get_attribute_exists("outputs:a_a_boolUiName"))
        attribute = test_node.get_attribute("outputs:a_a_boolUiName")
        db_value = database.outputs.a_a_boolUiName

        self.assertTrue(test_node.get_attribute_exists("outputs:a_bool"))
        attribute = test_node.get_attribute("outputs:a_bool")
        db_value = database.outputs.a_bool

        self.assertTrue(test_node.get_attribute_exists("outputs:a_double"))
        attribute = test_node.get_attribute("outputs:a_double")
        db_value = database.outputs.a_double

        self.assertTrue(test_node.get_attribute_exists("outputs:a_float"))
        attribute = test_node.get_attribute("outputs:a_float")
        db_value = database.outputs.a_float

        self.assertTrue(test_node.get_attribute_exists("outputs:a_half"))
        attribute = test_node.get_attribute("outputs:a_half")
        db_value = database.outputs.a_half

        self.assertTrue(test_node.get_attribute_exists("outputs:a_int"))
        attribute = test_node.get_attribute("outputs:a_int")
        db_value = database.outputs.a_int

        self.assertTrue(test_node.get_attribute_exists("outputs:a_int64"))
        attribute = test_node.get_attribute("outputs:a_int64")
        db_value = database.outputs.a_int64

        self.assertTrue(test_node.get_attribute_exists("outputs:a_nodeTypeUiName"))
        attribute = test_node.get_attribute("outputs:a_nodeTypeUiName")
        db_value = database.outputs.a_nodeTypeUiName

        self.assertTrue(test_node.get_attribute_exists("outputs:a_objectId"))
        attribute = test_node.get_attribute("outputs:a_objectId")
        db_value = database.outputs.a_objectId

        self.assertTrue(test_node.get_attribute_exists("outputs:a_path"))
        attribute = test_node.get_attribute("outputs:a_path")
        db_value = database.outputs.a_path

        self.assertTrue(test_node.get_attribute_exists("outputs:a_string"))
        attribute = test_node.get_attribute("outputs:a_string")
        db_value = database.outputs.a_string

        self.assertTrue(test_node.get_attribute_exists("outputs:a_token"))
        attribute = test_node.get_attribute("outputs:a_token")
        db_value = database.outputs.a_token

        self.assertTrue(test_node.get_attribute_exists("outputs:a_uchar"))
        attribute = test_node.get_attribute("outputs:a_uchar")
        db_value = database.outputs.a_uchar

        self.assertTrue(test_node.get_attribute_exists("outputs:a_uint"))
        attribute = test_node.get_attribute("outputs:a_uint")
        db_value = database.outputs.a_uint

        self.assertTrue(test_node.get_attribute_exists("outputs:a_uint64"))
        attribute = test_node.get_attribute("outputs:a_uint64")
        db_value = database.outputs.a_uint64
