// Copyright 2013 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_SIGNIN_ANDROID_SIGNIN_MANAGER_ANDROID_H_
#define CHROME_BROWSER_SIGNIN_ANDROID_SIGNIN_MANAGER_ANDROID_H_

#include <optional>
#include <string>
#include <vector>

#include "base/android/scoped_java_ref.h"
#include "base/functional/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "components/keyed_service/core/keyed_service.h"
#include "google_apis/gaia/gaia_id.h"

namespace policy {
class UserCloudPolicyManager;
class UserPolicySigninService;
}  // namespace policy

namespace signin {
class IdentityManager;
}

struct CoreAccountInfo;
class Profile;

// TODO(crbug.com/469293318): Merge this enum with DataWipeOption in
// SigninManager.
enum class ClearedTypes {
  // Clear the service worker caches for Google domains.
  kGoogleServiceWorkerCaches,
  // Clear all the profile data.
  kAllData
};

// Android wrapper of Chrome's C++ identity management code which provides
// access from the Java layer. Note that on Android, there's only a single
// profile, and therefore a single instance of this wrapper. The name of the
// Java class is SigninManager. This class should only be accessed from the UI
// thread.
//
// This class implements parts of the sign-in flow, to make sure that policy
// is available before sign-in completes.
class SigninManagerAndroid : public KeyedService {
 public:
  SigninManagerAndroid(Profile* profile,
                       signin::IdentityManager* identity_manager);

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

  ~SigninManagerAndroid() override;

  void Shutdown() override;

  base::android::ScopedJavaLocalRef<jobject> GetJavaObject();

  // Registers a CloudPolicyClient for fetching policy for a user and fetches
  // the policy if necessary.
  void FetchAndApplyCloudPolicy(JNIEnv* env,
                                const CoreAccountInfo& account,
                                const base::RepeatingClosure& callback);

  void StopApplyingCloudPolicy(JNIEnv* env);

  // Delete all data for this profile.
  void WipeProfileData(JNIEnv* env, const base::RepeatingClosure& callback);

  // Delete service worker caches for google.<eTLD>.
  void WipeGoogleServiceWorkerCaches(JNIEnv* env,
                                     const base::RepeatingClosure& callback);

  // Configures the AccountExtensionTracker to uninstall signed-in account
  // extensions during the next sign-out event.
  void SetUninstallAccountExtensionsOnSignout(JNIEnv* env, bool uninstall);

  // Returns true if there are any signed-in account extensions installed.
  bool HasSignedInAccountExtensions(JNIEnv* env);

  void SetUserAcceptedAccountManagement(JNIEnv* env,
                                        bool accepted_account_management);

  bool GetUserAcceptedAccountManagement(JNIEnv* env);

 private:
  friend class SigninManagerAndroidTest;
  FRIEND_TEST_ALL_PREFIXES(SigninManagerAndroidTest,
                           DeleteGoogleServiceWorkerCaches);

  struct ManagementCredentials {
    ManagementCredentials(const std::string& dm_token,
                          const std::string& client_id,
                          const std::vector<std::string>& user_affiliation_ids);
    ~ManagementCredentials();
    const std::string dm_token;
    const std::string client_id;
    const std::vector<std::string> user_affiliation_ids;
  };

  // Cached value for a previous execution of IsAccountManaged().
  struct CachedIsAccountManaged {
    GaiaId gaia_id;
    bool is_account_managed;
    base::Time expiration_time;
  };

  static bool MatchesCachedIsAccountManagedEntry(
      const CachedIsAccountManaged& cached_entry,
      const CoreAccountInfo& account);

  using RegisterPolicyWithAccountCallback = base::OnceCallback<void(
      const std::optional<ManagementCredentials>& credentials)>;

  // If required registers for policy with given account. callback will be
  // called with credentials if the account is managed.
  void RegisterPolicyWithAccount(const CoreAccountInfo& account,
                                 RegisterPolicyWithAccountCallback callback);

  void OnPolicyRegisterDone(
      const CoreAccountInfo& account_id,
      base::OnceCallback<void()> policy_callback,
      const std::optional<ManagementCredentials>& credentials);

  void FetchPolicyBeforeSignIn(const CoreAccountInfo& account_id,
                               base::OnceCallback<void()> policy_callback,
                               const ManagementCredentials& credentials);

  static void WipeData(Profile* profile,
                       ClearedTypes cleared_types,
                       base::OnceClosure callback);

  const raw_ptr<Profile> profile_ = nullptr;

  const raw_ptr<signin::IdentityManager> identity_manager_ = nullptr;
  const raw_ptr<policy::UserCloudPolicyManager> user_cloud_policy_manager_ =
      nullptr;
  const raw_ptr<policy::UserPolicySigninService> user_policy_signin_service_ =
      nullptr;

  // Java-side SigninManager object.
  base::android::ScopedJavaGlobalRef<jobject> java_signin_manager_;

  base::ThreadChecker thread_checker_;

  base::WeakPtrFactory<SigninManagerAndroid> weak_factory_;
};

#endif  // CHROME_BROWSER_SIGNIN_ANDROID_SIGNIN_MANAGER_ANDROID_H_
