# Copyright (c) 2018-2020, 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 carb.settings
import omni.kit.app
import omni.ui as ui
from omni.kit.test import TestRunStatus

from .ext_components import SimpleCheckBox

DEFAULT_TEST_APP = "${kit}/apps/omni.app.test_ext.kit"


class ExtTestTab:
    def __init__(self):
        self.test_status = {}

        # options
        self.info_log = False
        self.wait_for_debugger = False
        self.python_debugger = False
        self.wait_for_python_debugger = False
        self.ui_mode = False
        self.do_not_exit = False
        self.coverage = False
        self.tests_filter = ""

        self._test_filter_model = None

        self._app_combo = None

        self.apps = [f"{DEFAULT_TEST_APP} (empty)"]

        manager = omni.kit.app.get_app_interface().get_extension_manager()
        all_exts = [(manager.get_extension_dict(e["id"]), e["id"]) for e in manager.get_extensions()]
        self.apps += [ext_id for d, ext_id in all_exts if d.get("isKitFile", False)]

    def destroy(self):
        pass

    def build_cb(self, attr, name):
        SimpleCheckBox(
            getattr(self, attr),
            lambda v: setattr(self, attr, not getattr(self, attr)),
            name,
        )

    def _update_test_args(self):
        args = []
        if self.info_log:
            args += ["-v"]
        if self.wait_for_debugger:
            args += ["-d"]
        if self.wait_for_python_debugger:
            self.python_debugger = True
            args += ["--/exts/omni.kit.debug.python/break=1"]
        if self.python_debugger:
            args += ["--enable", "omni.kit.debug.python"]
        if self.do_not_exit:
            args += ["--/exts/omni.kit.test/doNotQuit=1"]

        self.tests_filter = self._test_filter_model.as_string
        args += [f"--/exts/omni.kit.test/runTestsFilter='{self.tests_filter}'"]

        settings = carb.settings.get_settings()

        selected_app = self._app_combo.model.get_item_value_model().as_int
        app = self.apps[selected_app] if selected_app > 0 else DEFAULT_TEST_APP
        settings.set("/exts/omni.kit.test/testExtApp", app)

        settings.set("/exts/omni.kit.test/testExtArgs", args)
        settings.set("/exts/omni.kit.test/testExtUIMode", self.ui_mode)
        settings.set("/exts/omni.kit.test/testExtGenerateCoverageReport", self.coverage)
        settings.set("/exts/omni.kit.test/testExtCleanOutputPath", self.coverage)
        # todo offer a way to pick reliable/unreliable/both
        # settings.set("/exts/omni.kit.test/testExtRunUnreliableTests", 2)

    def build(self, ext_info):
        ext_id = ext_info.get("package").get("id")

        with ui.VStack(height=0):
            ui.Spacer(height=20)

            ui.Label("Options:", height=0, width=50, style_type_name_override="ExtensionDescription.Label")
            ui.Spacer(height=10)

            self.build_cb("info_log", "info log")
            self.build_cb("ui_mode", "ui mode (test selection)")
            self.build_cb("coverage", "generate coverage report")
            self.build_cb("wait_for_debugger", "wait for native debugger")
            self.build_cb("python_debugger", "enable python debugger")
            self.build_cb("wait_for_python_debugger", "enable python debugger and wait")
            self.build_cb("do_not_exit", "do not exit after tests")

            ui.Spacer(height=10)
            with ui.HStack():
                ui.Spacer(width=10)
                ui.Label(
                    "filter (e.g.: *test_usd*):",
                    height=0,
                    width=50,
                    style_type_name_override="ExtensionDescription.Label",
                )
                self._test_filter_model = ui.StringField(width=250).model
                self._test_filter_model.as_string = self.tests_filter

            ui.Spacer(height=20)

            with ui.HStack():
                ui.Spacer(width=10)
                ui.Label("app:", height=0, width=50, style_type_name_override="ExtensionDescription.Label")
                self._app_combo = ui.ComboBox(0, *self.apps, style={"padding": 4}, width=400)

            ui.Spacer(height=20)

            with ui.HStack():
                status_image = None

                def _refresh_test_status():
                    status = self.test_status.get(ext_id, TestRunStatus.UNKNOWN)
                    status_image.name = str(status.name)

                def on_status(test_id, status, **_):
                    self.test_status[ext_id] = status
                    _refresh_test_status()

                def on_finish(status, *_):
                    if self.coverage:
                        omni.kit.test.generate_report()

                def on_click(ext_id=ext_id):
                    self._update_test_args()
                    omni.kit.test.run_ext_tests([ext_id], on_finish, on_status)

                ui.Button(
                    "RUN EXTENSION TESTS",
                    style_type_name_override="ExtensionDescription.InstallButton",
                    width=80,
                    height=20,
                    clicked_fn=on_click,
                )

                ui.Spacer(width=20)

                ui.Label("Result:", width=0, style_type_name_override="ExtensionDescription.Label")

                status_image = ui.Image(
                    name="TestStatus",
                    width=20,
                    height=20,
                    alignment=ui.Alignment.RIGHT_CENTER,
                )

                _refresh_test_status()
