// Copyright 2022 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 <fidl/fuchsia.component.decl/cpp/wire.h>
#include <fidl/fuchsia.driver.framework/cpp/wire.h>
#include <fidl/fuchsia.runtime.test/cpp/driver/wire.h>
#include <fidl/fuchsia.runtime.test/cpp/wire.h>
#include <lib/async/cpp/executor.h>
#include <lib/driver2/logger.h>
#include <lib/driver2/namespace.h>
#include <lib/driver2/promise.h>
#include <lib/driver2/record_cpp.h>
#include <lib/driver2/runtime.h>
#include <lib/driver2/runtime_connector_impl.h>
#include <lib/fdf/cpp/channel.h>
#include <lib/fdf/dispatcher.h>
#include <lib/fpromise/bridge.h>
#include <lib/fpromise/scope.h>
#include <lib/sys/component/cpp/outgoing_directory.h>

#include <bind/fuchsia/test/cpp/bind.h>

namespace fdf {
using namespace fuchsia_driver_framework;
}  // namespace fdf

namespace fcd = fuchsia_component_decl;
namespace fio = fuchsia_io;
namespace ft = fuchsia_runtime_test;

using fpromise::error;
using fpromise::ok;
using fpromise::promise;
using fpromise::result;

namespace {

class RootDriver : public driver::RuntimeConnectorImpl {
 public:
  RootDriver(fdf::UnownedDispatcher dispatcher, fidl::WireSharedClient<fdf::Node> node,
             driver::Namespace ns, driver::Logger logger)
      : driver::RuntimeConnectorImpl(dispatcher->async_dispatcher()),
        dispatcher_(dispatcher->async_dispatcher()),
        executor_(dispatcher->async_dispatcher()),
        outgoing_(component::OutgoingDirectory::Create(dispatcher->async_dispatcher())),
        fdf_dispatcher_(std::move(dispatcher)),
        node_(std::move(node)),
        ns_(std::move(ns)),
        logger_(std::move(logger)) {}

  static constexpr const char* Name() { return "root"; }

  static zx::status<std::unique_ptr<RootDriver>> Start(fdf::wire::DriverStartArgs& start_args,
                                                       fdf::UnownedDispatcher dispatcher,
                                                       fidl::WireSharedClient<fdf::Node> node,
                                                       driver::Namespace ns,
                                                       driver::Logger logger) {
    auto driver = std::make_unique<RootDriver>(std::move(dispatcher), std::move(node),
                                               std::move(ns), std::move(logger));
    auto result = driver->Run(std::move(start_args.outgoing_dir()));
    if (result.is_error()) {
      return result.take_error();
    }
    return zx::ok(std::move(driver));
  }

  zx_status_t RegisterProtocolHandler(fdf::Channel channel) {
    // Wait for messages from the child.
    auto channel_read = std::make_unique<fdf::ChannelRead>(
        channel.release(), 0 /* options */,
        [this](fdf_dispatcher_t* dispatcher, fdf::ChannelRead* channel_read, fdf_status_t status) {
          if (status == ZX_OK) {
            zx_status_t status =
                HandleChildRuntimeRequest(fdf::UnownedChannel(channel_read->channel()));
            if (status == ZX_OK) {
              status = channel_read->Begin(fdf_dispatcher_->get());
              if (status == ZX_OK) {
                return;
              }
            }
          }
          fdf_handle_close(channel_read->channel());
          delete channel_read;
        });
    zx_status_t status = channel_read->Begin(fdf_dispatcher_->get());
    if (status != ZX_OK) {
      return status;
    }
    channel_read.release();
    return ZX_OK;
  }

  zx_status_t HandleChildRuntimeRequest(fdf::UnownedChannel channel) {
    auto read_return = channel->Read(0);
    if (read_return.is_error()) {
      FDF_LOG(ERROR, "HandleChildRuntimeRequest got unexpected read error: %s",
              zx_status_get_string(read_return.status_value()));
      return read_return.status_value();
    }

    uint32_t data = ft::wire::kParentDeviceTestData;
    void* ptr = read_return->arena.Allocate(sizeof(data));
    memcpy(ptr, &data, sizeof(data));

    auto write_status =
        channel->Write(0, read_return->arena, ptr, sizeof(data), cpp20::span<zx_handle_t>());
    if (write_status.is_error()) {
      FDF_LOG(ERROR, "HandleChildRuntimeRequest got unexpected write error: %s",
              zx_status_get_string(write_status.status_value()));
      return write_status.status_value();
    }
    return ZX_OK;
  }

 private:
  zx::status<> Run(fidl::ServerEnd<fio::Directory> outgoing_dir) {
    // Setup the outgoing directory.
    auto service = [this](fidl::ServerEnd<fdf::RuntimeConnector> server_end) {
      fidl::BindServer(dispatcher_, std::move(server_end), this);
    };
    zx::status<> status = outgoing_.AddProtocol<fdf::RuntimeConnector>(std::move(service));
    if (status.is_error()) {
      return status;
    }

    auto serve = outgoing_.Serve(std::move(outgoing_dir));
    if (serve.is_error()) {
      return serve.take_error();
    }

    RegisterProtocol(fidl::DiscoverableProtocolName<ft::DriverTransportProtocol>,
                     fit::bind_member(this, &RootDriver::RegisterProtocolHandler));

    // Start the driver.
    auto task =
        AddChild().or_else(fit::bind_member(this, &RootDriver::UnbindNode)).wrap_with(scope_);
    executor_.schedule_task(std::move(task));
    return zx::ok();
  }

  promise<void, fdf::wire::NodeError> AddChild() {
    fidl::Arena arena;

    // Offer `fuchsia.test.Handshake` to the driver that binds to the node.
    auto protocol = fcd::wire::OfferProtocol::Builder(arena)
                        .source_name(fidl::StringView::FromExternal(
                            fidl::DiscoverableProtocolName<fdf::RuntimeConnector>))
                        .target_name(fidl::StringView::FromExternal(
                            fidl::DiscoverableProtocolName<fdf::RuntimeConnector>))
                        .dependency_type(fcd::wire::DependencyType::kStrong)
                        .Build();
    fcd::wire::Offer offer = fcd::wire::Offer::WithProtocol(arena, std::move(protocol));

    // Set the properties of the node that a driver will bind to.
    auto property = fdf::wire::NodeProperty::Builder(arena)
                        .key(fdf::wire::NodePropertyKey::WithIntValue(1 /* BIND_PROTOCOL */))
                        .value(fdf::wire::NodePropertyValue::WithIntValue(
                            bind_fuchsia_test::BIND_PROTOCOL_DEVICE))
                        .Build();

    auto args =
        fdf::wire::NodeAddArgs::Builder(arena)
            .name("leaf")
            .properties(fidl::VectorView<fdf::wire::NodeProperty>::FromExternal(&property, 1))
            .offers(fidl::VectorView<fcd::wire::Offer>::FromExternal(&offer, 1))
            .Build();

    // Create endpoints of the `NodeController` for the node.
    auto endpoints = fidl::CreateEndpoints<fdf::NodeController>();
    if (endpoints.is_error()) {
      return fpromise::make_error_promise(fdf::wire::NodeError::kInternal);
    }

    return driver::AddChild(node_, std::move(args), std::move(endpoints->server), {})
        .and_then([this, client = std::move(endpoints->client)]() mutable {
          controller_.Bind(std::move(client), dispatcher_);
        });
  }

  result<> UnbindNode(const fdf::wire::NodeError& error) {
    FDF_LOG(ERROR, "Failed to start root driver: %d", error);
    node_.AsyncTeardown();
    return ok();
  }

  async_dispatcher_t* const dispatcher_;
  async::Executor executor_;
  component::OutgoingDirectory outgoing_;
  fdf::UnownedDispatcher const fdf_dispatcher_;

  fidl::WireSharedClient<fdf::Node> node_;
  fidl::WireSharedClient<fdf::NodeController> controller_;
  driver::Namespace ns_;
  driver::Logger logger_;

  // NOTE: Must be the last member.
  fpromise::scope scope_;
};

}  // namespace

FUCHSIA_DRIVER_RECORD_CPP_V1(RootDriver);
