# Copyright (c) 2023, NVIDIA CORPORATION.  All rights reserved.
#
# NVIDIA CORPORATION and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto.  Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION is strictly prohibited.
#

import asyncio
from pathlib import Path
from typing import Tuple

import omni.graph.core as og
import omni.kit.app
import omni.kit.commands
import omni.kit.test
import omni.kit.ui_test as ui_test
import omni.usd
from carb.input import KeyboardInput as Key


class TestTimerNode(omni.kit.test.AsyncTestCase):
    async def setUp(self):
        extension_root_folder = Path(
            omni.kit.app.get_app().get_extension_manager().get_extension_path_by_module(__name__)
        )
        self._test_files = extension_root_folder.joinpath("data/tests/usd")
        await self._load_stage()

    async def tearDown(self):
        await omni.usd.get_context().close_stage_async()

    async def test_timer_node(self):
        await self._test_timer_node_impl()

    async def _load_stage(self):
        usd_context = omni.usd.get_context()

        filename = "timer.usda"
        test_file_path = self._test_files.joinpath(filename).absolute()
        await usd_context.open_stage_async(str(test_file_path))
        print(f"Loaded: {test_file_path}")
        self._stage = usd_context.get_stage()

    async def _test_timer_node_impl(self):
        node = self._stage.GetPrimAtPath("/World/ActionGraph/Timer")
        graph = self._stage.GetPrimAtPath("/World/ActionGraph")
        self.assertEqual(graph.GetTypeName(), "OmniGraph")

        await ui_test.emulate_keyboard_press(Key.A)
        await omni.kit.app.get_app().next_update_async()
        await self._test_time_and_range(node, [(0, (0, 0.1)), (1, (0.4, 0.6)), (2.5, (1, 1))])

    async def _test_time_and_range(self, node: og.Node, time_range: Tuple[float, Tuple[float, float]]):
        for (time, (min_value, max_value)) in time_range:
            print("Time: ", time, "Range: ", min_value, max_value)
            if time > 0:
                print("sleeping for ", time, " seconds")
                await asyncio.sleep(time)
                print("sleeping done")

            self._test_y_within_range(node, min_value, max_value)

    # because asyncio.sleep(1) does not sleep for exactly that amount of time, check the result in an range
    def _test_y_within_range(self, node: og.Node, min_value: float, max_value: float):

        actual_value = og.Controller.get(f"{node.GetPath()}.outputs:value")

        print(f"min_value: {min_value}, max_value: {max_value} actual_value: {actual_value}")
        self.assertGreaterEqual(actual_value, min_value)
        self.assertLessEqual(actual_value, max_value)
