import omni.kit.test
from unittest.mock import patch

import omni.client
from omni import ui
from carb.input import KeyboardInput

from omni.kit.test.async_unittest import AsyncTestCase
from omni.kit import ui_test
from omni.kit.test_suite.helpers import get_test_data_path
from omni.kit.widget.filebrowser import is_clipboard_cut, get_clipboard_items, clear_clipboard
from ..test_helper import ContentBrowserTestHelper


class TestCutPaste(AsyncTestCase):
    """Testing ContentBrowserWidget cut and paste behavior"""
    async def setUp(self):
        await ui_test.find("Content").focus()

    async def tearDown(self):
        pass

    async def test_paste_availability(self):
        """Testing paste context menu shows up correctly."""
        test_dir = get_test_data_path(__name__)
        test_file = "4Lights.usda"
        test_folder = "folder.usda"

        async with ContentBrowserTestHelper() as content_browser_helper:
            await content_browser_helper.navigate_to_async(test_dir)
            await content_browser_helper.toggle_grid_view_async(True)
            await ui_test.human_delay(100)
            item = await content_browser_helper.get_gridview_item_async(test_file)
            folder_item = await content_browser_helper.get_gridview_item_async(test_folder)
            if not item:
                return
            await item.right_click()
            await ui_test.human_delay()

            context_menu = await ui_test.get_context_menu()
            context_options = context_menu["_"]
            self.assertIn("Cut", context_options)
            self.assertNotIn("Paste", context_options)

            await ui_test.select_context_menu("Cut")

            # now paste should be available
            await ui_test.human_delay()
            await folder_item.right_click()
            await ui_test.human_delay()
            context_menu = await ui_test.get_context_menu()
            context_options = context_menu["_"]
            self.assertIn("Paste", context_options)

            # paste will not be available if more than one item is selected, but Cut should
            await content_browser_helper.select_items_async(test_dir, [test_file, test_folder])
            await item.right_click()
            await ui_test.human_delay()
            context_menu = await ui_test.get_context_menu()
            context_options = context_menu["_"]
            self.assertNotIn("Paste", context_options)
            self.assertIn("Cut", context_options)

        clear_clipboard()


    async def test_cut_and_paste(self):
        """Testing cut and paste."""
        test_dir = get_test_data_path(__name__)
        test_file = "4Lights.usda"
        test_folder = "folder.usda"

        async with ContentBrowserTestHelper() as content_browser_helper:
            await content_browser_helper.navigate_to_async(test_dir)
            await content_browser_helper.toggle_grid_view_async(True)
            await ui_test.human_delay(100)
            item = await content_browser_helper.get_gridview_item_async(test_file)
            folder_item = await content_browser_helper.get_gridview_item_async(test_folder)
            if not item:
                return
            if not folder_item:
                return

            await folder_item.right_click()
            await ui_test.human_delay()
            await ui_test.select_context_menu("Cut")

            # cut clipboard should have one item in it
            self.assertTrue(is_clipboard_cut())
            self.assertEqual(1, len(get_clipboard_items()))
            self.assertEqual(get_clipboard_items()[0].path.replace("\\", "/").lower(),
                f"{test_dir}/{test_folder}".replace("\\", "/").lower())

            # cut clipboard should still have one item in it, but updated
            await item.right_click()
            await ui_test.human_delay()
            await ui_test.select_context_menu("Cut")
            self.assertTrue(is_clipboard_cut())
            self.assertEqual(1, len(get_clipboard_items()))
            cut_path = get_clipboard_items()[0].path
            self.assertEqual(cut_path.replace("\\", "/").lower(), f"{test_dir}/{test_file}".replace("\\", "/").lower())

            with patch.object(omni.client, "move_async", return_value=(omni.client.Result.OK, None)) as mock_move:
                await folder_item.right_click()
                await ui_test.human_delay()
                await ui_test.select_context_menu("Paste")

                await ui_test.human_delay(10)
                window = ui_test.find("MOVE")
                self.assertIsNotNone(window)
                await ui_test.emulate_keyboard_press(KeyboardInput.ENTER)
                await ui_test.human_delay()

            mock_move.assert_called_once()
            # clipboard should be cleared now
            self.assertEqual(get_clipboard_items(), [])
            self.assertFalse(is_clipboard_cut())
