// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "google_apis/drive/auth_service.h"

#include <string>
#include <vector>

#include "base/bind.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "google_apis/drive/auth_service_observer.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "services/identity/public/cpp/access_token_fetcher.h"
#include "services/identity/public/cpp/access_token_info.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"

namespace google_apis {

namespace {

// Used for success ratio histograms. 0 for failure, 1 for success,
// 2 for no connection (likely offline).
const int kSuccessRatioHistogramFailure = 0;
const int kSuccessRatioHistogramSuccess = 1;
const int kSuccessRatioHistogramNoConnection = 2;
const int kSuccessRatioHistogramTemporaryFailure = 3;
const int kSuccessRatioHistogramMaxValue = 4;  // The max value is exclusive.

void RecordAuthResultHistogram(int value) {
  UMA_HISTOGRAM_ENUMERATION("GData.AuthSuccess", value,
                            kSuccessRatioHistogramMaxValue);
}

// OAuth2 authorization token retrieval request.
class AuthRequest {
 public:
  AuthRequest(identity::IdentityManager* identity_manager,
              const std::string& account_id,
              scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
              const AuthStatusCallback& callback,
              const std::vector<std::string>& scopes);
  ~AuthRequest();

 private:
  void OnAccessTokenFetchComplete(GoogleServiceAuthError error,
                                  identity::AccessTokenInfo token_info);

  AuthStatusCallback callback_;
  std::unique_ptr<identity::AccessTokenFetcher> access_token_fetcher_;
  base::ThreadChecker thread_checker_;

  DISALLOW_COPY_AND_ASSIGN(AuthRequest);
};

AuthRequest::AuthRequest(
    identity::IdentityManager* identity_manager,
    const std::string& account_id,
    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
    const AuthStatusCallback& callback,
    const std::vector<std::string>& scopes)
    : callback_(callback) {
  DCHECK(identity_manager);
  DCHECK(!callback_.is_null());

  access_token_fetcher_ = identity_manager->CreateAccessTokenFetcherForAccount(
      account_id, "auth_service", url_loader_factory,
      identity::ScopeSet(scopes.begin(), scopes.end()),
      base::BindOnce(&AuthRequest::OnAccessTokenFetchComplete,
                     base::Unretained(this)),
      identity::AccessTokenFetcher::Mode::kImmediate);
}

AuthRequest::~AuthRequest() {}

void AuthRequest::OnAccessTokenFetchComplete(
    GoogleServiceAuthError error,
    identity::AccessTokenInfo token_info) {
  DCHECK(thread_checker_.CalledOnValidThread());

  if (error.state() == GoogleServiceAuthError::NONE) {
    RecordAuthResultHistogram(kSuccessRatioHistogramSuccess);
    callback_.Run(HTTP_SUCCESS, token_info.token);
  } else {
    LOG(WARNING) << "AuthRequest: token request using refresh token failed: "
                 << error.ToString();

    // There are many ways to fail, but if the failure is due to connection,
    // it's likely that the device is off-line. We treat the error differently
    // so that the file manager works while off-line.
    if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED) {
      RecordAuthResultHistogram(kSuccessRatioHistogramNoConnection);
      callback_.Run(DRIVE_NO_CONNECTION, std::string());
    } else if (error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE) {
      RecordAuthResultHistogram(kSuccessRatioHistogramTemporaryFailure);
      callback_.Run(HTTP_FORBIDDEN, std::string());
    } else {
      // Permanent auth error.
      RecordAuthResultHistogram(kSuccessRatioHistogramFailure);
      callback_.Run(HTTP_UNAUTHORIZED, std::string());
    }
  }

  delete this;
}

}  // namespace

AuthService::AuthService(
    identity::IdentityManager* identity_manager,
    const std::string& account_id,
    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
    const std::vector<std::string>& scopes)
    : identity_manager_(identity_manager),
      account_id_(account_id),
      url_loader_factory_(url_loader_factory),
      scopes_(scopes),
      weak_ptr_factory_(this) {
  DCHECK(identity_manager_);

  identity_manager_->AddObserver(this);
  has_refresh_token_ =
      identity_manager_->HasAccountWithRefreshToken(account_id_);
}

AuthService::~AuthService() {
  identity_manager_->RemoveObserver(this);
}

void AuthService::StartAuthentication(const AuthStatusCallback& callback) {
  DCHECK(thread_checker_.CalledOnValidThread());

  if (HasAccessToken()) {
    // We already have access token. Give it back to the caller asynchronously.
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE, base::BindOnce(callback, HTTP_SUCCESS, access_token_));
  } else if (HasRefreshToken()) {
    // We have refresh token, let's get an access token.
    new AuthRequest(identity_manager_, account_id_, url_loader_factory_,
                    base::Bind(&AuthService::OnAuthCompleted,
                               weak_ptr_factory_.GetWeakPtr(), callback),
                    scopes_);
  } else {
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE, base::BindOnce(callback, DRIVE_NOT_READY, std::string()));
  }
}

bool AuthService::HasAccessToken() const {
  return !access_token_.empty();
}

bool AuthService::HasRefreshToken() const {
  return has_refresh_token_;
}

const std::string& AuthService::access_token() const {
  return access_token_;
}

void AuthService::ClearAccessToken() {
  access_token_.clear();
}

void AuthService::ClearRefreshToken() {
  OnHandleRefreshToken(false);
}

void AuthService::OnAuthCompleted(const AuthStatusCallback& callback,
                                  DriveApiErrorCode error,
                                  const std::string& access_token) {
  DCHECK(thread_checker_.CalledOnValidThread());
  DCHECK(!callback.is_null());

  if (error == HTTP_SUCCESS) {
    access_token_ = access_token;
  } else if (error == HTTP_UNAUTHORIZED) {
    // Refreshing access token using the refresh token is failed with 401 error
    // (HTTP_UNAUTHORIZED). This means the current refresh token is invalid for
    // Drive, hence we clear the refresh token here to make HasRefreshToken()
    // false, thus the invalidness is clearly observable.
    // This is not for triggering refetch of the refresh token. UI should
    // show some message to encourage user to log-off and log-in again in order
    // to fetch new valid refresh token.
    ClearRefreshToken();
  }

  callback.Run(error, access_token);
}

void AuthService::AddObserver(AuthServiceObserver* observer) {
  observers_.AddObserver(observer);
}

void AuthService::RemoveObserver(AuthServiceObserver* observer) {
  observers_.RemoveObserver(observer);
}

void AuthService::OnRefreshTokenUpdatedForAccount(
    const CoreAccountInfo& account_info) {
  if (account_info.account_id == account_id_)
    OnHandleRefreshToken(true);
}

void AuthService::OnRefreshTokenRemovedForAccount(
    const std::string& account_id) {
  if (account_id == account_id_)
    OnHandleRefreshToken(false);
}

void AuthService::OnHandleRefreshToken(bool has_refresh_token) {
  access_token_.clear();
  has_refresh_token_ = has_refresh_token;

  for (auto& observer : observers_)
    observer.OnOAuth2RefreshTokenChanged();
}

}  // namespace google_apis
