// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/api/permissions/permissions_api.h"

#include "base/test/bind.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/browser/ui/extensions/extension_action_test_helper.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "content/public/test/browser_test.h"
#include "extensions/test/extension_test_message_listener.h"
#include "ui/gfx/native_ui_types.h"

namespace extensions {
using PermissionsApiInteractiveTest = ExtensionApiTest;

// Tests that the dialog is parented to the correct window when there are
// multiple browser windows open. Regression test for crbug.com/41482206.
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
// BringBrowserWindowToFront hangs on Linux: http://crbug.com/356183782
#define MAYBE_DialogWithMultipleWindows DISABLED_DialogWithMultipleWindows
#else
#define MAYBE_DialogWithMultipleWindows DialogWithMultipleWindows
#endif
IN_PROC_BROWSER_TEST_F(PermissionsApiInteractiveTest,
                       MAYBE_DialogWithMultipleWindows) {
  PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
  auto dialog_action_reset =
      PermissionsRequestFunction::SetDialogActionForTests(
          PermissionsRequestFunction::DialogAction::kProgrammatic);

  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("permissions/optional_request_from_popup"));

  BrowserWindowInterface* first_browser = browser();
  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(first_browser));

  // Create a second browser window and wait for activation.
  BrowserWindowInterface* second_browser = CreateBrowser(profile());
  ASSERT_NE(first_browser, second_browser);
  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(second_browser));

  // Activate the first browser (again).
  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(first_browser));

  // Simulate a click on the extension action. The extension expects back a
  // reply from the browser. On receiving the reply, it will request additional
  // permissions.
  std::unique_ptr<ExtensionActionTestHelper> action_helper =
      ExtensionActionTestHelper::Create(first_browser);
  ExtensionTestMessageListener popup_listener("popup_loaded",
                                              ReplyBehavior::kWillReply);
  action_helper->Press(extension->id());
  ASSERT_TRUE(popup_listener.WaitUntilSatisfied());

  // We must wait for the popup to be activated, before asking it to request
  // additional permissions.
  action_helper->WaitForPopup();

  // Configure a custom show dialog callback to capture the parent_window. This
  // callback is our actual test, which validates the dialog's parent window.
  base::RunLoop run_loop;
  auto show_dialog_callback = [&](gfx::NativeWindow parent_window) {
    EXPECT_EQ(parent_window, first_browser->GetWindow()->GetNativeWindow());
    run_loop.Quit();
  };

  auto bound_callback = base::BindLambdaForTesting(show_dialog_callback);
  auto show_dialog_callback_reset =
      PermissionsRequestFunction::SetShowDialogCallbackForTests(
          &bound_callback);

  // At this point, the popup is active and our test hooks are configured. Ask
  // the popup to request additional permissions and wait for our test callback.
  popup_listener.Reply("request_permissions");
  run_loop.Run();

  PermissionsRequestFunction::ResolvePendingDialogForTests(
      /*accept_dialog=*/true);
}
}  // namespace extensions
