// Copyright 2015 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_SIGNIN_INTERNAL_IDENTITY_MANAGER_FAKE_PROFILE_OAUTH2_TOKEN_SERVICE_DELEGATE_H_
#define COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_FAKE_PROFILE_OAUTH2_TOKEN_SERVICE_DELEGATE_H_

#include <list>
#include <memory>
#include <vector>

#include "base/containers/span.h"
#include "base/functional/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "build/build_config.h"
#include "components/signin/internal/identity_manager/profile_oauth2_token_service_delegate.h"
#include "components/signin/public/base/signin_buildflags.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#if BUILDFLAG(IS_IOS)
#include "components/signin/public/identity_manager/access_token_fetcher.h"
#include "components/signin/public/identity_manager/access_token_info.h"
#endif

#if BUILDFLAG(ENABLE_DICE_SUPPORT)
#include "components/signin/public/base/binding_key_registration_token_result.h"
#include "components/unexportable_keys/unexportable_key_id.h"
#endif

namespace network {
class SharedURLLoaderFactory;
}

class FakeProfileOAuth2TokenServiceDelegate
    : public ProfileOAuth2TokenServiceDelegate {
 public:
  FakeProfileOAuth2TokenServiceDelegate();

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

  ~FakeProfileOAuth2TokenServiceDelegate() override;

  std::unique_ptr<OAuth2AccessTokenFetcher> CreateAccessTokenFetcher(
      const CoreAccountId& account_id,
      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
      OAuth2AccessTokenConsumer* consumer,
      const std::string& token_binding_challenge) override;

#if BUILDFLAG(IS_IOS)
  void GetRefreshTokenFromDevice(
      const CoreAccountId& account_id,
      const OAuth2AccessTokenManager::ScopeSet& scopes,
      signin::AccessTokenFetcher::TokenCallback callback) override;
#endif

  // Overriden to make sure it works on Android.
  bool RefreshTokenIsAvailable(const CoreAccountId& account_id) const override;

#if BUILDFLAG(IS_IOS)
  bool RefreshTokenIsAvailableOnDevice(
      const CoreAccountId& account_id) const override;
#endif  // BUILDFLAG(IS_IOS)

#if BUILDFLAG(ENABLE_DICE_SUPPORT)
  bool GenerateBindingKeyRegistrationToken(
      base::span<const crypto::SignatureVerifier::SignatureAlgorithm>
          supported_algorithms,
      std::string_view auth_code,
      base::OnceCallback<void(
          std::optional<signin::BindingKeyRegistrationTokenResult>)> callback)
      override;
  void EnableTokenBindingRegistration();
  void IssueTokenBindingRegistrationTokenForAuthCode(
      std::string_view auth_code,
      std::optional<signin::BindingKeyRegistrationTokenResult> result);
  bool IsRefreshTokenBoundToKey(const CoreAccountId& account_id) const override;
  std::vector<uint8_t> GetWrappedBindingKey(
      const CoreAccountId& account_id) const override;
  bool IsRefreshTokenBoundToMtls(
      const CoreAccountId& account_id) const override;
  bool AllBoundTokensShareSameBindingKey() const override;
  void GenerateRefreshTokenBindingKeyAssertionForMultilogin(
      const CoreAccountId& account_id,
      std::string_view challenge,
      std::string_view ephemeral_public_key,
      TokenBindingHelper::GenerateAssertionCallback callback) override;
  void AddBindingKeyToService(
      base::span<const uint8_t> wrapped_binding_key) override;
#endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)

  std::vector<CoreAccountId> GetAccounts() const override;

#if BUILDFLAG(IS_IOS)
  std::vector<AccountInfo> GetAccountsOnDevice() const override;
#endif  // BUILDFLAG(IS_IOS)

  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory()
      const override;

  FakeProfileOAuth2TokenServiceDelegate*
  AsFakeProfileOAuth2TokenServiceDelegateForTesting() override;

  bool FixAccountErrorIfPossible() override;

  std::string GetRefreshToken(const CoreAccountId& account_id) const;

  network::TestURLLoaderFactory* test_url_loader_factory() {
    return &test_url_loader_factory_;
  }

  void set_fix_request_if_possible(base::RepeatingCallback<bool()> callback) {
    fix_account_if_possible_ = std::move(callback);
  }

 private:
  // ProfileOAuth2TokenServiceDelegate implementation:
  void RevokeAllCredentialsInternal(
      signin_metrics::SourceForRefreshTokenOperation source) override;
  void LoadCredentialsInternal(
      const CoreAccountId& primary_account_id) override;
  void UpdateCredentialsInternal(
      const CoreAccountId& account_id,
      const std::string& refresh_token,
      const signin::TokenBindingInfo& token_binding_info) override;
  void RevokeCredentialsInternal(const CoreAccountId& account_id) override;
  void ExtractCredentialsInternal(ProfileOAuth2TokenService* to_service,
                                  const CoreAccountId& account_id) override;

  void IssueRefreshTokenForUser(
      const CoreAccountId& account_id,
      const std::string& token,
      const signin::TokenBindingInfo& token_binding_info);

#if BUILDFLAG(IS_ANDROID)
  base::android::ScopedJavaLocalRef<jobject> GetJavaObject() override;
#endif

  // The account IDs, in the order they were first added.
  // A given account ID appears at most once in this list.
  std::list<CoreAccountId> account_ids_;

  // Maps account ids to tokens.
  std::map<CoreAccountId, std::string> refresh_tokens_;

  std::map<CoreAccountId, std::vector<uint8_t>> wrapped_binding_keys_;

#if BUILDFLAG(ENABLE_DICE_SUPPORT)
  bool is_token_binding_registration_enabled_ = false;
  std::map<std::string,
           base::OnceCallback<void(
               std::optional<signin::BindingKeyRegistrationTokenResult>)>>
      pending_token_binding_callbacks_;
  std::map<CoreAccountId, bool> mtls_token_bindings_;
#endif

  network::TestURLLoaderFactory test_url_loader_factory_;
  scoped_refptr<network::SharedURLLoaderFactory> shared_factory_;
  base::RepeatingCallback<bool()> fix_account_if_possible_;
};
#endif  // COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_FAKE_PROFILE_OAUTH2_TOKEN_SERVICE_DELEGATE_H_
