// Copyright 2015 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 "remoting/test/app_remoting_test_driver_environment.h"

#include <map>
#include <string>
#include <vector>

#include "base/bind.h"
#include "base/callback_forward.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "remoting/test/access_token_fetcher.h"
#include "remoting/test/app_remoting_report_issue_request.h"
#include "remoting/test/refresh_token_store.h"
#include "remoting/test/remote_host_info.h"

namespace remoting {
namespace test {

AppRemotingTestDriverEnvironment* AppRemotingSharedData;

AppRemotingTestDriverEnvironment::EnvironmentOptions::EnvironmentOptions()
    : refresh_token_file_path(base::FilePath()),
      service_environment(kUnknownEnvironment),
      release_hosts_when_done(false) {}

AppRemotingTestDriverEnvironment::EnvironmentOptions::~EnvironmentOptions() {}

AppRemotingTestDriverEnvironment::AppRemotingTestDriverEnvironment(
    const EnvironmentOptions& options)
    : user_name_(options.user_name),
      service_environment_(options.service_environment),
      release_hosts_when_done_(options.release_hosts_when_done),
      refresh_token_file_path_(options.refresh_token_file_path),
      test_access_token_fetcher_(nullptr),
      test_app_remoting_report_issue_request_(nullptr),
      test_refresh_token_store_(nullptr),
      test_remote_host_info_fetcher_(nullptr) {
  DCHECK(!user_name_.empty());
  DCHECK(service_environment_ < kUnknownEnvironment);
}

AppRemotingTestDriverEnvironment::~AppRemotingTestDriverEnvironment() {}

bool AppRemotingTestDriverEnvironment::Initialize(
    const std::string& auth_code) {
  if (!access_token_.empty()) {
    return true;
  }

  if (!base::MessageLoop::current()) {
    message_loop_.reset(new base::MessageLoopForIO);
  }

  // If a unit test has set |test_refresh_token_store_| then we should use it
  // below.  Note that we do not want to destroy the test object.
  std::unique_ptr<RefreshTokenStore> temporary_refresh_token_store;
  RefreshTokenStore* refresh_token_store = test_refresh_token_store_;
  if (!refresh_token_store) {
    temporary_refresh_token_store =
        RefreshTokenStore::OnDisk(user_name_, refresh_token_file_path_);
    refresh_token_store = temporary_refresh_token_store.get();
  }

  // Check to see if we have a refresh token stored for this user.
  refresh_token_ = refresh_token_store->FetchRefreshToken();
  if (refresh_token_.empty()) {
    // This isn't necessarily an error as this might be a first run scenario.
    VLOG(2) << "No refresh token stored for " << user_name_;

    if (auth_code.empty()) {
      // No token and no Auth code means no service connectivity, bail!
      LOG(ERROR) << "Cannot retrieve an access token without a stored refresh"
                 << " token on disk or an auth_code passed into the tool";
      return false;
    }
  }

  if (!RetrieveAccessToken(auth_code)) {
    // If we cannot retrieve an access token, then nothing is going to work and
    // we should let the caller know that our object is not ready to be used.
    return false;
  }

  return true;
}

bool AppRemotingTestDriverEnvironment::RefreshAccessToken() {
  DCHECK(!refresh_token_.empty());

  // Empty auth code is used when refreshing.
  return RetrieveAccessToken(std::string());
}

bool AppRemotingTestDriverEnvironment::GetRemoteHostInfoForApplicationId(
    const std::string& application_id,
    RemoteHostInfo* remote_host_info) {
  DCHECK(!application_id.empty());
  DCHECK(remote_host_info);

  if (access_token_.empty()) {
    LOG(ERROR) << "RemoteHostInfo requested without a valid access token. "
               << "Ensure the environment object has been initialized.";
    return false;
  }

  base::RunLoop run_loop;

  RemoteHostInfoCallback remote_host_info_fetch_callback = base::Bind(
      &AppRemotingTestDriverEnvironment::OnRemoteHostInfoRetrieved,
      base::Unretained(this), run_loop.QuitClosure(), remote_host_info);

  // If a unit test has set |test_remote_host_info_fetcher_| then we should use
  // it below.  Note that we do not want to destroy the test object at the end
  // of the function which is why we have the dance below.
  std::unique_ptr<RemoteHostInfoFetcher> temporary_remote_host_info_fetcher;
  RemoteHostInfoFetcher* remote_host_info_fetcher =
      test_remote_host_info_fetcher_;
  if (!remote_host_info_fetcher) {
    temporary_remote_host_info_fetcher.reset(new RemoteHostInfoFetcher());
    remote_host_info_fetcher = temporary_remote_host_info_fetcher.get();
  }

  remote_host_info_fetcher->RetrieveRemoteHostInfo(
      application_id, access_token_, service_environment_,
      remote_host_info_fetch_callback);

  run_loop.Run();

  return remote_host_info->IsReadyForConnection();
}

void AppRemotingTestDriverEnvironment::AddHostToReleaseList(
    const std::string& application_id,
    const std::string& host_id) {
  if (!release_hosts_when_done_) {
    return;
  }

  auto map_iterator = host_ids_to_release_.find(application_id);
  if (map_iterator == host_ids_to_release_.end()) {
    std::vector<std::string> host_id_list(1, host_id);
    host_ids_to_release_.insert(std::make_pair(application_id, host_id_list));
  } else {
    std::vector<std::string>* host_ids = &map_iterator->second;
    if (std::find(host_ids->begin(), host_ids->end(), host_id) ==
        host_ids->end()) {
      host_ids->push_back(host_id);
    }
  }
}

void AppRemotingTestDriverEnvironment::ShowHostAvailability() {
  const char kHostAvailabilityFormatString[] = "%-25s%-35s%-10s";

  LOG(INFO) << base::StringPrintf(kHostAvailabilityFormatString,
                                  "Application Name", "Application ID",
                                  "Status");

  for (const auto& application_name : application_names_) {
    const RemoteApplicationDetails& application_details =
        GetDetailsFromAppName(application_name);

    RemoteHostInfo remote_host_info;
    GetRemoteHostInfoForApplicationId(application_details.application_id,
                                      &remote_host_info);

    std::string status;
    RemoteHostStatus remote_host_status = remote_host_info.remote_host_status;
    if (remote_host_status == kRemoteHostStatusReady) {
      status = "Ready :)";
    } else if (remote_host_status == kRemoteHostStatusPending) {
      status = "Pending :|";
    } else {
      status = "Unknown :(";
    }

    LOG(INFO) << base::StringPrintf(
        kHostAvailabilityFormatString, application_name.c_str(),
        application_details.application_id.c_str(), status.c_str());
  }
}

const RemoteApplicationDetails&
AppRemotingTestDriverEnvironment::GetDetailsFromAppName(
    const std::string& application_name) {
  const auto map_pair_iterator =
      application_details_map_.find(application_name);
  DCHECK(map_pair_iterator != application_details_map_.end());

  return map_pair_iterator->second;
}

void AppRemotingTestDriverEnvironment::SetAccessTokenFetcherForTest(
    AccessTokenFetcher* access_token_fetcher) {
  DCHECK(access_token_fetcher);

  test_access_token_fetcher_ = access_token_fetcher;
}

void AppRemotingTestDriverEnvironment::SetAppRemotingReportIssueRequestForTest(
    AppRemotingReportIssueRequest* app_remoting_report_issue_request) {
  DCHECK(app_remoting_report_issue_request);

  test_app_remoting_report_issue_request_ = app_remoting_report_issue_request;
}

void AppRemotingTestDriverEnvironment::SetRefreshTokenStoreForTest(
    RefreshTokenStore* refresh_token_store) {
  DCHECK(refresh_token_store);

  test_refresh_token_store_ = refresh_token_store;
}

void AppRemotingTestDriverEnvironment::SetRemoteHostInfoFetcherForTest(
    RemoteHostInfoFetcher* remote_host_info_fetcher) {
  DCHECK(remote_host_info_fetcher);

  test_remote_host_info_fetcher_ = remote_host_info_fetcher;
}

void AppRemotingTestDriverEnvironment::TearDown() {
  // If a unit test has set |test_app_remoting_report_issue_request_| then we
  // should use it below.  Note that we do not want to destroy the test object
  // at the end of the function which is why we have the dance below.
  std::unique_ptr<AppRemotingReportIssueRequest> temporary_report_issue_request;
  AppRemotingReportIssueRequest* report_issue_request =
      test_app_remoting_report_issue_request_;
  if (!report_issue_request) {
    temporary_report_issue_request.reset(new AppRemotingReportIssueRequest());
    report_issue_request = temporary_report_issue_request.get();
  }

  for (const auto& kvp : host_ids_to_release_) {
    std::string application_id = kvp.first;
    VLOG(1) << "Releasing hosts for application: " << application_id;

    for (const auto& host_id : kvp.second) {
      base::RunLoop run_loop;

      VLOG(1) << "    Releasing host: " << host_id;
      bool request_started = report_issue_request->Start(
          application_id, host_id, access_token_, service_environment_, true,
          run_loop.QuitClosure());

      if (request_started) {
        run_loop.Run();
      } else {
        LOG(ERROR) << "Failed to send ReportIssueRequest for: "
                   << application_id << ", " << host_id;
      }
    }
  }
  temporary_report_issue_request.reset();

  // Letting the MessageLoop tear down during the test destructor results in
  // errors after test completion, when the MessageLoop dtor touches the
  // registered AtExitManager. The AtExitManager is torn down before the test
  // destructor is executed, so we tear down the MessageLoop here, while it is
  // still valid.
  message_loop_.reset();
}

bool AppRemotingTestDriverEnvironment::RetrieveAccessToken(
    const std::string& auth_code) {
  base::RunLoop run_loop;

  access_token_.clear();

  AccessTokenCallback access_token_callback =
      base::Bind(&AppRemotingTestDriverEnvironment::OnAccessTokenRetrieved,
                 base::Unretained(this), run_loop.QuitClosure());

  // If a unit test has set |test_access_token_fetcher_| then we should use it
  // below.  Note that we do not want to destroy the test object at the end of
  // the function which is why we have the dance below.
  std::unique_ptr<AccessTokenFetcher> temporary_access_token_fetcher;
  AccessTokenFetcher* access_token_fetcher = test_access_token_fetcher_;
  if (!access_token_fetcher) {
    temporary_access_token_fetcher.reset(new AccessTokenFetcher());
    access_token_fetcher = temporary_access_token_fetcher.get();
  }

  if (!auth_code.empty()) {
    // If the user passed in an authcode, then use it to retrieve an
    // updated access/refresh token.
    access_token_fetcher->GetAccessTokenFromAuthCode(auth_code,
                                                     access_token_callback);
  } else {
    DCHECK(!refresh_token_.empty());

    access_token_fetcher->GetAccessTokenFromRefreshToken(refresh_token_,
                                                         access_token_callback);
  }

  run_loop.Run();

  // If we were using an auth_code and received a valid refresh token,
  // then we want to store it locally.  If we had an auth code and did not
  // receive a refresh token, then we should let the user know and exit.
  if (!auth_code.empty()) {
    if (!refresh_token_.empty()) {
      // If a unit test has set |test_refresh_token_store_| then we should use
      // it below.  Note that we do not want to destroy the test object.
      std::unique_ptr<RefreshTokenStore> temporary_refresh_token_store;
      RefreshTokenStore* refresh_token_store = test_refresh_token_store_;
      if (!refresh_token_store) {
        temporary_refresh_token_store =
            RefreshTokenStore::OnDisk(user_name_, refresh_token_file_path_);
        refresh_token_store = temporary_refresh_token_store.get();
      }

      if (!refresh_token_store->StoreRefreshToken(refresh_token_)) {
        // If we failed to persist the refresh token, then we should let the
        // user sort out the issue before continuing.
        return false;
      }
    } else {
      LOG(ERROR) << "Failed to use AUTH CODE to retrieve a refresh token.\n"
                 << "Was the one-time use AUTH CODE used more than once?";
      return false;
    }
  }

  if (access_token_.empty()) {
    LOG(ERROR) << "Failed to retrieve access token.";
    return false;
  }

  return true;
}

void AppRemotingTestDriverEnvironment::OnAccessTokenRetrieved(
    base::Closure done_closure,
    const std::string& access_token,
    const std::string& refresh_token) {
  access_token_ = access_token;
  refresh_token_ = refresh_token;

  done_closure.Run();
}

void AppRemotingTestDriverEnvironment::OnRemoteHostInfoRetrieved(
    base::Closure done_closure,
    RemoteHostInfo* remote_host_info,
    const RemoteHostInfo& retrieved_remote_host_info) {
  DCHECK(remote_host_info);

  *remote_host_info = retrieved_remote_host_info;

  done_closure.Run();
}

}  // namespace test
}  // namespace remoting
