// 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 COMPONENTS_BOOKMARKS_TEST_TEST_BOOKMARK_CLIENT_H_
#define COMPONENTS_BOOKMARKS_TEST_TEST_BOOKMARK_CLIENT_H_

#include <stdint.h>

#include <list>
#include <map>
#include <memory>

#include "base/functional/callback.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "components/bookmarks/browser/bookmark_client.h"
#include "components/os_crypt/async/browser/os_crypt_async.h"
#include "components/os_crypt/async/common/encryptor.h"

namespace gfx {
class Image;
}  // namespace gfx

namespace bookmarks {

class BookmarkModel;

class TestBookmarkClient : public BookmarkClient {
 public:
  explicit TestBookmarkClient(
      os_crypt_async::OSCryptAsync* os_crypt_async = nullptr);

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

  ~TestBookmarkClient() override;

  // Returns a new BookmarkModel using a TestBookmarkClient.
  static std::unique_ptr<BookmarkModel> CreateModel();

  // Returns true if the test environment defaults to a desktop form factor.
  static bool IsDesktopFormFactorByDefault();

  // Returns a new BookmarkModel using `client`.
  static std::unique_ptr<BookmarkModel> CreateModelWithClient(
      std::unique_ptr<TestBookmarkClient> client);

  // Causes the the next call to CreateModel() or GetLoadManagedNodeCallback()
  // to return a node representing managed bookmarks. The raw pointer of this
  // node is returned for convenience.
  BookmarkPermanentNode* EnableManagedNode();

  // Returns true if `node` is the `managed_node_`.
  bool IsManagedNodeRoot(const BookmarkNode* node);

  // Mimics the completion of a previously-triggered GetFaviconImageForPageURL()
  // call for `page_url`, usually invoked by BookmarkModel. Returns false if no
  // such a call is pending completion. The completion returns a favicon with
  // URL `icon_url` and a single-color 16x16 image using `color`.
  bool SimulateFaviconLoaded(const GURL& page_url,
                             const GURL& icon_url,
                             const gfx::Image& color);

  // Mimics the completion of a previously-triggered GetFaviconImageForPageURL()
  // call for `page_url`, usually invoked by BookmarkModel. Returns false if no
  // such a call is pending completion. The completion returns an empty image
  // for the favicon.
  bool SimulateEmptyFaviconLoaded(const GURL& page_url);

  // Returns true if there is at least one active favicon loading task.
  bool HasFaviconLoadTasks() const;

  // Sets the value returned by
  // `IsSyncFeatureEnabledIncludingBookmarks()`.
  void SetIsSyncFeatureEnabledIncludingBookmarks(bool value);

  // Returns sync metadata for account bookmarks,  received via
  // DecodeAccountBookmarkSyncMetadata() or modified via
  // SetAccountBookmarkSyncMetadataAndScheduleWrite().
  const std::string& account_bookmark_sync_metadata() const {
    return account_bookmark_sync_metadata_;
  }

  void SetAccountBookmarkSyncMetadataAndScheduleWrite(
      const std::string& account_bookmark_sync_metadata);

  // Allows overriding the value returned by
  // `DecodeAccountBookmarkSyncMetadataResult()`.
  void SetDecodeAccountBookmarkSyncMetadataResult(
      DecodeAccountBookmarkSyncMetadataResult result);

  // Simulates the log interval trigger by calling `metrics_callback_` that was
  // the input in `SchedulePersistentTimerForDailyMetrics()`.
  void TriggerPersistentLogInterval();

  // BookmarkClient:
  LoadManagedNodeCallback GetLoadManagedNodeCallback() override;
  bool IsSyncFeatureEnabledIncludingBookmarks() override;
  bool CanSetPermanentNodeTitle(const BookmarkNode* permanent_node) override;
  bool IsNodeManaged(const BookmarkNode* node) override;
  BookmarkFormFactor GetBookmarkFormFactor() override;
  std::string EncodeLocalOrSyncableBookmarkSyncMetadata() override;
  std::string EncodeAccountBookmarkSyncMetadata() override;
  void DecodeLocalOrSyncableBookmarkSyncMetadata(
      const std::string& metadata_str,
      const base::RepeatingClosure& schedule_save_closure) override;
  DecodeAccountBookmarkSyncMetadataResult DecodeAccountBookmarkSyncMetadata(
      const std::string& metadata_str,
      const base::RepeatingClosure& schedule_save_closure) override;
  base::CancelableTaskTracker::TaskId GetFaviconImageForPageURL(
      const GURL& page_url,
      favicon_base::FaviconImageCallback callback,
      base::CancelableTaskTracker* tracker) override;
  void OnBookmarkNodeRemovedUndoable(
      const BookmarkNode* parent,
      size_t index,
      std::unique_ptr<BookmarkNode> node) override;
  void SchedulePersistentTimerForDailyMetrics(
      base::RepeatingClosure metrics_callback) override;
  void GetEncryptor(base::OnceCallback<
                    void(scoped_refptr<os_crypt_async::Encryptor> encryptor)>
                        callback) override;

 private:
  // Helpers for GetLoadManagedNodeCallback().
  static std::unique_ptr<BookmarkPermanentNode> LoadManagedNode(
      std::unique_ptr<BookmarkPermanentNode> managed_node,
      int64_t* next_id);

  // managed_node_ exists only until GetLoadManagedNodeCallback gets called, but
  // unowned_managed_node_ stays around after that.
  std::unique_ptr<BookmarkPermanentNode> managed_node_;
  raw_ptr<BookmarkPermanentNode, DanglingUntriaged> unowned_managed_node_ =
      nullptr;

  base::CancelableTaskTracker::TaskId next_task_id_ = 1;
  std::map<GURL, std::list<favicon_base::FaviconImageCallback>>
      requests_per_page_url_;

  bool is_sync_feature_enabled_including_bookmarks_ = false;

  std::string account_bookmark_sync_metadata_;
  base::RepeatingClosure account_bookmark_sync_metadata_save_closure_ =
      base::DoNothing();

  DecodeAccountBookmarkSyncMetadataResult
      decode_account_bookmark_sync_metadata_result_ =
          DecodeAccountBookmarkSyncMetadataResult::kSuccess;

  base::RepeatingClosure metrics_callback_;
  raw_ptr<os_crypt_async::OSCryptAsync> os_crypt_async_;
};

}  // namespace bookmarks

#endif  // COMPONENTS_BOOKMARKS_TEST_TEST_BOOKMARK_CLIENT_H_
