// Copyright 2017 The Fuchsia 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 "peridot/bin/cloud_provider_firestore/testing/cloud_provider_factory.h"

#include <utility>

#include <fuchsia/net/oldhttp/cpp/fidl.h>
#include <lib/async/cpp/task.h>
#include <lib/backoff/exponential_backoff.h>
#include <lib/fit/function.h>
#include <lib/fxl/functional/make_copyable.h>
#include <lib/svc/cpp/services.h>

#include "peridot/lib/convert/convert.h"

namespace cloud_provider_firestore {
namespace {
namespace http = ::fuchsia::net::oldhttp;

constexpr char kAppUrl[] =
    "fuchsia-pkg://fuchsia.com/cloud_provider_firestore"
    "#meta/cloud_provider_firestore.cmx";

std::string GenerateUserId() {
  // Always use a real random generator for user ids.
  rng::SystemRandom system_random;
  return convert::ToHex(system_random.RandomUniqueBytes());
}

}  // namespace

CloudProviderFactory::UserId::UserId(const UserId& user_id) = default;

CloudProviderFactory::UserId::UserId(UserId&& user_id) = default;

CloudProviderFactory::UserId& CloudProviderFactory::UserId::operator=(
    const UserId& user_id) = default;

CloudProviderFactory::UserId& CloudProviderFactory::UserId::operator=(
    UserId&& user_id) = default;

CloudProviderFactory::UserId CloudProviderFactory::UserId::New() {
  return UserId();
}

CloudProviderFactory::UserId::UserId() : user_id_(GenerateUserId()) {}

class CloudProviderFactory::TokenManagerContainer {
 public:
  TokenManagerContainer(
      component::StartupContext* startup_context,
      async_dispatcher_t* dispatcher, rng::Random* random,
      std::unique_ptr<service_account::Credentials> credentials,
      std::string user_id,
      fidl::InterfaceRequest<fuchsia::auth::TokenManager> request)
      : startup_context_(startup_context),
        network_wrapper_(
            dispatcher,
            std::make_unique<backoff::ExponentialBackoff>(
                random->NewBitGenerator<uint64_t>()),
            [this] {
              return startup_context_
                  ->ConnectToEnvironmentService<http::HttpService>();
            }),
        token_manager_(&network_wrapper_, std::move(credentials),
                       std::move(user_id)),
        binding_(&token_manager_, std::move(request)) {}

  void set_on_empty(fit::closure on_empty) {
    binding_.set_error_handler(
        [on_empty = std::move(on_empty)](zx_status_t status) { on_empty(); });
  }

 private:
  component::StartupContext* const startup_context_;
  network_wrapper::NetworkWrapperImpl network_wrapper_;
  service_account::ServiceAccountTokenManager token_manager_;
  fidl::Binding<fuchsia::auth::TokenManager> binding_;

  FXL_DISALLOW_COPY_AND_ASSIGN(TokenManagerContainer);
};

CloudProviderFactory::CloudProviderFactory(
    component::StartupContext* startup_context, rng::Random* random,
    std::string api_key,
    std::unique_ptr<service_account::Credentials> credentials)
    : startup_context_(startup_context),
      random_(random),
      api_key_(std::move(api_key)),
      credentials_(std::move(credentials)),
      services_loop_(&kAsyncLoopConfigNoAttachToThread) {
  FXL_DCHECK(startup_context);
  FXL_DCHECK(!api_key_.empty());
}

CloudProviderFactory::~CloudProviderFactory() { services_loop_.Shutdown(); }

void CloudProviderFactory::Init() {
  services_loop_.StartThread();
  component::Services child_services;
  fuchsia::sys::LaunchInfo launch_info;
  launch_info.url = kAppUrl;
  launch_info.directory_request = child_services.NewRequest();
  startup_context_->launcher()->CreateComponent(
      std::move(launch_info), cloud_provider_controller_.NewRequest());
  child_services.ConnectToService(cloud_provider_factory_.NewRequest());
}

void CloudProviderFactory::MakeCloudProvider(
    UserId user_id,
    fidl::InterfaceRequest<cloud_provider::CloudProvider> request) {
  fuchsia::auth::TokenManagerPtr token_manager;
  MakeTokenManager(std::move(user_id), token_manager.NewRequest());

  cloud_provider_firestore::Config firebase_config;
  firebase_config.server_id = credentials_->project_id();
  firebase_config.api_key = api_key_;

  cloud_provider_factory_->GetCloudProvider(
      std::move(firebase_config), std::move(token_manager), std::move(request),
      [](cloud_provider::Status status) {
        if (status != cloud_provider::Status::OK) {
          FXL_LOG(ERROR) << "Failed to create a cloud provider: "
                         << fidl::ToUnderlying(status);
        }
      });
}

void CloudProviderFactory::MakeTokenManager(
    UserId user_id,
    fidl::InterfaceRequest<fuchsia::auth::TokenManager> request) {
  async::PostTask(services_loop_.dispatcher(),
                  fxl::MakeCopyable([this, user_id = std::move(user_id),
                                     request = std::move(request)]() mutable {
                    token_managers_.emplace(
                        startup_context_, services_loop_.dispatcher(), random_,
                        credentials_->Clone(), std::move(user_id.user_id()),
                        std::move(request));
                  }));
}

}  // namespace cloud_provider_firestore
