// Copyright 2025 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_SAFE_BROWSING_SAFE_BROWSING_PREF_CHANGE_HANDLER_H_
#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_PREF_CHANGE_HANDLER_H_

#include <memory>

#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"

#if BUILDFLAG(IS_ANDROID)
#include "chrome/browser/safe_browsing/tailored_security/chrome_tailored_security_service.h"
#include "chrome/browser/safe_browsing/tailored_security/consented_message_android.h"
#include "chrome/browser/safe_browsing/tailored_security/unconsented_message_android.h"
#include "chrome/browser/ui/android/tab_model/tab_model_list_observer.h"
#include "chrome/browser/ui/android/tab_model/tab_model_observer.h"
#endif

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN) || \
    BUILDFLAG(IS_MAC)
#include "chrome/browser/ui/toasts/toast_controller.h"
#endif

namespace content {
class WebContents;
}

class Profile;

namespace safe_browsing {

// Handles showing the appropriate toast or modal when the Safe Browsing
// protection setting changes. This class is not thread-safe.
#if BUILDFLAG(IS_ANDROID)
class SafeBrowsingPrefChangeHandler : public TabModelObserver,
                                      public TabModelListObserver {
#else
class SafeBrowsingPrefChangeHandler {
#endif
 public:
  explicit SafeBrowsingPrefChangeHandler(Profile* profile);
#if BUILDFLAG(IS_ANDROID)
  ~SafeBrowsingPrefChangeHandler() override;
#else
  virtual ~SafeBrowsingPrefChangeHandler();
#endif

  // The amount of time to wait after construction before checking if a retry is
  // needed.
  static constexpr const base::TimeDelta kRetryAttemptStartupDelay =
      base::Minutes(2);

  // The amount of time to wait between retry attempts.
  static constexpr const base::TimeDelta kRetryNextAttemptDelay = base::Days(1);

  // Length of time that the retry mechanism will wait before running. This
  // delay is used for the case where the safe browsing pref change handler
  // can't tell if it succeeded in the past.
  static constexpr const base::TimeDelta kWaitingPeriodInterval = base::Days(2);

  // Handles notifying the user when necessary. The type of notification shown
  // depends on the platform and whether the user is currently on the security
  // settings page. Virtual for tests.
  virtual void MaybeShowEnhancedProtectionSettingChangeNotification(
      content::WebContents* web_contents);
  void MaybeShowEnhancedProtectionSettingChangeNotification() {
    MaybeShowEnhancedProtectionSettingChangeNotification(nullptr);
  }

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN) || \
    BUILDFLAG(IS_MAC)
  void SetToastControllerForTesting(ToastController* controller);
#endif

 private:
  // Returns true if the notification should be suppressed for Tailored
  // Security.
  bool SuppressNotificationForTailoredSecurity();

  // Member variable to store the Profile*.
  raw_ptr<Profile> profile_;

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN) || \
    BUILDFLAG(IS_MAC)
  raw_ptr<ToastController> toast_controller_for_testing_ = nullptr;
#endif

#if BUILDFLAG(IS_ANDROID)
  // Called when the consented modal is dismissed.
  void ConsentedMessageDismissed();

  friend class SafeBrowsingPrefChangeHandlerAndroidTest;

  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingPrefChangeHandlerAndroidTest,
                           AddAndRemoveTabModelListObserver);
  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingPrefChangeHandlerAndroidTest,
                           AddAndRemoveTabModelObserver);
  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingPrefChangeHandlerAndroidTest,
                           AddTabModelObserver_NoMatchingProfile);
  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingPrefChangeHandlerAndroidTest,
                           RegisterObserver);
  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingPrefChangeHandlerAndroidTest, DidAddTab);
  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingPrefChangeHandlerAndroidTest,
                           DidAddTab_NullTab);
  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingPrefChangeHandlerAndroidTest,
                           OnTabModelAddedAndRemoved);
  FRIEND_TEST_ALL_PREFIXES(
      SafeBrowsingPrefChangeHandlerAndroidTest,
      MaybeShowEnhancedProtectionSettingChangeNotificationResetsPref);
  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingPrefChangeHandlerAndroidTest,
                           NoRetryAfterTailoredSecuritySync);

  // Functions used for testing.
  // Sets the TabModel for testing purposes.
  void SetTabModelForTesting(TabModel* tab_model);

  // Checks if the handler is currently observing the TabModelList.
  bool IsObservingTabModelListForTesting() const;

  // Checks if the handler is currently observing a TabModel.
  bool IsObservingTabModelForTesting() const;

  // Updates the retry state and tris to show notification when needed.
  void RetryStateCallback();

  // Registers this as an observer on the TabModelList and, if possible, on a
  // TabModel.
  void RegisterObserver();
  void AddTabModelListObserver();
  void AddTabModelObserver();
  void RemoveTabModelListObserver();
  void RemoveTabModelObserver();

  // TabModelObserver::
  void DidAddTab(TabAndroid* tab, TabModel::TabLaunchType type) override;
  // TabModelListObserver::
  void OnTabModelAdded(TabModel* tab_model) override;
  void OnTabModelRemoved(TabModel* tab_model) override;

  // This tab model is used for the observer based retry mechanism.
  // We can't depend on this being set as a tab can be deleted at
  // any time.
  raw_ptr<TabModel> observed_tab_model_ = nullptr;
  bool observing_tab_model_list_ = false;

  // The retry handler used to manage retry logic.
  std::unique_ptr<MessageRetryHandler> retry_handler_;

  // The modal that is shown to the user.
  std::unique_ptr<TailoredSecurityConsentedModalAndroid> message_;

  base::WeakPtrFactory<SafeBrowsingPrefChangeHandler> weak_ptr_factory_{this};
#endif
};

}  // namespace safe_browsing

#endif  // CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_PREF_CHANGE_HANDLER_H_
