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

#ifndef CHROME_BROWSER_RENDERER_CONTEXT_MENU_RENDER_VIEW_CONTEXT_MENU_TEST_UTIL_H_
#define CHROME_BROWSER_RENDERER_CONTEXT_MENU_RENDER_VIEW_CONTEXT_MENU_TEST_UTIL_H_

#include <stddef.h>

#include <memory>
#include <optional>
#include <utility>

#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
#include "extensions/buildflags/buildflags.h"
#include "url/gurl.h"

#if BUILDFLAG(ENABLE_EXTENSIONS)
namespace extensions {
class ContextMenuMatcher;
}
#endif

#if BUILDFLAG(ENABLE_COMPOSE)
class ChromeComposeClient;
#endif

namespace custom_handlers {
class ProtocolHandlerRegistry;
}

namespace content {
class WebContents;
}
namespace ui {
class MenuModel;
}
#if BUILDFLAG(IS_CHROMEOS)
namespace policy {
class DlpRulesManager;
}
#endif

class TestRenderViewContextMenu : public RenderViewContextMenu {
 public:
  TestRenderViewContextMenu(content::RenderFrameHost& render_frame_host,
                            content::ContextMenuParams params);

  TestRenderViewContextMenu(const TestRenderViewContextMenu&) = delete;
  TestRenderViewContextMenu& operator=(const TestRenderViewContextMenu&) =
      delete;

  ~TestRenderViewContextMenu() override;

  // Factory.
  // This is a lightweight method to create a test RenderViewContextMenu
  // instance.
  // Use the constructor if you want to create menu with fine-grained params.
  static std::unique_ptr<TestRenderViewContextMenu> Create(
      content::WebContents* web_contents,
      const GURL& frame_url,
      const GURL& link_url = GURL(),
      bool is_subframe = false);

  static std::unique_ptr<TestRenderViewContextMenu> Create(
      content::RenderFrameHost* render_frame_host,
      const GURL& frame_url,
      const GURL& link_url = GURL(),
      bool is_subframe = false);

  // Returns true if the command specified by |command_id| is present
  // in the menu.
  // A list of command ids can be found in chrome/app/chrome_command_ids.h.
  bool IsItemPresent(int command_id) const;

  // Returns true if the command specified by |command_id| is checked in the
  // menu.
  bool IsItemChecked(int command_id) const;

  // Returns true if the command specified by |command_id| is enabled in the
  // menu.
  bool IsItemEnabled(int command_id) const;

  // Returns true if a command specified by any command id between
  // |command_id_first| and |command_id_last| (inclusive) is present in the
  // menu.
  bool IsItemInRangePresent(int command_id_first, int command_id_last) const;

  // Searches for a menu item with |command_id|. If it's found, the return
  // value is (model, index). Otherwise returns std::nullopt.
  std::optional<std::pair<ui::MenuModel*, size_t>> GetMenuModelAndItemIndex(
      int command_id);

  // Returns the command id of the menu item with the specified |path|.
  int GetCommandIDByProfilePath(const base::FilePath& path) const;

#if BUILDFLAG(ENABLE_EXTENSIONS)
  extensions::ContextMenuMatcher& extension_items() { return extension_items_; }
#endif

  void set_protocol_handler_registry(
      custom_handlers::ProtocolHandlerRegistry* registry) {
    protocol_handler_registry_ = registry;
  }

  void set_selection_navigation_url(GURL url) {
    selection_navigation_url_ = url;
  }

  void SetGlicItemExecutedForTesting(bool executed) {
    glic_item_executed_ = executed;
  }

  using RenderViewContextMenu::AppendImageItems;
  using RenderViewContextMenu::GetIsNewFeatureAtValue;

  // RenderViewContextMenu:
  void Show() override;
#if BUILDFLAG(IS_CHROMEOS)
  const policy::DlpRulesManager* GetDlpRulesManager() const override;
#endif

#if BUILDFLAG(IS_CHROMEOS)
  void set_dlp_rules_manager(policy::DlpRulesManager* dlp_rules_manager);
#endif

#if BUILDFLAG(ENABLE_COMPOSE)
  void SetChromeComposeClient(ChromeComposeClient* compose_client);
#endif
  // If `browser` is not null, sets it as the return value of GetBrowser(),
  // overriding the base class behavior. If the Browser object is destroyed
  // before this class is, then SetBrowser(nullptr) should be called. If
  // `browser` is null, restores the base class behavior of GetBrowser().
  void SetBrowser(BrowserWindowInterface* browser);

 protected:
  // RenderViewContextMenu:
  BrowserWindowInterface* GetBrowser() const override;

#if BUILDFLAG(ENABLE_COMPOSE)
  ChromeComposeClient* GetChromeComposeClient() const override;
#endif

 private:
  raw_ptr<BrowserWindowInterface> browser_ = nullptr;

#if BUILDFLAG(IS_CHROMEOS)
  raw_ptr<policy::DlpRulesManager> dlp_rules_manager_ = nullptr;
#endif

#if BUILDFLAG(ENABLE_COMPOSE)
  raw_ptr<ChromeComposeClient> compose_client_ = nullptr;
#endif
};

#endif  // CHROME_BROWSER_RENDERER_CONTEXT_MENU_RENDER_VIEW_CONTEXT_MENU_TEST_UTIL_H_
