// Copyright 2023 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/devices/bin/driver_manager/bind/bind_manager.h"

#include <fidl/fuchsia.driver.framework/cpp/fidl.h>

#include "src/devices/bin/driver_manager/node_property_conversion.h"
#include "src/devices/lib/log/log.h"

namespace fdd = fuchsia_driver_development;
namespace fdi = fuchsia_driver_index;

namespace driver_manager {

BindManager::BindManager(BindManagerBridge* bridge, NodeManager* node_manager,
                         async_dispatcher_t* dispatcher)
    : bridge_(bridge) {
  bind_node_set_.set_on_bind_state_changed([bridge]() { bridge->OnBindingStateChanged(); });
}

void BindManager::TryBindAllAvailable(NodeBindingInfoResultCallback result_callback) {
  // If there's an ongoing process to bind all orphans, queue up this callback. Once
  // the process is complete, it'll make another attempt to bind all orphans and invoke
  // all callbacks in the list.
  if (bind_node_set_.is_bind_ongoing()) {
    pending_orphan_rebind_callbacks_.push_back(std::move(result_callback));
    return;
  }

  if (bind_node_set_.NumOfAvailableNodes() == 0) {
    result_callback(fidl::VectorView<fuchsia_driver_development::wire::NodeBindingInfo>());
    return;
  }

  bind_node_set_.StartNextBindProcess();

  // In case there is a pending call to TryBindAllAvailable() after this one, we automatically
  // restart the process and call all queued up callbacks upon completion.
  auto next_attempt =
      [this, result_callback = std::move(result_callback)](
          fidl::VectorView<fuchsia_driver_development::wire::NodeBindingInfo> results) mutable {
        result_callback(results);
        ProcessPendingBindRequests();
      };
  std::shared_ptr<BindResultTracker> tracker = std::make_shared<BindResultTracker>(
      bind_node_set_.NumOfAvailableNodes(), std::move(next_attempt));
  TryBindAllAvailableInternal(tracker);
}

void BindManager::Bind(Node& node, std::string_view driver_url_suffix,
                       std::shared_ptr<BindResultTracker> result_tracker) {
  BindRequest request = {
      .node_moniker = node.MakeComponentMoniker(),
      .node = node.weak_from_this(),
      .driver_url_suffix = std::string(driver_url_suffix),
      .tracker = result_tracker,
      .composite_only = false,
  };
  if (bind_node_set_.is_bind_ongoing()) {
    pending_bind_requests_.push_back(std::move(request));
    return;
  }

  // Remove the node from the orphaned nodes to avoid collision.
  bind_node_set_.RemoveOrphanedNode(node.MakeComponentMoniker());
  bind_node_set_.StartNextBindProcess();

  auto next_attempt = [this]() mutable { ProcessPendingBindRequests(); };
  BindInternal(std::move(request), next_attempt);
}

void BindManager::TryBindAllAvailableInternal(std::shared_ptr<BindResultTracker> tracker) {
  ZX_ASSERT(bind_node_set_.is_bind_ongoing());
  if (bind_node_set_.NumOfAvailableNodes() == 0) {
    return;
  }

  auto multibind_nodes = bind_node_set_.CurrentMultibindNodes();
  for (auto& [path, node_weak] : multibind_nodes) {
    std::shared_ptr node = node_weak.lock();
    if (!node) {
      tracker->ReportNoBind();
      continue;
    }

    BindInternal(BindRequest{
        .node_moniker = path,
        .node = node_weak,
        .tracker = tracker,
        .composite_only = true,
    });
  }

  std::unordered_map<std::string, std::weak_ptr<Node>> orphaned_nodes =
      bind_node_set_.CurrentOrphanedNodes();
  for (auto& [path, node] : orphaned_nodes) {
    BindInternal(BindRequest{
        .node_moniker = path,
        .node = node,
        .tracker = tracker,
        .composite_only = false,
    });
  }
}

void BindManager::BindInternal(BindRequest request,
                               BindMatchCompleteCallback match_complete_callback) {
  ZX_ASSERT(bind_node_set_.is_bind_ongoing());
  std::shared_ptr node = request.node.lock();
  if (!node) {
    fdf_log::warn("Node was freed before bind request is processed. {}", request.node_moniker);
    if (request.tracker) {
      request.tracker->ReportNoBind();
    }
    match_complete_callback();
    return;
  }

  std::string driver_url_suffix = request.driver_url_suffix;
  auto match_callback =
      [this, request = std::move(request),
       match_complete_callback = std::move(match_complete_callback)](
          fidl::WireUnownedResult<fdi::DriverIndex::MatchDriver>& result) mutable {
        OnMatchDriverCallback(std::move(request), result, std::move(match_complete_callback));
      };
  fidl::Arena arena;
  auto builder = fuchsia_driver_index::wire::MatchDriverArgs::Builder(arena).name(node->name());

  // Composite node's "default" node properties are its primary parent's node properties which
  // should not be used.
  if (node->type() == NodeType::kNormal) {
    if (std::optional props = node->GetNodeProperties(); props.has_value()) {
      builder.properties(fidl::ToWire(arena, props.value()));
    }
  }
  if (!driver_url_suffix.empty()) {
    builder.driver_url_suffix(driver_url_suffix);
  }
  bridge_->RequestMatchFromDriverIndex(builder.Build(), std::move(match_callback));
}

void BindManager::OnMatchDriverCallback(
    BindRequest request, fidl::WireUnownedResult<fdi::DriverIndex::MatchDriver>& result,
    BindMatchCompleteCallback match_complete_callback) {
  auto report_no_bind = fit::defer([&request, &match_complete_callback]() mutable {
    if (request.tracker) {
      request.tracker->ReportNoBind();
    }
    match_complete_callback();
  });

  std::shared_ptr node = request.node.lock();

  // TODO(https://fxbug.dev/42075939): Add an additional guard to ensure that the node is still
  // available for binding when the match callback is fired. Currently, there are no issues from it,
  // but it is something we should address.
  if (!node) {
    fdf_log::warn("Node {} was freed before it could be bound", request.node_moniker);
    return;
  }

  BindResult bind_result =
      BindNodeToResult(*node, request.composite_only, result, request.tracker != nullptr);

  auto node_moniker = node->MakeComponentMoniker();

  // If the node fails to bind to anything, add it to the orphaned nodes.
  if (!bind_result.bound() && !request.composite_only &&
      !bind_node_set_.MultibindContains(node_moniker)) {
    bind_node_set_.AddOrphanedNode(*node);
    return;
  }

  // Remove bound nodes from the orphaned nodes.
  bind_node_set_.RemoveOrphanedNode(node_moniker);

  if (bind_result.bound()) {
    report_no_bind.cancel();
    if (request.tracker) {
      if (bind_result.is_driver_url()) {
        request.tracker->ReportSuccessfulBind(node_moniker, bind_result.driver_url());
      } else if (bind_result.is_composite_parents()) {
        request.tracker->ReportSuccessfulBind(node_moniker, bind_result.composite_parents());
      } else {
        fdf_log::error("Unknown bind result type for {}.", node_moniker);
      }
    }

    match_complete_callback();
  }
}

BindResult BindManager::BindNodeToResult(
    Node& node, bool composite_only, fidl::WireUnownedResult<fdi::DriverIndex::MatchDriver>& result,
    bool has_tracker) {
  if (!result.ok()) {
    fdf_log::error("Failed to call match Node '{}': {}", node.name(), result.error());
    return BindResult();
  }

  if (result->is_error()) {
    // Log the failed MatchDriver only if we are not tracking the results with a tracker
    // or if the error is not a ZX_ERR_NOT_FOUND error (meaning it could not find a driver).
    // When we have a tracker, the bind is happening for all the orphan nodes and the
    // not found errors get very noisy.
    zx_status_t match_error = result->error_value();
    if (match_error != ZX_ERR_NOT_FOUND && !has_tracker) {
      fdf_log::warn("Failed to match Node '{}': {}", node.MakeTopologicalPath(),
                    zx_status_get_string(match_error));
    }

    return BindResult();
  }

  auto& matched_driver = result->value();
  if (composite_only && !matched_driver->is_composite_parents()) {
    return BindResult();
  }

  if (!matched_driver->is_driver() && !matched_driver->is_composite_parents()) {
    fdf_log::warn(
        "Failed to match Node '{}', the MatchedDriver is not a normal driver or a "
        "parent spec.",
        node.name());
    return BindResult();
  }

  if (matched_driver->is_composite_parents()) {
    fidl::Arena arena;
    auto result = BindNodeToSpec(arena, node, matched_driver->composite_parents());
    if (!result.is_ok()) {
      return BindResult();
    }

    auto owned_result = fidl::ToNatural(result.value());
    ZX_ASSERT(owned_result.has_value());
    return BindResult(owned_result.value());
  }

  ZX_ASSERT(matched_driver->is_driver());

  // If the node is already part of a composite, it should not bind to a driver.
  if (bind_node_set_.MultibindContains(node.MakeComponentMoniker())) {
    return BindResult();
  }

  auto start_result = bridge_->StartDriver(node, matched_driver->driver());
  if (start_result.is_error()) {
    fdf_log::error("Failed to start driver '{}': {}", node.name(),
                   zx_status_get_string(start_result.error_value()));
    return BindResult();
  }

  return BindResult(start_result.value());
}

zx::result<CompositeParents> BindManager::BindNodeToSpec(fidl::AnyArena& arena, Node& node,
                                                         CompositeParents parents) {
  if (node.can_multibind_composites()) {
    bind_node_set_.AddOrMoveMultibindNode(node);
  }

  auto result = bridge_->BindToParentSpec(arena, parents, node.weak_from_this(),
                                          node.can_multibind_composites());
  if (result.is_error()) {
    if (result.error_value() != ZX_ERR_NOT_FOUND) {
      fdf_log::error("Failed to bind node '{}' to any of the matched parent specs.", node.name());
    }

    node.OnMatchError(result.error_value());
    return result.take_error();
  }

  for (auto& composite : result.value().completed_node_and_drivers) {
    std::shared_ptr composite_node = composite.node.lock();
    ZX_ASSERT(composite_node);
    auto start_result = bridge_->StartDriver(*composite_node, composite.driver.driver_info());
    if (start_result.is_error()) {
      fdf_log::error("Failed to start driver '{}': {}", node.name(),
                     zx_status_get_string(start_result.error_value()));
    }
  }

  return zx::ok(result.value().bound_composite_parents);
}

void BindManager::ProcessPendingBindRequests() {
  ZX_ASSERT(bind_node_set_.is_bind_ongoing());
  if (pending_bind_requests_.empty() && pending_orphan_rebind_callbacks_.empty()) {
    bind_node_set_.EndBindProcess();
    return;
  }

  // Consolidate the pending bind requests and orphaned nodes to prevent collisions.
  for (auto& request : pending_bind_requests_) {
    if (auto node = request.node.lock(); node) {
      bind_node_set_.RemoveOrphanedNode(node->MakeComponentMoniker());
    }
  }

  // Begin the next bind process.
  bind_node_set_.StartNextBindProcess();

  bool have_bind_all_orphans_request = !pending_orphan_rebind_callbacks_.empty();
  size_t bind_tracker_size =
      have_bind_all_orphans_request
          ? pending_bind_requests_.size() + bind_node_set_.NumOfAvailableNodes()
          : pending_bind_requests_.size();

  // If there are no nodes to bind, then we'll run through all the callbacks and end the bind
  // process.
  if (have_bind_all_orphans_request && bind_tracker_size == 0) {
    for (auto& callback : pending_orphan_rebind_callbacks_) {
      fidl::Arena arena;
      callback(fidl::VectorView<fuchsia_driver_development::wire::NodeBindingInfo>(arena, 0));
    }
    pending_orphan_rebind_callbacks_.clear();
    bind_node_set_.EndBindProcess();
    return;
  }

  // Follow up with another ProcessPendingBindRequests() after all the pending bind calls are
  // complete. If there are no more accumulated bind calls, then the bind process ends.
  auto next_attempt =
      [this, callbacks = std::move(pending_orphan_rebind_callbacks_)](
          fidl::VectorView<fuchsia_driver_development::wire::NodeBindingInfo> results) mutable {
        for (auto& callback : callbacks) {
          callback(results);
        }
        ProcessPendingBindRequests();
      };

  std::shared_ptr<BindResultTracker> tracker =
      std::make_shared<BindResultTracker>(bind_tracker_size, std::move(next_attempt));

  // Go through all the pending bind requests.
  std::vector<BindRequest> pending_bind = std::move(pending_bind_requests_);
  for (auto& request : pending_bind) {
    auto match_complete_callback = [tracker]() mutable {
      // The bind status doesn't matter for this tracker.
      tracker->ReportNoBind();
    };
    BindInternal(std::move(request), std::move(match_complete_callback));
  }

  // If there are any pending callbacks for TryBindAllAvailable(), begin a new attempt.
  if (have_bind_all_orphans_request) {
    TryBindAllAvailableInternal(tracker);
  }
}

void BindManager::RecordInspect(inspect::Inspector& inspector) const {
  auto orphans = inspector.GetRoot().CreateChild("orphan_nodes");
  for (auto& [moniker, node] : bind_node_set_.CurrentOrphanedNodes()) {
    if (std::shared_ptr locked_node = node.lock()) {
      auto orphan = orphans.CreateChild(orphans.UniqueName("orphan-"));
      orphan.RecordString("moniker", moniker);
      orphans.Record(std::move(orphan));
    }
  }

  orphans.RecordBool("bind_all_ongoing", bind_node_set_.is_bind_ongoing());
  orphans.RecordUint("pending_bind_requests", pending_bind_requests_.size());
  orphans.RecordUint("pending_orphan_rebind_callbacks", pending_orphan_rebind_callbacks_.size());
  inspector.GetRoot().Record(std::move(orphans));
}

std::vector<fdd::wire::CompositeNodeInfo> BindManager::GetCompositeListInfo(
    fidl::AnyArena& arena) const {
  // TODO(https://fxbug.dev/42071016): Add composite node specs to the list.
  return {};
}

}  // namespace driver_manager
