class PrefService;

namespace password_manager {

// Instantiate this object to migrate all password stored in the built-in
// backend to the Android backend. Migration is potentially an expensive
// operation and shouldn't start during the hot phase of Chrome start.
class BuiltInBackendToAndroidBackendMigrator {
 public:
  // |built_in_backend| and |android_backend| must not be null and must outlive
  // the migrator.
  BuiltInBackendToAndroidBackendMigrator(
      PasswordStoreBackend* built_in_backend,
      PasswordStoreBackend* android_backend,
      PrefService* prefs,
      PasswordStoreBackend::SyncDelegate* sync_delegate);

  BuiltInBackendToAndroidBackendMigrator(
      const BuiltInBackendToAndroidBackendMigrator&) = delete;
  BuiltInBackendToAndroidBackendMigrator& operator=(
      const BuiltInBackendToAndroidBackendMigrator&) = delete;
  BuiltInBackendToAndroidBackendMigrator(
      BuiltInBackendToAndroidBackendMigrator&&) = delete;
  BuiltInBackendToAndroidBackendMigrator& operator=(
      BuiltInBackendToAndroidBackendMigrator&&) = delete;
  ~BuiltInBackendToAndroidBackendMigrator();

  void StartMigrationIfNecessary();

 private:
  struct IsPasswordLess;
  struct BackendAndLoginsResults;
  class MigrationMetricsReporter;

  using PasswordFormPtrFlatSet =
      base::flat_set<const PasswordForm*, IsPasswordLess>;

  // Saves current migration version in |prefs_|.
  void UpdateMigrationVersionInPref();

  // Schedules async calls to read of all passwords from both backends.
  void PrepareForMigration();

  // Migrates all non-syncable data from the |built_in_backend_| to the
  // |android_backend_|. This is implemented by reading all the passwords from
  // the |built_in_backend_| and use that to issue update requests to the
  // credentials in the |android_backend_|.
  void MigrateNonSyncableDataToAndroidBackend(
      LoginsResultOrError built_in_backend_logins_or_error);

  // Migrates password between |built_in_backend_| and |android_backend_|.
  // |result| consists of passwords from the |built_in_backend_| let's call them
  // |A| and passwords from the |android_backend_| - |B|. If initial migration
  // needed this function will update both backends with |A|U|B| otherwise it
  // will replace passwords from the |built_in_backend_| with |B|.
  void MigratePasswordsBetweenAndroidAndBuiltInBackends(
      std::vector<BackendAndLoginsResults> result);

  // Updates both |built_in_backend_| and |android_backend_| such that both
  // contain the same set of passwords without deleting any password. In
  // addition, it marks the initial migration as completed.
  void MergeAndroidBackendAndBuiltInBackend(
      PasswordFormPtrFlatSet built_in_backend_logins,
      PasswordFormPtrFlatSet android_logins);

  // Updates |built_in_backend_| such that it contains the same set of passwords
  // as in |android_backend_|.
  void MirrorAndroidBackendToBuiltInBackend(
      PasswordFormPtrFlatSet built_in_backend_logins,
      PasswordFormPtrFlatSet android_logins);

  // Helper methods to {Add,Update,Remove} |form| in |backend|. This is used to
  // ensure that all the operations are happening inside
  // BuiltInBackendToAndroidBackendMigrator life-scope.
  void AddLoginToBackend(PasswordStoreBackend* backend,
                         const PasswordForm& form,
                         base::OnceClosure callback);
  void UpdateLoginInBackend(PasswordStoreBackend* backend,
                            const PasswordForm& form,
                            base::OnceClosure callback);
  void RemoveLoginFromBackend(PasswordStoreBackend* backend,
                              const PasswordForm& form,
                              base::OnceClosure callback);

  // If |changelist| is an empty changelist, migration is aborted by calling
  // MigrationFinished() indicating the migration is *not* successful.
  // Otherwise, |callback| is invoked.
  void RunCallbackOrAbortMigration(
      base::OnceClosure callback,
      absl::optional<PasswordStoreChangeList> changelist);

  // Reports metrics and deletes |metrics_reporter_|
  void MigrationFinished(bool is_success);

  const raw_ptr<PasswordStoreBackend> built_in_backend_;
  const raw_ptr<PasswordStoreBackend> android_backend_;

  const raw_ptr<PrefService> prefs_ = nullptr;

  std::unique_ptr<MigrationMetricsReporter> metrics_reporter_;

  const raw_ptr<PasswordStoreBackend::SyncDelegate> sync_delegate_;

  base::WeakPtrFactory<BuiltInBackendToAndroidBackendMigrator>
      weak_ptr_factory_{this};
};

}  // namespace password_manager

#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_BUILT_IN_BACKEND_TO_ANDROID_BACKEND_MIGRATOR_H_
