// SPDX-License-Identifier: GPL-3.0-or-later

#include "test_utils.h"
#include "tests.h"
#include "tests_common.h"

#include "common/sleeptimer.h"

// WORKAROUND: Checking clipboard right after closing menu gets stuck on OS X.
#define ACTIVATE_MENU_ITEM(MENU_ID, WIDGET_ID, CONTENT) \
    KEYS(MENU_ID << "ENTER"); \
    KEYS(WIDGET_ID); \
    WAIT_FOR_CLIPBOARD(CONTENT)

void CoreTests::tray()
{
    RUN("add" << "A", "");
    KEYS(clipboardBrowserId);
    RUN("menu", "");
    ACTIVATE_MENU_ITEM(trayMenuId, clipboardBrowserId, "A");
}

void CoreTests::menu()
{
    const auto tab = testTab(1);

    RUN("tab" << tab << "add" << "D" << "C" << "B" << "A", "");

    KEYS(clipboardBrowserId);
    RUN("menu" << tab, "");
    ACTIVATE_MENU_ITEM(menuId, clipboardBrowserId, "A");

    // Show menu with 2 items from the tab and select last one.
    KEYS(clipboardBrowserId);
    RUN("menu" << tab << "2", "");
    KEYS(menuId << "END");
    ACTIVATE_MENU_ITEM(menuId, clipboardBrowserId, "B");

#ifdef Q_OS_MAC
    SKIP("Number keys don't seem to work in the tray menu on macOS.");
#endif

    // Select item by row number.
    RUN("tab" << tab << "add(3,2,1,0)", "");
    RUN("menu" << tab, "");
    KEYS(menuId << "3" << clipboardBrowserId);
    WAIT_FOR_CLIPBOARD("2");

    // Select item by index.
    RUN("config" << "row_index_from_one" << "false", "false\n");
    RUN("tab" << tab << "add(3,2,1,0)", "");
    RUN("menu" << tab, "");
    KEYS(menuId << "3" << clipboardBrowserId);
    WAIT_FOR_CLIPBOARD("3");
}

void CoreTests::traySearch()
{
    RUN("add" << "C" << "B" << "A", "");

    KEYS(clipboardBrowserId);
    RUN("menu", "");
    KEYS(trayMenuId << "B");
    ACTIVATE_MENU_ITEM(trayMenuId, clipboardBrowserId, "B");
}

void CoreTests::trayPaste()
{
    RUN("config" << "tray_tab_is_current" << "false", "false\n");

    const auto tab1 = testTab(1);
    RUN("setCurrentTab" << tab1, "");
    KEYS(clipboardBrowserId << "CTRL+N" << editorId << ":NEW ");

    RUN("add" << "TEST", "");
    KEYS(editorId);
    RUN("menu", "");
    ACTIVATE_MENU_ITEM(trayMenuId, editorId, "TEST");
    waitFor(waitMsPasteClipboard);

    KEYS(editorId << "F2");
    RUN("tab" << tab1 << "read" << "0", "NEW TEST");

    KEYS(clipboardBrowserId << "CTRL+N" << editorId << ":NEW ");

    RUN("config" << "tray_item_paste" << "false", "false\n");
    RUN("add" << "TEST2", "");
    KEYS(editorId);
    RUN("menu", "");
    ACTIVATE_MENU_ITEM(trayMenuId, editorId, "TEST2");

    KEYS(editorId << "F2");
    RUN("tab" << tab1 << "read" << "0", "NEW ");
}

void CoreTests::trayShowHideAction()
{
#ifdef Q_OS_MAC
    SKIP("Tests seem unable to trigger Show/Hide from tray on macOS");
#endif

    // Test Show/Hide action from tray menu:
    // The main window should be hide even if unfocused.
    RUN("visible", "true\n");
    WAIT_ON_OUTPUT("visible", "true\n");
    WAIT_ON_OUTPUT("focused", "true\n");

    // Unfocus the main window by focusing a dialog
    RUN("action('copyq:dialog()')", "");
    WAIT_ON_OUTPUT("visible", "true\n");
    WAIT_ON_OUTPUT("focused", "false\n");

    // Trigger &Show/Hide
    RUN("menu", "");
    KEYS(trayMenuId << "S");
    WAIT_ON_OUTPUT("visible", "false\n");
    WAIT_ON_OUTPUT("focused", "false\n");

    RUN("menu", "");
    KEYS(trayMenuId << "S");
    WAIT_ON_OUTPUT("visible", "true\n");
    WAIT_ON_OUTPUT("focused", "true\n");
}

void CoreTests::configTrayTab()
{
    const auto tab1 = testTab(1);
    RUN("tab" << tab1 << "add" << "A", "");

    const auto tab2 = testTab(2);
    RUN("tab" << tab2 << "add" << "B", "");

    RUN("config" << "tray_tab_is_current" << "false", "false\n");

    RUN("config" << "tray_item_paste" << "false", "false\n");

    RUN("config" << "tray_tab" << tab1, tab1 + "\n");

    KEYS(clipboardBrowserId);
    RUN("menu", "");
    ACTIVATE_MENU_ITEM(trayMenuId, clipboardBrowserId, "A");

    RUN("config" << "tray_tab" << tab2, tab2 + "\n");

    KEYS(clipboardBrowserId);
    RUN("menu", "");
    ACTIVATE_MENU_ITEM(trayMenuId, clipboardBrowserId, "B");
}

void CoreTests::configMove()
{
    SKIP_ON_ENV("COPYQ_TESTS_SKIP_CONFIG_MOVE");

    RUN("add" << "B" << "A", "");

    RUN("config" << "tray_item_paste" << "false", "false\n");

    RUN("config" << "move" << "true", "true\n");

    KEYS(clipboardBrowserId);
    RUN("menu", "");
    KEYS(trayMenuId << "DOWN");
    ACTIVATE_MENU_ITEM(trayMenuId, clipboardBrowserId, "B");
    RUN("read" << "0" << "1", "B\nA");

    RUN("config" << "move" << "false", "false\n");

    KEYS(clipboardBrowserId);
    RUN("menu", "");
    KEYS(trayMenuId << "DOWN");
    ACTIVATE_MENU_ITEM(trayMenuId, clipboardBrowserId, "A");
    RUN("read" << "0" << "1", "B\nA");
}

void CoreTests::configTrayTabIsCurrent()
{
    const auto tab1 = testTab(1);
    RUN("tab" << tab1 << "add" << "A", "");

    const auto tab2 = testTab(2);
    RUN("tab" << tab2 << "add" << "B", "");

    RUN("config" << "tray_tab_is_current" << "true", "true\n");

    RUN("setCurrentTab" << tab1, "");
    KEYS(clipboardBrowserId);
    RUN("menu", "");
    ACTIVATE_MENU_ITEM(trayMenuId, clipboardBrowserId, "A");

    RUN("setCurrentTab" << tab2, "");
    KEYS(clipboardBrowserId);
    RUN("menu", "");
    ACTIVATE_MENU_ITEM(trayMenuId, clipboardBrowserId, "B");
}

void CoreTests::trayMenuToggleRapid()
{
    RUN("add" << "X" << "Y" << "Z", "");

    // Verify the menu can be opened, closed, and reopened reliably.
    // Regression test for #3445: on macOS, the first shortcut press
    // failed to show the menu due to deferred focus-stealing.
    for (int i = 0; i < 3; ++i) {
        KEYS(clipboardBrowserId);
        RUN("menu", "");
        KEYS(trayMenuId << "ESCAPE");
    }

    // Final open + activate to confirm the menu is functional.
    KEYS(clipboardBrowserId);
    RUN("menu", "");
    ACTIVATE_MENU_ITEM(trayMenuId, clipboardBrowserId, "Z");
}
