// 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::Bind(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::Bind(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 AccountInfo& 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
