// Copyright 2019 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 "src/virtualization/lib/guest_interaction/client/guest_discovery_service.h"

using ::fuchsia::virtualization::HostVsockEndpoint_Connect2_Result;

GuestDiscoveryServiceImpl::GuestDiscoveryServiceImpl(async_dispatcher_t* dispatcher)
    : context_(sys::ServiceDirectory::CreateFromNamespace(), dispatcher), executor_(dispatcher) {
  context_.svc()->Connect(manager_.NewRequest(dispatcher));
  manager_.set_error_handler([this](zx_status_t status) {
    std::lock_guard lock(lock_);
    for (auto& completer : manager_completers_) {
      completer->complete_error(status);
    }
  });
  context_.outgoing()->AddPublicService(bindings_.GetHandler(this, dispatcher));
  context_.outgoing()->ServeFromStartupInfo(dispatcher);
}

namespace {
// Helpers from the reference documentation for std::visit<>, to allow
// visit-by-overload of std::variant<>.
template <class... Ts>
struct overloaded : Ts... {
  using Ts::operator()...;
};
// explicit deduction guide (not needed as of C++20).
template <class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
}  // namespace

void GuestDiscoveryServiceImpl::GetGuest(
    fidl::StringPtr realm_name, std::string guest_name,
    fidl::InterfaceRequest<fuchsia::netemul::guest::GuestInteraction> request) {
  // Find the realm ID and guest instance ID associated with the caller's labels.
  fpromise::bridge<GuestInfo, zx_status_t> bridge;
  std::shared_ptr completer =
      std::make_shared<decltype(bridge.completer)>(std::move(bridge.completer));
  {
    std::lock_guard lock(lock_);
    manager_completers_.insert(completer);
  }
  manager_->List([completer,
                  realm_name = realm_name.value_or(fuchsia::netemul::guest::DEFAULT_REALM),
                  guest_name = std::move(guest_name)](
                     const std::vector<fuchsia::virtualization::EnvironmentInfo>& realm_infos) {
    for (const auto& realm_info : realm_infos) {
      if (realm_info.label == realm_name) {
        for (const auto& instance_info : realm_info.instances) {
          if (instance_info.label == guest_name) {
            completer->complete_ok({
                .realm_id = realm_info.id,
                .guest_cid = instance_info.cid,
            });
            return;
          }
        }
      }
    }
    completer->complete_error(ZX_ERR_NOT_FOUND);
  });
  fpromise::promise<> task =
      bridge.consumer.promise()
          .inspect([this, completer](const fpromise::result<GuestInfo, zx_status_t>&) {
            std::lock_guard lock(lock_);
            manager_completers_.erase(completer);
          })
          .and_then([this](const GuestInfo& guest_info)
                        -> fpromise::promise<FuchsiaGuestInteractionService*, zx_status_t> {
            auto [it, inserted] = guests_.try_emplace(guest_info);
            std::variant<GuestCompleters, FuchsiaGuestInteractionService>& variant = it->second;
            if (!inserted) {
              // An entry already exists; the connection to the guest is either complete or in
              // progress; if it is complete, return a resolved promise, otherwise store a completer
              // to be resolved when the connection completes.
              return std::visit(
                  overloaded{
                      [](FuchsiaGuestInteractionService& guest)
                          -> fpromise::promise<FuchsiaGuestInteractionService*, zx_status_t> {
                        return fpromise::make_result_promise<FuchsiaGuestInteractionService*,
                                                             zx_status_t>(fpromise::ok(&guest));
                      },
                      [](GuestCompleters& completers)
                          -> fpromise::promise<FuchsiaGuestInteractionService*, zx_status_t> {
                        fpromise::bridge<FuchsiaGuestInteractionService*, zx_status_t> bridge;
                        completers.push_back(std::move(bridge.completer));
                        return bridge.consumer.promise();
                      },
                  },
                  variant);
            }

            fuchsia::virtualization::RealmSyncPtr realm;
            manager_->Connect(guest_info.realm_id, realm.NewRequest());

            fpromise::bridge<FuchsiaGuestInteractionService*, zx_status_t> bridge;
            std::shared_ptr completer =
                std::make_shared<decltype(bridge.completer)>(std::move(bridge.completer));

            fuchsia::virtualization::HostVsockEndpointPtr ep;
            ep.set_error_handler(
                [completer](zx_status_t status) { completer->complete_error(status); });
            realm->GetHostVsockEndpoint(ep.NewRequest(executor_.dispatcher()));

            auto completers_cb = [this, guest_info, &variant, completer](
                                     GuestCompleters completers, zx::socket socket,
                                     zx_status_t status) mutable {
              if (status != ZX_OK) {
                // Connecting to the guest failed; notify pending completers and remove the entry to
                // allow retries.
                completer->complete_error(status);
                for (auto& pending : completers) {
                  pending.complete_error(status);
                }
                guests_.erase(guest_info);
              } else {
                // Connecting to the guest succeeded; replace pending completers with the complete
                // connection and notify them.
                FuchsiaGuestInteractionService& guest =
                    variant.emplace<FuchsiaGuestInteractionService>(std::move(socket),
                                                                    executor_.dispatcher());
                completer->complete_ok(&guest);
                for (auto& pending : completers) {
                  pending.complete_ok(&guest);
                }
              }
            };

            auto connect_cb = [completer, completers_cb = std::move(completers_cb),
                               &variant](HostVsockEndpoint_Connect2_Result result) mutable {
              std::visit(overloaded{
                             [completer](FuchsiaGuestInteractionService& guest) {
                               // We completed the connection to the guest and
                               // discovered an already-existing connection. This should
                               // never happen.
                               FX_LOGS(ERROR) << "existing connection in connection callback";
                               completer->complete_ok(&guest);
                             },
                             [&](GuestCompleters& completers) {
                               if (result.is_response()) {
                                 completers_cb(std::move(completers),
                                               std::move(result.response().socket), ZX_OK);
                               } else {
                                 completers_cb(std::move(completers), zx::socket(), result.err());
                               }
                             },
                         },
                         variant);
            };

            ep->Connect2(GUEST_INTERACTION_PORT, std::move(connect_cb));

            return bridge.consumer.promise().inspect(
                [ep = std::move(ep)](
                    const fpromise::result<FuchsiaGuestInteractionService*, zx_status_t>&) {});
          })
          .and_then(
              [request = std::move(request)](FuchsiaGuestInteractionService*& service) mutable {
                service->AddBinding(std::move(request));
              })
          .or_else([](const zx_status_t& status) {
            FX_PLOGS(ERROR, status) << "Guest connection failed";
          })
          .wrap_with(scope_);
  executor_.schedule_task(std::move(task));
}
