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

#include "base/notreached.h"
#include "build/build_config.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "ui/base/ui_base_features.h"
#include "ui/display/screen.h"
#include "ui/gfx/native_ui_types.h"
#include "ui/views/debug_utils.h"
#include "ui/views/view.h"
#include "ui/views/view_utils.h"
#include "ui/views/widget/widget.h"

#if defined(USE_AURA)
#include "ui/aura/window.h"
#include "ui/wm/public/activation_client.h"
#endif

#if BUILDFLAG(IS_MAC)
#include "chrome/browser/platform_util.h"
#endif

namespace {
#if defined(USE_AURA) || BUILDFLAG(IS_MAC)
gfx::NativeWindow GetActiveWindow(const BrowserWindowInterface* browser) {
#if defined(USE_AURA)
  wm::ActivationClient* client = wm::GetActivationClient(
      browser->GetWindow()->GetNativeWindow()->GetRootWindow());
  return client ? client->GetActiveWindow() : nullptr;
#elif BUILDFLAG(IS_MAC)
  return platform_util::GetActiveWindow();
#endif
}
#endif

views::View* GetActiveWindowRootView(const BrowserWindowInterface* browser) {
#if defined(USE_AURA) || BUILDFLAG(IS_MAC)
  gfx::NativeWindow active_window = GetActiveWindow(browser);
  views::Widget* widget =
      views::Widget::GetWidgetForNativeWindow(active_window);
  return widget ? widget->GetRootView() : nullptr;
#else
  return nullptr;
#endif
}

gfx::NativeWindow GetTargetWindowForDebug(
    const BrowserWindowInterface* browser) {
  gfx::Point screen_point = display::Screen::Get()->GetCursorScreenPoint();
  gfx::NativeWindow target_window =
      display::Screen::Get()->GetWindowAtScreenPoint(screen_point);
#if defined(USE_AURA) || BUILDFLAG(IS_MAC)
  if (!target_window) {
    target_window = GetActiveWindow(browser);
  }
#endif
  return target_window;
}
}  // namespace

namespace chrome {

std::optional<int> GetKeyboardFocusedTabIndex(
    const BrowserWindowInterface* browser) {
  BrowserView* view = BrowserView::GetBrowserViewForBrowser(browser);
  if (view && view->tab_strip_view()) {
    return view->tab_strip_view()->GetFocusedTabIndex();
  }
  return std::nullopt;
}

void ExecuteUIDebugCommand(int id, const BrowserWindowInterface* browser) {
  if (!base::FeatureList::IsEnabled(features::kUIDebugTools)) {
    return;
  }

  switch (id) {
    case IDC_DEBUG_TOGGLE_TABLET_MODE: {
      auto* controller = ui::TouchUiController::Get();
      // Chrome always uses touch_ui_state auto mode except in tests, so whether
      // it is touch ui relies on whether it is in tablet mode.
      controller->OnTabletModeToggled(!controller->touch_ui());
      break;
    }
    case IDC_DEBUG_PRINT_VIEW_TREE:
    case IDC_DEBUG_PRINT_VIEW_TREE_DETAILS:
      if (views::View* view = GetActiveWindowRootView(browser)) {
        LOG(ERROR) << '\n'
                   << PrintViewHierarchy(
                          view, id == IDC_DEBUG_PRINT_VIEW_TREE_DETAILS);
      }
      break;
    case IDC_DEBUG_PRINT_WINDOW_HIERARCHY: {
      if (gfx::NativeWindow target_window = GetTargetWindowForDebug(browser)) {
        std::ostringstream out;
        views::PrintWindowHierarchy(target_window, &out);
        LOG(ERROR) << out.str();
      } else {
        LOG(ERROR) << "No window found under mouse cursor or active.";
      }
      break;
    }
    case IDC_DEBUG_PRINT_LAYER_HIERARCHY: {
      if (gfx::NativeWindow target_window = GetTargetWindowForDebug(browser)) {
        std::ostringstream out;
        views::PrintLayerHierarchy(target_window, &out);
        LOG(ERROR) << out.str();
      } else {
        LOG(ERROR) << "No window found under mouse cursor or active.";
      }
      break;
    }
    default:
      NOTREACHED() << "Unimplemented UI Debug command: " << id;
  }
}

}  // namespace chrome
