// 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/ui/ash/test_util.h"

#include "ash/constants/ash_switches.h"
#include "ash/public/cpp/shelf_test_api.h"
#include "ash/public/cpp/split_view_test_api.h"
#include "ash/shell.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/splitview/split_view_types.h"
#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
#include "ash/wm/window_pin_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_web_contents_delegate/browser_web_contents_delegate.h"
#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
#include "chrome/browser/ui/exclusive_access/exclusive_access_test.h"
#include "chrome/browser/ui/immersive/immersive_mode_controller.h"
#include "chrome/browser/ui/views/frame/browser_frame_view_chromeos.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/immersive_mode_tester.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chromeos/ui/base/window_properties.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "third_party/blink/public/mojom/frame/fullscreen.mojom.h"
#include "ui/aura/window.h"
#include "ui/display/screen.h"
#include "ui/views/test/widget_activation_waiter.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/widget/widget.h"

void ChromeOSBrowserUITest::SetUpDefaultCommandLine(
    base::CommandLine* command_line) {
  MixinBasedInProcessBrowserTest::SetUpDefaultCommandLine(command_line);
  command_line->AppendSwitch(ash::switches::kAshEnableTabletMode);
}

void ChromeOSBrowserUITest::TearDownOnMainThread() {
  if (InTabletMode()) {
    ExitTabletMode();
  }
  MixinBasedInProcessBrowserTest::TearDownOnMainThread();
}

bool ChromeOSBrowserUITest::InTabletMode() {
  return display::Screen::Get()->InTabletMode();
}

void ChromeOSBrowserUITest::EnterTabletMode() {
  SetTabletMode(true);
}

void ChromeOSBrowserUITest::ExitTabletMode() {
  SetTabletMode(false);
}

void ChromeOSBrowserUITest::SetTabletMode(bool enable) {
  CHECK_NE(InTabletMode(), enable);
  if (enable) {
    ash::TabletModeControllerTestApi().EnterTabletMode();
  } else {
    ash::TabletModeControllerTestApi().LeaveTabletMode();
  }
  CHECK_EQ(InTabletMode(), enable);
}

void ChromeOSBrowserUITest::EnterOverviewMode() {
  SetOverviewMode(true);
}

void ChromeOSBrowserUITest::ExitOverviewMode() {
  SetOverviewMode(false);
}

void ChromeOSBrowserUITest::SetOverviewMode(bool enable) {
  if (enable) {
    ash::Shell::Get()->overview_controller()->StartOverview(
        ash::OverviewStartAction::kTests);
  } else {
    ash::Shell::Get()->overview_controller()->EndOverview(
        ash::OverviewEndAction::kTests);
  }
}

void ChromeOSBrowserUITest::SnapWindow(aura::Window* window,
                                       ash::SnapPosition position) {
  ash::SplitViewTestApi().SnapWindow(window, position);
}

void ChromeOSBrowserUITest::PinWindow(aura::Window* window, bool trusted) {
  ash::PinWindow(window, trusted);
}

bool ChromeOSBrowserUITest::IsShelfVisible() {
  return ash::ShelfTestApi().IsVisible();
}

void ChromeOSBrowserUITest::DeactivateWidget(views::Widget* widget) {
  widget->Deactivate();
}

void ChromeOSBrowserUITest::EnterImmersiveFullscreenMode(
    BrowserWindowInterface* browser) {
  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
  ASSERT_FALSE(browser_view->IsFullscreen());

  auto* const immersive_mode_controller =
      ImmersiveModeController::From(browser);
  ASSERT_FALSE(immersive_mode_controller->IsEnabled());

  ui_test_utils::ToggleFullscreenModeAndWait(browser);
  // TODO(crbug.com/40942067): Simplify waiting once the two states are merged.
  ImmersiveModeTester(browser).WaitForFullscreenToEnter();
  ASSERT_TRUE(immersive_mode_controller->IsEnabled());
  ASSERT_TRUE(browser_view->IsFullscreen());
}

void ChromeOSBrowserUITest::ExitImmersiveFullscreenMode(
    BrowserWindowInterface* browser) {
  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
  ASSERT_TRUE(browser_view->IsFullscreen());

  auto* const immersive_mode_controller =
      ImmersiveModeController::From(browser);
  ASSERT_TRUE(immersive_mode_controller->IsEnabled());

  ui_test_utils::ToggleFullscreenModeAndWait(browser);
  // TODO(crbug.com/40942067): Simplify waiting once the two states are merged.
  ImmersiveModeTester(browser).WaitForFullscreenToExit();
  ASSERT_FALSE(immersive_mode_controller->IsEnabled());
  ASSERT_FALSE(browser_view->IsFullscreen());
}

void ChromeOSBrowserUITest::EnterTabFullscreenMode(
    BrowserWindowInterface* browser,
    content::WebContents* web_contents) {
  ui_test_utils::FullscreenWaiter waiter(browser, {.tab_fullscreen = true});
  BrowserWebContentsDelegate::From(browser)->EnterFullscreenModeForTab(
      web_contents->GetPrimaryMainFrame(), {});
  waiter.Wait();
}

void ChromeOSBrowserUITest::ExitTabFullscreenMode(
    BrowserWindowInterface* browser,
    content::WebContents* web_contents) {
  ui_test_utils::FullscreenWaiter waiter(browser, {.tab_fullscreen = false});
  ExclusiveAccessManager::From(browser)
      ->fullscreen_controller()
      ->ExitFullscreenModeForTab(web_contents);
  waiter.Wait();
}

BrowserFrameViewChromeOS* ChromeOSBrowserUITest::GetFrameViewChromeOS(
    BrowserView* browser_view) {
  // We know we're using ChromeOS, so static cast.
  auto* frame_view = static_cast<BrowserFrameViewChromeOS*>(
      browser_view->GetWidget()->non_client_view()->frame_view());
  DCHECK(frame_view);
  return frame_view;
}
