// Copyright 2018 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 "bredr_connection_manager.h"

#include <lib/async/time.h>
#include <zircon/assert.h>

#include "src/connectivity/bluetooth/core/bt-host/common/expiring_set.h"
#include "src/connectivity/bluetooth/core/bt-host/common/log.h"
#include "src/connectivity/bluetooth/core/bt-host/gap/bredr_connection.h"
#include "src/connectivity/bluetooth/core/bt-host/gap/peer_cache.h"
#include "src/connectivity/bluetooth/core/bt-host/hci-spec/constants.h"
#include "src/connectivity/bluetooth/core/bt-host/hci-spec/protocol.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/bredr_connection.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/sequential_command_runner.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/l2cap_defs.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/types.h"
#include "src/connectivity/bluetooth/core/bt-host/transport/error.h"
#include "src/connectivity/bluetooth/core/bt-host/transport/transport.h"

namespace bt::gap {

using std::unique_ptr;
using ConnectionState = Peer::ConnectionState;

namespace {

const char* const kInspectRequestsNodeName = "connection_requests";
const char* const kInspectRequestNodeNamePrefix = "request_";
const char* const kInspectConnectionsNodeName = "connections";
const char* const kInspectConnectionNodeNamePrefix = "connection_";
const char* const kInspectLastDisconnectedListName = "last_disconnected";
const char* const kInspectLastDisconnectedItemDurationPropertyName = "duration_s";
const char* const kInspectLastDisconnectedItemPeerPropertyName = "peer_id";
const char* const kInspectTimestampPropertyName = "@time";
const char* const kInspectOutgoingNodeName = "outgoing";
const char* const kInspectIncomingNodeName = "incoming";
const char* const kInspectConnectionAttemptsNodeName = "connection_attempts";
const char* const kInspectSuccessfulConnectionsNodeName = "successful_connections";
const char* const kInspectFailedConnectionsNodeName = "failed_connections";
const char* const kInspectInterrogationCompleteCountNodeName = "interrogation_complete_count";
const char* const kInspectLocalApiRequestCountNodeName = "disconnect_local_api_request_count";
const char* const kInspectInterrogationFailedCountNodeName =
    "disconnect_interrogation_failed_count";
const char* const kInspectPairingFailedCountNodeName = "disconnect_pairing_failed_count";
const char* const kInspectAclLinkErrorCountNodeName = "disconnect_acl_link_error_count";
const char* const kInspectPeerDisconnectionCountNodeName = "disconnect_peer_disconnection_count";

std::string ReasonAsString(DisconnectReason reason) {
  switch (reason) {
    case DisconnectReason::kApiRequest:
      return "ApiRequest";
    case DisconnectReason::kInterrogationFailed:
      return "InterrogationFailed";
    case DisconnectReason::kPairingFailed:
      return "PairingFailed";
    case DisconnectReason::kAclLinkError:
      return "AclLinkError";
    case DisconnectReason::kPeerDisconnection:
      return "PeerDisconnection";
    default:
      return "<Unknown Reason>";
  }
}

// This procedure can continue to operate independently of the existence of an
// BrEdrConnectionManager instance, which will begin to disable Page Scan as it shuts down.
void SetPageScanEnabled(bool enabled, fxl::WeakPtr<hci::Transport> hci,
                        async_dispatcher_t* dispatcher, hci::ResultFunction<> cb) {
  ZX_DEBUG_ASSERT(cb);
  auto read_enable = hci::CommandPacket::New(hci_spec::kReadScanEnable);
  auto finish_enable_cb = [enabled, hci, finish_cb = std::move(cb)](
                              auto, const hci::EventPacket& event) mutable {
    if (hci_is_error(event, WARN, "gap-bredr", "read scan enable failed")) {
      finish_cb(event.ToResult());
      return;
    }

    auto params = event.return_params<hci_spec::ReadScanEnableReturnParams>();
    uint8_t scan_type = params->scan_enable;
    if (enabled) {
      scan_type |= static_cast<uint8_t>(hci_spec::ScanEnableBit::kPage);
    } else {
      scan_type &= ~static_cast<uint8_t>(hci_spec::ScanEnableBit::kPage);
    }
    auto write_enable = hci::CommandPacket::New(hci_spec::kWriteScanEnable,
                                                sizeof(hci_spec::WriteScanEnableCommandParams));
    write_enable->mutable_payload<hci_spec::WriteScanEnableCommandParams>()->scan_enable =
        scan_type;
    hci->command_channel()->SendCommand(
        std::move(write_enable),
        [cb = std::move(finish_cb)](auto, const hci::EventPacket& event) { cb(event.ToResult()); });
  };
  hci->command_channel()->SendCommand(std::move(read_enable), std::move(finish_enable_cb));
}

}  // namespace

// An event signifying that a connection was completed by the controller
BrEdrConnectionManager::ConnectionComplete::ConnectionComplete(const hci::EventPacket& event) {
  ZX_ASSERT(event.event_code() == hci_spec::kConnectionCompleteEventCode);
  const auto& params = event.params<hci_spec::ConnectionCompleteEventParams>();
  handle = letoh16(params.connection_handle);
  addr = DeviceAddress(DeviceAddress::Type::kBREDR, params.bd_addr);
  status_code = params.status;
  link_type = params.link_type;
}

// An event signifying that an incoming connection is being requested by a peer
BrEdrConnectionManager::ConnectionRequestEvent::ConnectionRequestEvent(
    const hci::EventPacket& event) {
  ZX_ASSERT(event.event_code() == hci_spec::kConnectionRequestEventCode);
  const auto& params = event.params<hci_spec::ConnectionRequestEventParams>();
  addr = DeviceAddress(DeviceAddress::Type::kBREDR, params.bd_addr);
  link_type = params.link_type;
  class_of_device = params.class_of_device;
}

hci::CommandChannel::EventHandlerId BrEdrConnectionManager::AddEventHandler(
    const hci_spec::EventCode& code, hci::CommandChannel::EventCallback cb) {
  auto self = weak_ptr_factory_.GetWeakPtr();
  auto event_id = hci_->command_channel()->AddEventHandler(
      code, [self, callback = std::move(cb)](const auto& event) {
        if (self) {
          return callback(event);
        }
        return hci::CommandChannel::EventCallbackResult::kRemove;
      });
  ZX_DEBUG_ASSERT(event_id);
  event_handler_ids_.push_back(event_id);
  return event_id;
}

BrEdrConnectionManager::BrEdrConnectionManager(fxl::WeakPtr<hci::Transport> hci,
                                               PeerCache* peer_cache, DeviceAddress local_address,
                                               l2cap::ChannelManager* l2cap,
                                               bool use_interlaced_scan)
    : hci_(std::move(hci)),
      cache_(peer_cache),
      local_address_(local_address),
      l2cap_(l2cap),
      page_scan_interval_(0),
      page_scan_window_(0),
      use_interlaced_scan_(use_interlaced_scan),
      request_timeout_(kBrEdrCreateConnectionTimeout),
      dispatcher_(async_get_default_dispatcher()),
      weak_ptr_factory_(this) {
  ZX_DEBUG_ASSERT(hci_);
  ZX_DEBUG_ASSERT(cache_);
  ZX_DEBUG_ASSERT(l2cap_);
  ZX_DEBUG_ASSERT(dispatcher_);

  hci_cmd_runner_ = std::make_unique<hci::SequentialCommandRunner>(hci_);

  // Register event handlers
  AddEventHandler(hci_spec::kAuthenticationCompleteEventCode,
                  fit::bind_member<&BrEdrConnectionManager::OnAuthenticationComplete>(this));
  AddEventHandler(hci_spec::kConnectionCompleteEventCode, [this](const hci::EventPacket& event) {
    OnConnectionComplete(ConnectionComplete(event));
    return hci::CommandChannel::EventCallbackResult::kContinue;
  });
  AddEventHandler(hci_spec::kConnectionRequestEventCode, [this](const hci::EventPacket& event) {
    OnConnectionRequest(ConnectionRequestEvent(event));
    return hci::CommandChannel::EventCallbackResult::kContinue;
  });
  AddEventHandler(hci_spec::kIOCapabilityRequestEventCode,
                  fit::bind_member<&BrEdrConnectionManager::OnIoCapabilityRequest>(this));
  AddEventHandler(hci_spec::kIOCapabilityResponseEventCode,
                  fit::bind_member<&BrEdrConnectionManager::OnIoCapabilityResponse>(this));
  AddEventHandler(hci_spec::kLinkKeyRequestEventCode,
                  fit::bind_member<&BrEdrConnectionManager::OnLinkKeyRequest>(this));
  AddEventHandler(hci_spec::kLinkKeyNotificationEventCode,
                  fit::bind_member<&BrEdrConnectionManager::OnLinkKeyNotification>(this));
  AddEventHandler(hci_spec::kSimplePairingCompleteEventCode,
                  fit::bind_member<&BrEdrConnectionManager::OnSimplePairingComplete>(this));
  AddEventHandler(hci_spec::kUserConfirmationRequestEventCode,
                  fit::bind_member<&BrEdrConnectionManager::OnUserConfirmationRequest>(this));
  AddEventHandler(hci_spec::kUserPasskeyRequestEventCode,
                  fit::bind_member<&BrEdrConnectionManager::OnUserPasskeyRequest>(this));
  AddEventHandler(hci_spec::kUserPasskeyNotificationEventCode,
                  fit::bind_member<&BrEdrConnectionManager::OnUserPasskeyNotification>(this));
  AddEventHandler(hci_spec::kRoleChangeEventCode,
                  fit::bind_member<&BrEdrConnectionManager::OnRoleChange>(this));

  // Set the timeout for outbound connections explicitly to the spec default.
  WritePageTimeout(hci_spec::kDefaultPageTimeoutDuration, [](const hci::Result<> status) {
    [[maybe_unused]] bool _ = bt_is_error(status, WARN, "gap-bredr", "write page timeout failed");
  });
}

BrEdrConnectionManager::~BrEdrConnectionManager() {
  // Disconnect any connections that we're holding.
  connections_.clear();

  if (!hci_ || !hci_->command_channel()) {
    return;
  }

  if (pending_request_ && pending_request_->Cancel())
    SendCreateConnectionCancelCommand(pending_request_->peer_address());

  // Become unconnectable
  SetPageScanEnabled(/*enabled=*/false, hci_, dispatcher_, [](const auto) {});

  // Remove all event handlers
  for (auto handler_id : event_handler_ids_) {
    hci_->command_channel()->RemoveEventHandler(handler_id);
  }
}

void BrEdrConnectionManager::SetConnectable(bool connectable, hci::ResultFunction<> status_cb) {
  auto self = weak_ptr_factory_.GetWeakPtr();
  if (!connectable) {
    auto not_connectable_cb = [self, cb = std::move(status_cb)](const auto& status) {
      if (self) {
        self->page_scan_interval_ = 0;
        self->page_scan_window_ = 0;
      } else if (status.is_ok()) {
        cb(ToResult(HostError::kFailed));
        return;
      }
      cb(status);
    };
    SetPageScanEnabled(/*enabled=*/false, hci_, dispatcher_, std::move(not_connectable_cb));
    return;
  }

  WritePageScanSettings(
      hci_spec::kPageScanR1Interval, hci_spec::kPageScanR1Window, use_interlaced_scan_,
      [self, cb = std::move(status_cb)](const auto& status) mutable {
        if (bt_is_error(status, WARN, "gap-bredr", "Write Page Scan Settings failed")) {
          cb(status);
          return;
        }
        if (!self) {
          cb(ToResult(HostError::kFailed));
          return;
        }
        SetPageScanEnabled(/*enabled=*/true, self->hci_, self->dispatcher_, std::move(cb));
      });
}

void BrEdrConnectionManager::SetPairingDelegate(fxl::WeakPtr<PairingDelegate> delegate) {
  pairing_delegate_ = std::move(delegate);
  for (auto& [handle, connection] : connections_) {
    connection.pairing_state().SetPairingDelegate(pairing_delegate_);
  }
}

PeerId BrEdrConnectionManager::GetPeerId(hci_spec::ConnectionHandle handle) const {
  auto it = connections_.find(handle);
  if (it == connections_.end()) {
    return kInvalidPeerId;
  }

  auto* peer = cache_->FindByAddress(it->second.link().peer_address());
  ZX_DEBUG_ASSERT_MSG(peer, "Couldn't find peer for handle %#.4x", handle);
  return peer->identifier();
}

void BrEdrConnectionManager::Pair(PeerId peer_id, BrEdrSecurityRequirements security,
                                  hci::ResultFunction<> callback) {
  auto conn_pair = FindConnectionById(peer_id);
  if (!conn_pair) {
    bt_log(WARN, "gap-bredr", "can't pair to peer_id %s: connection not found", bt_str(peer_id));
    callback(ToResult(HostError::kNotFound));
    return;
  }
  auto& [handle, connection] = *conn_pair;
  auto pairing_callback = [pair_callback = std::move(callback)](auto, hci::Result<> status) {
    pair_callback(status);
  };
  connection->pairing_state().InitiatePairing(security, std::move(pairing_callback));
}

void BrEdrConnectionManager::OpenL2capChannel(PeerId peer_id, l2cap::PSM psm,
                                              BrEdrSecurityRequirements security_reqs,
                                              l2cap::ChannelParameters params,
                                              l2cap::ChannelCallback cb) {
  auto pairing_cb = [self = weak_ptr_factory_.GetWeakPtr(), peer_id, psm, params,
                     cb = std::move(cb)](auto status) mutable {
    bt_log(TRACE, "gap-bredr", "got pairing status %s, %sreturning socket to %s", bt_str(status),
           status.is_ok() ? "" : "not ", bt_str(peer_id));
    if (status.is_error() || !self) {
      // Report the failure to the user with a null channel.
      cb(nullptr);
      return;
    }

    auto conn_pair = self->FindConnectionById(peer_id);
    if (!conn_pair) {
      bt_log(INFO, "gap-bredr", "can't open l2cap channel: connection not found (peer: %s)",
             bt_str(peer_id));
      cb(nullptr);
      return;
    }
    auto& [handle, connection] = *conn_pair;

    connection->OpenL2capChannel(psm, params,
                                 [cb = std::move(cb)](auto chan) { cb(std::move(chan)); });
  };

  Pair(peer_id, security_reqs, std::move(pairing_cb));
}

BrEdrConnectionManager::SearchId BrEdrConnectionManager::AddServiceSearch(
    const UUID& uuid, std::unordered_set<sdp::AttributeId> attributes,
    BrEdrConnectionManager::SearchCallback callback) {
  auto on_service_discovered = [self = weak_ptr_factory_.GetWeakPtr(), uuid,
                                client_cb = std::move(callback)](PeerId peer_id, auto& attributes) {
    if (self) {
      Peer* const peer = self->cache_->FindById(peer_id);
      ZX_ASSERT(peer);
      peer->MutBrEdr().AddService(uuid);
    }
    client_cb(peer_id, attributes);
  };
  return discoverer_.AddSearch(uuid, std::move(attributes), std::move(on_service_discovered));
}

bool BrEdrConnectionManager::RemoveServiceSearch(SearchId id) {
  return discoverer_.RemoveSearch(id);
}

std::optional<BrEdrConnectionManager::ScoRequestHandle> BrEdrConnectionManager::OpenScoConnection(
    PeerId peer_id, hci_spec::SynchronousConnectionParameters parameters,
    sco::ScoConnectionManager::OpenConnectionCallback callback) {
  auto conn_pair = FindConnectionById(peer_id);
  if (!conn_pair) {
    bt_log(WARN, "gap-bredr", "Can't open SCO connection to unconnected peer (peer: %s)",
           bt_str(peer_id));
    callback(fitx::error(HostError::kNotFound));
    return std::nullopt;
  };
  return conn_pair->second->OpenScoConnection(parameters, std::move(callback));
}

std::optional<BrEdrConnectionManager::ScoRequestHandle> BrEdrConnectionManager::AcceptScoConnection(
    PeerId peer_id, std::vector<hci_spec::SynchronousConnectionParameters> parameters,
    sco::ScoConnectionManager::AcceptConnectionCallback callback) {
  auto conn_pair = FindConnectionById(peer_id);
  if (!conn_pair) {
    bt_log(WARN, "gap-bredr", "Can't accept SCO connection from unconnected peer (peer: %s)",
           bt_str(peer_id));
    callback(fitx::error(HostError::kNotFound));
    return std::nullopt;
  };
  return conn_pair->second->AcceptScoConnection(std::move(parameters), std::move(callback));
}

bool BrEdrConnectionManager::Disconnect(PeerId peer_id, DisconnectReason reason) {
  bt_log_scope("peer: %s", bt_str(peer_id));
  bt_log(INFO, "gap-bredr", "Disconnect Requested (reason %hhu - %s)", reason,
         ReasonAsString(reason).c_str());

  // TODO(fxbug.dev/65157) - If a disconnect request is received when we have a pending connection,
  // we should instead abort the connection, by either:
  //   * removing the request if it has not yet been processed
  //   * sending a cancel command to the controller and waiting for it to be processed
  //   * sending a cancel command, and if we already complete, then beginning a disconnect procedure
  if (connection_requests_.find(peer_id) != connection_requests_.end()) {
    bt_log(WARN, "gap-bredr", "Can't disconnect because it's being connected to");
    return false;
  }

  auto conn_pair = FindConnectionById(peer_id);
  if (!conn_pair) {
    bt_log(INFO, "gap-bredr", "No need to disconnect: It is not connected");
    return true;
  }

  auto [handle, connection] = *conn_pair;

  const DeviceAddress& peer_addr = connection->link().peer_address();
  bt_log_scope("addr: %s", bt_str(peer_addr));
  if (reason == DisconnectReason::kApiRequest) {
    bt_log(DEBUG, "gap-bredr", "requested disconnect from peer, cooldown for %lds",
           kLocalDisconnectCooldownDuration.to_secs());
    deny_incoming_.add_until(
        peer_addr, async::Now(async_get_default_dispatcher()) + kLocalDisconnectCooldownDuration);
  }

  CleanUpConnection(handle, std::move(connections_.extract(handle).mapped()), reason);
  return true;
}

void BrEdrConnectionManager::AttachInspect(inspect::Node& parent, std::string name) {
  inspect_node_ = parent.CreateChild(name);

  inspect_properties_.connections_node_ = inspect_node_.CreateChild(kInspectConnectionsNodeName);
  inspect_properties_.last_disconnected_list.AttachInspect(inspect_node_,
                                                           kInspectLastDisconnectedListName);

  inspect_properties_.requests_node_ = inspect_node_.CreateChild(kInspectRequestsNodeName);
  for (auto& [_, req] : connection_requests_) {
    req.AttachInspect(inspect_properties_.requests_node_,
                      inspect_properties_.requests_node_.UniqueName(kInspectRequestNodeNamePrefix));
  }

  inspect_properties_.outgoing_.node_ = inspect_node_.CreateChild(kInspectOutgoingNodeName);
  inspect_properties_.outgoing_.connection_attempts_.AttachInspect(
      inspect_properties_.outgoing_.node_, kInspectConnectionAttemptsNodeName);
  inspect_properties_.outgoing_.successful_connections_.AttachInspect(
      inspect_properties_.outgoing_.node_, kInspectSuccessfulConnectionsNodeName);
  inspect_properties_.outgoing_.failed_connections_.AttachInspect(
      inspect_properties_.outgoing_.node_, kInspectFailedConnectionsNodeName);

  inspect_properties_.incoming_.node_ = inspect_node_.CreateChild(kInspectIncomingNodeName);
  inspect_properties_.incoming_.connection_attempts_.AttachInspect(
      inspect_properties_.incoming_.node_, kInspectConnectionAttemptsNodeName);
  inspect_properties_.incoming_.successful_connections_.AttachInspect(
      inspect_properties_.incoming_.node_, kInspectSuccessfulConnectionsNodeName);
  inspect_properties_.incoming_.failed_connections_.AttachInspect(
      inspect_properties_.incoming_.node_, kInspectFailedConnectionsNodeName);

  inspect_properties_.interrogation_complete_count_.AttachInspect(
      inspect_node_, kInspectInterrogationCompleteCountNodeName);

  inspect_properties_.disconnect_local_api_request_count_.AttachInspect(
      inspect_node_, kInspectLocalApiRequestCountNodeName);
  inspect_properties_.disconnect_interrogation_failed_count_.AttachInspect(
      inspect_node_, kInspectInterrogationFailedCountNodeName);
  inspect_properties_.disconnect_pairing_failed_count_.AttachInspect(
      inspect_node_, kInspectPairingFailedCountNodeName);
  inspect_properties_.disconnect_acl_link_error_count_.AttachInspect(
      inspect_node_, kInspectAclLinkErrorCountNodeName);
  inspect_properties_.disconnect_peer_disconnection_count_.AttachInspect(
      inspect_node_, kInspectPeerDisconnectionCountNodeName);
}

void BrEdrConnectionManager::WritePageTimeout(zx::duration page_timeout, hci::ResultFunction<> cb) {
  ZX_ASSERT(page_timeout >= hci_spec::kMinPageTimeoutDuration);
  ZX_ASSERT(page_timeout <= hci_spec::kMaxPageTimeoutDuration);

  const int64_t raw_page_timeout = page_timeout / hci_spec::kDurationPerPageTimeoutUnit;
  ZX_ASSERT(raw_page_timeout >= hci_spec::kMinPageTimeoutCommandParameterValue);
  ZX_ASSERT(raw_page_timeout <= hci_spec::kMaxPageTimeoutCommandParameterValue);

  auto write_page_timeout_cmd = hci::CommandPacket::New(
      hci_spec::kWritePageTimeout, sizeof(hci_spec::WritePageTimeoutCommandParams));
  auto& params =
      *write_page_timeout_cmd->mutable_payload<hci_spec::WritePageTimeoutCommandParams>();
  params.page_timeout = static_cast<uint16_t>(raw_page_timeout);

  hci_->command_channel()->SendCommand(
      std::move(write_page_timeout_cmd),
      [cb = std::move(cb)](auto id, const hci::EventPacket& event) { cb(event.ToResult()); });
}

void BrEdrConnectionManager::WritePageScanSettings(uint16_t interval, uint16_t window,
                                                   bool interlaced, hci::ResultFunction<> cb) {
  auto self = weak_ptr_factory_.GetWeakPtr();
  if (!hci_cmd_runner_->IsReady()) {
    // TODO(jamuraa): could run the three "settings" commands in parallel and
    // remove the sequence runner.
    cb(ToResult(HostError::kInProgress));
    return;
  }

  auto write_activity = hci::CommandPacket::New(
      hci_spec::kWritePageScanActivity, sizeof(hci_spec::WritePageScanActivityCommandParams));
  auto* activity_params =
      write_activity->mutable_payload<hci_spec::WritePageScanActivityCommandParams>();
  activity_params->page_scan_interval = htole16(interval);
  activity_params->page_scan_window = htole16(window);

  hci_cmd_runner_->QueueCommand(
      std::move(write_activity), [self, interval, window](const hci::EventPacket& event) {
        if (!self || hci_is_error(event, WARN, "gap-bredr", "write page scan activity failed")) {
          return;
        }

        self->page_scan_interval_ = interval;
        self->page_scan_window_ = window;

        bt_log(TRACE, "gap-bredr", "page scan activity updated");
      });

  auto write_type = hci::CommandPacket::New(hci_spec::kWritePageScanType,
                                            sizeof(hci_spec::WritePageScanTypeCommandParams));
  auto* type_params = write_type->mutable_payload<hci_spec::WritePageScanTypeCommandParams>();
  type_params->page_scan_type = (interlaced ? hci_spec::PageScanType::kInterlacedScan
                                            : hci_spec::PageScanType::kStandardScan);

  hci_cmd_runner_->QueueCommand(
      std::move(write_type), [self, interlaced](const hci::EventPacket& event) {
        if (!self || hci_is_error(event, WARN, "gap-bredr", "write page scan type failed")) {
          return;
        }

        self->page_scan_type_ = (interlaced ? hci_spec::PageScanType::kInterlacedScan
                                            : hci_spec::PageScanType::kStandardScan);

        bt_log(TRACE, "gap-bredr", "page scan type updated");
      });

  hci_cmd_runner_->RunCommands(std::move(cb));
}

std::optional<std::pair<hci_spec::ConnectionHandle, BrEdrConnection*>>
BrEdrConnectionManager::FindConnectionById(PeerId peer_id) {
  auto it = std::find_if(connections_.begin(), connections_.end(),
                         [peer_id](const auto& c) { return c.second.peer_id() == peer_id; });

  if (it == connections_.end()) {
    return std::nullopt;
  }

  auto& [handle, conn] = *it;
  return std::pair(handle, &conn);
}

std::optional<std::pair<hci_spec::ConnectionHandle, BrEdrConnection*>>
BrEdrConnectionManager::FindConnectionByAddress(const DeviceAddressBytes& bd_addr) {
  auto* const peer = cache_->FindByAddress(DeviceAddress(DeviceAddress::Type::kBREDR, bd_addr));
  if (!peer) {
    return std::nullopt;
  }

  return FindConnectionById(peer->identifier());
}

Peer* BrEdrConnectionManager::FindOrInitPeer(DeviceAddress addr) {
  Peer* peer = cache_->FindByAddress(addr);
  if (!peer) {
    peer = cache_->NewPeer(addr, /*connectable*/ true);
  }
  return peer;
}

// Build connection state for a new connection and begin interrogation. L2CAP is not enabled for
// this link but pairing is allowed before interrogation completes.
void BrEdrConnectionManager::InitializeConnection(DeviceAddress addr,
                                                  hci_spec::ConnectionHandle connection_handle,
                                                  hci_spec::ConnectionRole role) {
  auto link =
      std::make_unique<hci::BrEdrConnection>(connection_handle, local_address_, addr, role, hci_);
  Peer* const peer = FindOrInitPeer(addr);
  auto peer_id = peer->identifier();
  bt_log(INFO, "gap-bredr", "Beginning interrogation for peer %s", bt_str(peer_id));

  // We should never have more than one link to a given peer
  ZX_DEBUG_ASSERT(!FindConnectionById(peer_id));

  // The controller has completed the HCI connection procedure, so the connection request can no
  // longer be failed by a lower layer error. Now tie error reporting of the request to the lifetime
  // of the connection state object (BrEdrConnection RAII).
  auto node = connection_requests_.extract(peer_id);
  auto request = node ? std::optional(std::move(node.mapped())) : std::nullopt;

  const hci_spec::ConnectionHandle handle = link->handle();
  auto send_auth_request_cb = [this, handle]() {
    this->SendAuthenticationRequested(handle, [handle](auto status) {
      bt_is_error(status, WARN, "gap-bredr", "authentication requested command failed for %#.4x",
                  handle);
    });
  };
  auto disconnect_cb = [this, peer_id] { Disconnect(peer_id, DisconnectReason::kPairingFailed); };
  auto on_peer_disconnect_cb = [this, link = link.get()] { OnPeerDisconnect(link); };
  auto [conn_iter, success] = connections_.try_emplace(
      handle, peer->GetWeakPtr(), std::move(link), std::move(send_auth_request_cb),
      std::move(disconnect_cb), std::move(on_peer_disconnect_cb), l2cap_, hci_, std::move(request));
  ZX_ASSERT(success);

  BrEdrConnection& connection = conn_iter->second;
  connection.pairing_state().SetPairingDelegate(pairing_delegate_);
  connection.AttachInspect(
      inspect_properties_.connections_node_,
      inspect_properties_.connections_node_.UniqueName(kInspectConnectionNodeNamePrefix));

  // Interrogate this peer to find out its version/capabilities.
  connection.Interrogate([this, peer = peer->GetWeakPtr(), handle](hci::Result<> result) {
    bt_log_scope("peer: %s, handle: %#.4x", bt_str(peer->identifier()), handle);
    if (bt_is_error(result, WARN, "gap-bredr", "interrogation failed, dropping connection")) {
      // If this connection was locally requested, requester(s) are notified by the disconnection.
      Disconnect(peer->identifier(), DisconnectReason::kInterrogationFailed);
      return;
    }
    bt_log(INFO, "gap-bredr", "interrogation complete");
    CompleteConnectionSetup(peer.get(), handle);
  });

  // If this was our in-flight request, close it
  if (pending_request_.has_value() && addr == pending_request_->peer_address()) {
    pending_request_.reset();
  }

  TryCreateNextConnection();
}

// Finish connection setup after a successful interrogation.
void BrEdrConnectionManager::CompleteConnectionSetup(Peer* peer,
                                                     hci_spec::ConnectionHandle handle) {
  auto self = weak_ptr_factory_.GetWeakPtr();

  bt_log_scope("peer: %s, handle: %#.4x", bt_str(peer->identifier()), handle);
  auto connections_iter = connections_.find(handle);
  if (connections_iter == connections_.end()) {
    bt_log(WARN, "gap-bredr", "Connection to complete not found");
    return;
  }
  BrEdrConnection& conn_state = connections_iter->second;
  if (conn_state.peer_id() != peer->identifier()) {
    bt_log(WARN, "gap-bredr",
           "Connection switched peers! (now to %s), ignoring interrogation result",
           bt_str(conn_state.peer_id()));
    return;
  }
  hci::BrEdrConnection* const connection = &conn_state.link();

  auto error_handler = [self, log_ctx = capture_log_context(), peer_id = peer->identifier(),
                        connection = connection->GetWeakPtr()] {
    if (!self || !connection)
      return;
    add_parent_context(log_ctx);
    bt_log(WARN, "gap-bredr", "Link error received, closing connection");
    self->Disconnect(peer_id, DisconnectReason::kAclLinkError);
  };

  // TODO(fxbug.dev/37650): Implement this callback as a call to InitiatePairing().
  auto security_callback = [log_ctx = capture_log_context()](hci_spec::ConnectionHandle handle,
                                                             sm::SecurityLevel level, auto cb) {
    add_parent_context(log_ctx);
    bt_log(INFO, "gap-bredr", "Ignoring security upgrade request; not implemented");
    cb(ToResult(HostError::kNotSupported));
  };

  // Register with L2CAP to handle services on the ACL signaling channel.
  l2cap_->AddACLConnection(handle, connection->role(), error_handler, std::move(security_callback));

  // Remove from the denylist if we successfully connect.
  deny_incoming_.remove(peer->address());

  inspect_properties_.interrogation_complete_count_.Add(1);

  if (discoverer_.search_count()) {
    l2cap_->OpenL2capChannel(handle, l2cap::kSDP, l2cap::ChannelParameters(),
                             [self, peer_id = peer->identifier()](auto channel) {
                               if (!self)
                                 return;
                               if (!channel) {
                                 bt_log_scope("peer: %s", bt_str(peer_id));
                                 bt_log(ERROR, "gap", "failed to create l2cap channel for SDP");
                                 return;
                               }

                               auto client = sdp::Client::Create(std::move(channel));
                               self->discoverer_.StartServiceDiscovery(peer_id, std::move(client));
                             });
  }

  conn_state.OnInterrogationComplete();
}

hci::CommandChannel::EventCallbackResult BrEdrConnectionManager::OnAuthenticationComplete(
    const hci::EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == hci_spec::kAuthenticationCompleteEventCode);
  const auto& params = event.params<hci_spec::AuthenticationCompleteEventParams>();
  auto connection_handle = params.connection_handle;

  auto iter = connections_.find(connection_handle);
  if (iter == connections_.end()) {
    bt_log(INFO, "gap-bredr",
           "ignoring authentication complete (status: %s) for unknown connection handle %#.04x",
           bt_str(ToResult(params.status)), connection_handle);
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }

  hci_spec::StatusCode status_code;
  event.ToStatusCode(&status_code);
  iter->second.pairing_state().OnAuthenticationComplete(status_code);
  return hci::CommandChannel::EventCallbackResult::kContinue;
}

bool BrEdrConnectionManager::ExistsIncomingRequest(PeerId id) {
  auto request = connection_requests_.find(id);
  return (request != connection_requests_.end() && request->second.HasIncoming());
}

void BrEdrConnectionManager::OnConnectionRequest(ConnectionRequestEvent event) {
  if (deny_incoming_.contains(event.addr)) {
    bt_log(INFO, "gap-bredr", "rejecting incoming from peer (addr: %s) on cooldown",
           bt_str(event.addr));
    SendRejectConnectionRequest(event.addr, hci_spec::StatusCode::kConnectionRejectedBadBdAddr);
    return;
  }
  // Initialize the peer if it doesn't exist, to ensure we have allocated a PeerId
  auto peer = FindOrInitPeer(event.addr);
  auto peer_id = peer->identifier();
  bt_log_scope("peer: %s, addr: %s, link_type: %s, class: %s", bt_str(peer_id), bt_str(event.addr),
               hci_spec::LinkTypeToString(event.link_type).c_str(), bt_str(event.class_of_device));

  // In case of concurrent incoming requests from the same peer, reject all but the first
  if (ExistsIncomingRequest(peer_id)) {
    bt_log(WARN, "gap-bredr", "rejecting duplicate incoming connection request");
    SendRejectConnectionRequest(event.addr, hci_spec::StatusCode::kConnectionRejectedBadBdAddr);
    return;
  }

  if (event.link_type == hci_spec::LinkType::kACL) {
    // If we happen to be already connected (for example, if our outgoing raced, or we received
    // duplicate requests), we reject the request with 'ConnectionAlreadyExists'
    if (FindConnectionById(peer_id)) {
      bt_log(WARN, "gap-bredr", "rejecting incoming connection request; already connected");
      SendRejectConnectionRequest(event.addr, hci_spec::StatusCode::kConnectionAlreadyExists);
      return;
    }

    // Accept the connection, performing a role switch. We receive a Connection Complete event
    // when the connection is complete, and finish the link then.
    bt_log(INFO, "gap-bredr", "accepting incoming connection");

    // Register that we're in the middle of an incoming request for this peer - create a new
    // request if one doesn't already exist
    auto [request, _ignore] = connection_requests_.try_emplace(
        peer_id, event.addr, peer_id, peer->MutBrEdr().RegisterInitializingConnection());

    inspect_properties_.incoming_.connection_attempts_.Add(1);

    request->second.BeginIncoming();
    request->second.AttachInspect(
        inspect_properties_.requests_node_,
        inspect_properties_.requests_node_.UniqueName(kInspectRequestNodeNamePrefix));

    SendAcceptConnectionRequest(
        event.addr.value(),
        [addr = event.addr, self = weak_ptr_factory_.GetWeakPtr(), peer_id](auto status) {
          if (self && status.is_error())
            self->CompleteRequest(peer_id, addr, status, /*handle=*/0);
        });

    return;
  }

  if (event.link_type == hci_spec::LinkType::kSCO ||
      event.link_type == hci_spec::LinkType::kExtendedSCO) {
    auto conn_pair = FindConnectionByAddress(event.addr.value());
    if (conn_pair) {
      // The ScoConnectionManager owned by the BrEdrConnection will respond.
      bt_log(INFO, "gap-bredr", "delegating incoming SCO connection to ScoConnectionManager");
      return;
    }
    bt_log(WARN, "gap-bredr", "rejecting (e)SCO connection request for peer that is not connected");
    SendRejectSynchronousRequest(event.addr,
                                 hci_spec::StatusCode::kUnacceptableConnectionParameters);
  } else {
    auto link_type = static_cast<unsigned int>(event.link_type);
    bt_log(WARN, "gap-bredr", "reject unsupported connection type %u", link_type);
    SendRejectConnectionRequest(event.addr, hci_spec::StatusCode::kUnsupportedFeatureOrParameter);
  }
}

void BrEdrConnectionManager::OnConnectionComplete(ConnectionComplete event) {
  if (event.link_type != hci_spec::LinkType::kACL) {
    // Only ACL links are processed
    return;
  }

  // Initialize the peer if it doesn't exist, to ensure we have allocated a PeerId (we should
  // usually have a peer by this point)
  auto peer = FindOrInitPeer(event.addr);

  CompleteRequest(peer->identifier(), event.addr, event.ToResult(), event.handle);
}

// A request for a connection - from an upstream client _or_ a remote peer - completed, successfully
// or not. This may be due to a ConnectionComplete event being received, or due to a CommandStatus
// response being received in response to a CreateConnection command
void BrEdrConnectionManager::CompleteRequest(PeerId peer_id, DeviceAddress address,
                                             hci::Result<> status,
                                             hci_spec::ConnectionHandle handle) {
  bt_log_scope("peer: %s, addr: %s, handle: %#.4x", bt_str(peer_id), bt_str(address), handle);

  auto req_iter = connection_requests_.find(peer_id);
  if (req_iter == connection_requests_.end()) {
    // Prevent logspam for rejected during cooldown.
    if (deny_incoming_.contains(address)) {
      return;
    }
    // This could potentially happen if the peer expired from the peer cache during the connection
    // procedure
    bt_log(INFO, "gap-bredr", "ConnectionComplete received with no known request (status: %s)",
           bt_str(status));
    return;
  }
  auto& request = req_iter->second;

  bool completes_outgoing_request =
      pending_request_.has_value() && pending_request_->peer_address() == address;
  bool failed = status.is_error();

  const char* direction = completes_outgoing_request ? "outgoing" : "incoming";
  const char* result = status.is_ok() ? "complete" : "error";
  hci_spec::ConnectionRole role = completes_outgoing_request
                                      ? hci_spec::ConnectionRole::kCentral
                                      : hci_spec::ConnectionRole::kPeripheral;
  if (request.role_change()) {
    role = request.role_change().value();
  }

  bt_log(INFO, "gap-bredr", "%s connection %s (status: %s, role: %s)", direction, result,
         bt_str(status), role == hci_spec::ConnectionRole::kCentral ? "leader" : "follower");

  if (completes_outgoing_request) {
    // Determine the modified status in case of cancellation or timeout
    status = pending_request_->CompleteRequest(status);
    pending_request_.reset();
  } else {
    // This incoming connection arrived while we're trying to make an outgoing connection; not an
    // impossible coincidence but log it in case it's interesting.
    // TODO(fxbug.dev/92299): Added to investigate timing and can be removed if it adds no value
    if (pending_request_.has_value()) {
      bt_log(INFO, "gap-bredr",
             "doesn't complete pending outgoing connection to peer %s (addr: %s)",
             bt_str(pending_request_->peer_id()), bt_str(pending_request_->peer_address()));
    }
    // If this was an incoming attempt, clear it
    request.CompleteIncoming();
  }

  if (failed) {
    if (request.HasIncoming() || (!completes_outgoing_request && request.AwaitingOutgoing())) {
      // This request failed, but we're still waiting on either:
      // * an in-progress incoming request or
      // * to attempt our own outgoing request
      // Therefore we don't notify yet - instead take no action, and wait until we finish those
      // steps before completing the request and notifying callbacks
      TryCreateNextConnection();
      return;
    }
    if (completes_outgoing_request && connection_requests_.size() == 1 &&
        request.ShouldRetry(status.error_value())) {
      bt_log(INFO, "gap-bredr",
             "no pending connection requests to other peers, so %sretrying outbound connection",
             request.HasIncoming() ? "waiting for inbound request completion before potentially "
                                   : "");
      // By not erasing |request| from |connection_requests_|, even if TryCreateNextConnection does
      // not directly retry because there's an inbound request to the same peer, the retry will
      // happen if the inbound request completes unusuccessfully.
      TryCreateNextConnection();
      return;
    }
    if (completes_outgoing_request) {
      inspect_properties_.outgoing_.failed_connections_.Add(1);
    } else if (request.HasIncoming()) {
      inspect_properties_.incoming_.failed_connections_.Add(1);
    }
    request.NotifyCallbacks(status, [] { return nullptr; });
    connection_requests_.erase(req_iter);
  } else {
    if (completes_outgoing_request) {
      inspect_properties_.outgoing_.successful_connections_.Add(1);
    } else if (request.HasIncoming()) {
      inspect_properties_.incoming_.successful_connections_.Add(1);
    }
    // Callbacks will be notified when interrogation completes
    InitializeConnection(address, handle, role);
  }

  TryCreateNextConnection();
}

void BrEdrConnectionManager::OnPeerDisconnect(const hci::Connection* connection) {
  auto handle = connection->handle();

  auto it = connections_.find(handle);
  if (it == connections_.end()) {
    bt_log(WARN, "gap-bredr", "disconnect from unknown connection handle %#.4x", handle);
    return;
  }

  auto conn = std::move(it->second);
  connections_.erase(it);

  bt_log(INFO, "gap-bredr", "peer disconnected (peer: %s, handle: %#.4x)", bt_str(conn.peer_id()),
         handle);
  CleanUpConnection(handle, std::move(conn), DisconnectReason::kPeerDisconnection);
}

void BrEdrConnectionManager::CleanUpConnection(hci_spec::ConnectionHandle handle,
                                               BrEdrConnection conn, DisconnectReason reason) {
  l2cap_->RemoveConnection(handle);
  RecordDisconnectInspect(conn, reason);
  // |conn| is destroyed when it goes out of scope.
}

hci::CommandChannel::EventCallbackResult BrEdrConnectionManager::OnIoCapabilityRequest(
    const hci::EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == hci_spec::kIOCapabilityRequestEventCode);
  const auto& params = event.params<hci_spec::IOCapabilityRequestEventParams>();

  auto conn_pair = FindConnectionByAddress(params.bd_addr);
  if (!conn_pair) {
    bt_log(ERROR, "gap-bredr", "got %s for unconnected addr %s", __func__, bt_str(params.bd_addr));
    SendIoCapabilityRequestNegativeReply(params.bd_addr, hci_spec::StatusCode::kPairingNotAllowed);
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }
  auto [handle, conn_ptr] = *conn_pair;
  auto reply = conn_ptr->pairing_state().OnIoCapabilityRequest();

  if (!reply) {
    SendIoCapabilityRequestNegativeReply(params.bd_addr, hci_spec::StatusCode::kPairingNotAllowed);
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }

  const hci_spec::IOCapability io_capability = *reply;

  // TODO(fxbug.dev/601): Add OOB status from PeerCache.
  const uint8_t oob_data_present = 0x00;  // None present.

  // TODO(fxbug.dev/1249): Determine this based on the service requirements.
  const hci_spec::AuthRequirements auth_requirements =
      io_capability == hci_spec::IOCapability::kNoInputNoOutput
          ? hci_spec::AuthRequirements::kGeneralBonding
          : hci_spec::AuthRequirements::kMITMGeneralBonding;

  SendIoCapabilityRequestReply(params.bd_addr, io_capability, oob_data_present, auth_requirements);
  return hci::CommandChannel::EventCallbackResult::kContinue;
}

hci::CommandChannel::EventCallbackResult BrEdrConnectionManager::OnIoCapabilityResponse(
    const hci::EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == hci_spec::kIOCapabilityResponseEventCode);
  const auto& params = event.params<hci_spec::IOCapabilityResponseEventParams>();

  auto conn_pair = FindConnectionByAddress(params.bd_addr);
  if (!conn_pair) {
    bt_log(INFO, "gap-bredr", "got %s for unconnected addr %s", __func__, bt_str(params.bd_addr));
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }
  conn_pair->second->pairing_state().OnIoCapabilityResponse(params.io_capability);
  return hci::CommandChannel::EventCallbackResult::kContinue;
}

hci::CommandChannel::EventCallbackResult BrEdrConnectionManager::OnLinkKeyRequest(
    const hci::EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == hci_spec::kLinkKeyRequestEventCode);
  const auto& params = event.params<hci_spec::LinkKeyRequestParams>();

  DeviceAddress addr(DeviceAddress::Type::kBREDR, params.bd_addr);
  auto* peer = cache_->FindByAddress(addr);
  if (!peer) {
    bt_log(WARN, "gap-bredr", "no peer with address %s found", bt_str(addr));
    SendLinkKeyRequestNegativeReply(params.bd_addr);
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }

  auto peer_id = peer->identifier();
  auto conn_pair = FindConnectionById(peer_id);

  if (!conn_pair) {
    bt_log(WARN, "gap-bredr", "can't find connection for ltk (id: %s)", bt_str(peer_id));
    SendLinkKeyRequestNegativeReply(params.bd_addr);
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }
  auto& [handle, conn] = *conn_pair;

  auto link_key = conn->pairing_state().OnLinkKeyRequest();
  if (!link_key.has_value()) {
    SendLinkKeyRequestNegativeReply(params.bd_addr);
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }

  SendLinkKeyRequestReply(params.bd_addr, link_key.value());
  return hci::CommandChannel::EventCallbackResult::kContinue;
}

hci::CommandChannel::EventCallbackResult BrEdrConnectionManager::OnLinkKeyNotification(
    const hci::EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == hci_spec::kLinkKeyNotificationEventCode);
  const auto& params = event.params<hci_spec::LinkKeyNotificationEventParams>();

  DeviceAddress addr(DeviceAddress::Type::kBREDR, params.bd_addr);

  auto* peer = cache_->FindByAddress(addr);
  if (!peer) {
    bt_log(WARN, "gap-bredr",
           "no known peer with address %s found; link key not stored (key type: %u)", bt_str(addr),
           params.key_type);
    cache_->LogBrEdrBondingEvent(false);
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }

  bt_log(INFO, "gap-bredr", "got link key notification (key type: %u, peer: %s)", params.key_type,
         bt_str(peer->identifier()));

  auto key_type = hci_spec::LinkKeyType{params.key_type};
  sm::SecurityProperties sec_props;
  if (key_type == hci_spec::LinkKeyType::kChangedCombination) {
    if (!peer->bredr() || !peer->bredr()->bonded()) {
      bt_log(WARN, "gap-bredr", "can't update link key of unbonded peer %s",
             bt_str(peer->identifier()));
      cache_->LogBrEdrBondingEvent(false);
      return hci::CommandChannel::EventCallbackResult::kContinue;
    }

    // Reuse current properties
    ZX_DEBUG_ASSERT(peer->bredr()->link_key());
    sec_props = peer->bredr()->link_key()->security();
    key_type = *sec_props.GetLinkKeyType();
  } else {
    sec_props = sm::SecurityProperties(key_type);
  }

  auto peer_id = peer->identifier();

  if (sec_props.level() == sm::SecurityLevel::kNoSecurity) {
    bt_log(WARN, "gap-bredr", "link key for peer %s has insufficient security; not stored",
           bt_str(peer_id));
    cache_->LogBrEdrBondingEvent(false);
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }

  UInt128 key_value;
  std::copy(params.link_key, &params.link_key[key_value.size()], key_value.begin());
  hci_spec::LinkKey hci_key(key_value, 0, 0);
  sm::LTK key(sec_props, hci_key);

  auto handle = FindConnectionById(peer_id);
  if (!handle) {
    bt_log(WARN, "gap-bredr", "can't find current connection for ltk (peer: %s)", bt_str(peer_id));
  } else {
    handle->second->link().set_link_key(hci_key, key_type);
    handle->second->pairing_state().OnLinkKeyNotification(key_value, key_type);
  }

  if (cache_->StoreBrEdrBond(addr, key)) {
    cache_->LogBrEdrBondingEvent(true);
  } else {
    cache_->LogBrEdrBondingEvent(false);
    bt_log(ERROR, "gap-bredr", "failed to cache bonding data (peer: %s)", bt_str(peer_id));
  }
  return hci::CommandChannel::EventCallbackResult::kContinue;
}

hci::CommandChannel::EventCallbackResult BrEdrConnectionManager::OnSimplePairingComplete(
    const hci::EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == hci_spec::kSimplePairingCompleteEventCode);
  const auto& params = event.params<hci_spec::SimplePairingCompleteEventParams>();

  auto conn_pair = FindConnectionByAddress(params.bd_addr);
  if (!conn_pair) {
    bt_log(WARN, "gap-bredr", "got Simple Pairing Complete (status: %s) for unconnected addr %s",
           bt_str(ToResult(params.status)), bt_str(params.bd_addr));
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }
  conn_pair->second->pairing_state().OnSimplePairingComplete(params.status);
  return hci::CommandChannel::EventCallbackResult::kContinue;
}

hci::CommandChannel::EventCallbackResult BrEdrConnectionManager::OnUserConfirmationRequest(
    const hci::EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == hci_spec::kUserConfirmationRequestEventCode);
  const auto& params = event.params<hci_spec::UserConfirmationRequestEventParams>();

  auto conn_pair = FindConnectionByAddress(params.bd_addr);
  if (!conn_pair) {
    bt_log(WARN, "gap-bredr", "got %s for unconnected addr %s", __func__, bt_str(params.bd_addr));
    SendUserConfirmationRequestNegativeReply(params.bd_addr);
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }

  auto confirm_cb = [this, self = weak_ptr_factory_.GetWeakPtr(),
                     bd_addr = params.bd_addr](bool confirm) {
    if (!self) {
      return;
    }

    if (confirm) {
      SendUserConfirmationRequestReply(bd_addr);
    } else {
      SendUserConfirmationRequestNegativeReply(bd_addr);
    }
  };
  conn_pair->second->pairing_state().OnUserConfirmationRequest(letoh32(params.numeric_value),
                                                               std::move(confirm_cb));
  return hci::CommandChannel::EventCallbackResult::kContinue;
}

hci::CommandChannel::EventCallbackResult BrEdrConnectionManager::OnUserPasskeyRequest(
    const hci::EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == hci_spec::kUserPasskeyRequestEventCode);
  const auto& params = event.params<hci_spec::UserPasskeyRequestEventParams>();

  auto conn_pair = FindConnectionByAddress(params.bd_addr);
  if (!conn_pair) {
    bt_log(WARN, "gap-bredr", "got %s for unconnected addr %s", __func__, bt_str(params.bd_addr));
    SendUserPasskeyRequestNegativeReply(params.bd_addr);
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }

  auto passkey_cb = [this, self = weak_ptr_factory_.GetWeakPtr(),
                     bd_addr = params.bd_addr](std::optional<uint32_t> passkey) {
    if (!self) {
      return;
    }

    if (passkey) {
      SendUserPasskeyRequestReply(bd_addr, *passkey);
    } else {
      SendUserPasskeyRequestNegativeReply(bd_addr);
    }
  };
  conn_pair->second->pairing_state().OnUserPasskeyRequest(std::move(passkey_cb));
  return hci::CommandChannel::EventCallbackResult::kContinue;
}

hci::CommandChannel::EventCallbackResult BrEdrConnectionManager::OnUserPasskeyNotification(
    const hci::EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == hci_spec::kUserPasskeyNotificationEventCode);
  const auto& params = event.params<hci_spec::UserPasskeyNotificationEventParams>();

  auto conn_pair = FindConnectionByAddress(params.bd_addr);
  if (!conn_pair) {
    bt_log(WARN, "gap-bredr", "got %s for unconnected addr %s", __func__, bt_str(params.bd_addr));
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }
  conn_pair->second->pairing_state().OnUserPasskeyNotification(letoh32(params.numeric_value));
  return hci::CommandChannel::EventCallbackResult::kContinue;
}

hci::CommandChannel::EventCallbackResult BrEdrConnectionManager::OnRoleChange(
    const hci::EventPacket& event) {
  ZX_ASSERT(event.event_code() == hci_spec::kRoleChangeEventCode);
  const auto& params = event.params<hci_spec::RoleChangeEventParams>();

  DeviceAddress address(DeviceAddress::Type::kBREDR, params.bd_addr);
  Peer* peer = cache_->FindByAddress(address);
  if (!peer) {
    bt_log(WARN, "gap-bredr", "got %s for unknown peer (address: %s)", __func__, bt_str(address));
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }
  PeerId peer_id = peer->identifier();

  // When a role change is requested in the HCI_Accept_Connection_Request command, a HCI_Role_Change
  // event may be received prior to the HCI_Connection_Complete event (so no connection object will
  // exist yet) (Core Spec v5.2, Vol 2, Part F, Sec 3.1).
  auto request_iter = connection_requests_.find(peer_id);
  if (request_iter != connection_requests_.end()) {
    request_iter->second.set_role_change(params.new_role);
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }

  auto conn_pair = FindConnectionByAddress(params.bd_addr);
  if (!conn_pair) {
    bt_log(WARN, "gap-bredr", "got %s for unconnected peer %s", __func__, bt_str(peer_id));
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }

  if (hci_is_error(event, WARN, "gap-bredr", "role change failed and remains %s (peer: %s)",
                   hci_spec::ConnectionRoleToString(params.new_role).c_str(), bt_str(peer_id))) {
    return hci::CommandChannel::EventCallbackResult::kContinue;
  }

  bt_log(DEBUG, "gap-bredr", "role changed to %s (peer: %s)",
         hci_spec::ConnectionRoleToString(params.new_role).c_str(), bt_str(peer_id));
  conn_pair->second->link().set_role(params.new_role);

  return hci::CommandChannel::EventCallbackResult::kContinue;
}

bool BrEdrConnectionManager::Connect(PeerId peer_id, ConnectResultCallback on_connection_result) {
  Peer* peer = cache_->FindById(peer_id);
  if (!peer) {
    bt_log(WARN, "gap-bredr", "%s: peer not found (peer: %s)", __func__, bt_str(peer_id));
    return false;
  }

  if (peer->technology() == TechnologyType::kLowEnergy) {
    bt_log(ERROR, "gap-bredr", "peer does not support BrEdr: %s", bt_str(*peer));
    return false;
  }

  // Br/Edr peers should always be connectable by definition
  ZX_ASSERT(peer->connectable());

  // Succeed immediately or after interrogation if there is already an active connection.
  auto conn = FindConnectionById(peer_id);
  if (conn) {
    conn->second->AddRequestCallback(std::move(on_connection_result));
    return true;
  }

  // If we are already waiting to connect to |peer_id| then we store
  // |on_connection_result| to be processed after the connection attempt
  // completes (in either success of failure).
  auto pending_iter = connection_requests_.find(peer_id);
  if (pending_iter != connection_requests_.end()) {
    pending_iter->second.AddCallback(std::move(on_connection_result));
    return true;
  }
  // If we are not already connected or pending, initiate a new connection
  auto [request_iter, _] = connection_requests_.try_emplace(
      peer_id, peer->address(), peer_id, peer->MutBrEdr().RegisterInitializingConnection(),
      std::move(on_connection_result));
  request_iter->second.AttachInspect(
      inspect_properties_.requests_node_,
      inspect_properties_.requests_node_.UniqueName(kInspectRequestNodeNamePrefix));

  TryCreateNextConnection();

  return true;
}

std::optional<BrEdrConnectionManager::CreateConnectionParams>
BrEdrConnectionManager::NextCreateConnectionParams() {
  for (auto& [peer_id, request] : connection_requests_) {
    // The peer should still be in PeerCache because it was marked "initializing" when the
    // connection was requested.
    const Peer* peer = cache_->FindById(peer_id);
    ZX_ASSERT(peer);
    if (peer->bredr() && !request.HasIncoming()) {
      return std::optional(CreateConnectionParams{peer->identifier(), request.address(),
                                                  peer->bredr()->clock_offset(),
                                                  peer->bredr()->page_scan_repetition_mode()});
    }
  }

  bt_log(TRACE, "gap-bredr", "no pending outbound connection requests remaining");
  return std::nullopt;
}

void BrEdrConnectionManager::TryCreateNextConnection() {
  // There can only be one outstanding BrEdr CreateConnection request at a time
  if (pending_request_) {
    return;
  }

  auto next = NextCreateConnectionParams();
  if (next) {
    InitiatePendingConnection(*next);
  }
}

void BrEdrConnectionManager::InitiatePendingConnection(CreateConnectionParams params) {
  auto self = weak_ptr_factory_.GetWeakPtr();
  auto on_failure = [self, addr = params.addr](hci::Result<> status, auto peer_id) {
    if (self && status.is_error())
      self->CompleteRequest(peer_id, addr, status, /*handle=*/0);
  };
  auto on_timeout = [self] {
    if (self)
      self->OnRequestTimeout();
  };
  BrEdrConnectionRequest& pending_gap_req = connection_requests_.find(params.peer_id)->second;
  pending_request_.emplace(params.peer_id, params.addr, on_timeout);
  pending_request_->CreateConnection(hci_->command_channel(), dispatcher_, params.clock_offset,
                                     params.page_scan_repetition_mode, request_timeout_,
                                     on_failure);
  pending_gap_req.RecordHciCreateConnectionAttempt();

  inspect_properties_.outgoing_.connection_attempts_.Add(1);
}

void BrEdrConnectionManager::OnRequestTimeout() {
  if (pending_request_) {
    pending_request_->Timeout();
    SendCreateConnectionCancelCommand(pending_request_->peer_address());
  }
}

void BrEdrConnectionManager::SendCreateConnectionCancelCommand(DeviceAddress addr) {
  auto cancel = hci::CommandPacket::New(hci_spec::kCreateConnectionCancel,
                                        sizeof(hci_spec::CreateConnectionCancelCommandParams));
  auto params = cancel->mutable_payload<hci_spec::CreateConnectionCancelCommandParams>();
  params->bd_addr = addr.value();
  hci_->command_channel()->SendCommand(std::move(cancel), [](auto, const hci::EventPacket& event) {
    hci_is_error(event, WARN, "hci-bredr", "failed to cancel connection request");
  });
}

void BrEdrConnectionManager::SendAuthenticationRequested(hci_spec::ConnectionHandle handle,
                                                         hci::ResultFunction<> cb) {
  auto auth_request = hci::CommandPacket::New(
      hci_spec::kAuthenticationRequested, sizeof(hci_spec::AuthenticationRequestedCommandParams));
  auth_request->mutable_payload<hci_spec::AuthenticationRequestedCommandParams>()
      ->connection_handle = htole16(handle);

  // Complete on command status because Authentication Complete Event is already registered.
  hci::CommandChannel::CommandCallback command_cb;
  if (cb) {
    command_cb = [cb = std::move(cb)](auto, const hci::EventPacket& event) {
      cb(event.ToResult());
    };
  }
  hci_->command_channel()->SendCommand(std::move(auth_request), std::move(command_cb),
                                       hci_spec::kCommandStatusEventCode);
}

void BrEdrConnectionManager::SendIoCapabilityRequestReply(
    DeviceAddressBytes bd_addr, hci_spec::IOCapability io_capability, uint8_t oob_data_present,
    hci_spec::AuthRequirements auth_requirements, hci::ResultFunction<> cb) {
  auto packet = hci::CommandPacket::New(hci_spec::kIOCapabilityRequestReply,
                                        sizeof(hci_spec::IOCapabilityRequestReplyCommandParams));
  auto params = packet->mutable_payload<hci_spec::IOCapabilityRequestReplyCommandParams>();
  params->bd_addr = bd_addr;
  params->io_capability = io_capability;
  params->oob_data_present = oob_data_present;
  params->auth_requirements = auth_requirements;
  SendCommandWithStatusCallback(std::move(packet), std::move(cb));
}

void BrEdrConnectionManager::SendIoCapabilityRequestNegativeReply(DeviceAddressBytes bd_addr,
                                                                  hci_spec::StatusCode reason,
                                                                  hci::ResultFunction<> cb) {
  auto packet =
      hci::CommandPacket::New(hci_spec::kIOCapabilityRequestNegativeReply,
                              sizeof(hci_spec::IOCapabilityRequestNegativeReplyCommandParams));
  auto params = packet->mutable_payload<hci_spec::IOCapabilityRequestNegativeReplyCommandParams>();
  params->bd_addr = bd_addr;
  params->reason = reason;
  SendCommandWithStatusCallback(std::move(packet), std::move(cb));
}

void BrEdrConnectionManager::SendUserConfirmationRequestReply(DeviceAddressBytes bd_addr,
                                                              hci::ResultFunction<> cb) {
  auto packet =
      hci::CommandPacket::New(hci_spec::kUserConfirmationRequestReply,
                              sizeof(hci_spec::UserConfirmationRequestReplyCommandParams));
  packet->mutable_payload<hci_spec::UserConfirmationRequestReplyCommandParams>()->bd_addr = bd_addr;
  SendCommandWithStatusCallback(std::move(packet), std::move(cb));
}

void BrEdrConnectionManager::SendUserConfirmationRequestNegativeReply(DeviceAddressBytes bd_addr,
                                                                      hci::ResultFunction<> cb) {
  auto packet =
      hci::CommandPacket::New(hci_spec::kUserConfirmationRequestNegativeReply,
                              sizeof(hci_spec::UserConfirmationRequestNegativeReplyCommandParams));
  packet->mutable_payload<hci_spec::UserConfirmationRequestNegativeReplyCommandParams>()->bd_addr =
      bd_addr;
  SendCommandWithStatusCallback(std::move(packet), std::move(cb));
}

void BrEdrConnectionManager::SendUserPasskeyRequestReply(DeviceAddressBytes bd_addr,
                                                         uint32_t numeric_value,
                                                         hci::ResultFunction<> cb) {
  auto packet = hci::CommandPacket::New(hci_spec::kUserPasskeyRequestReply,
                                        sizeof(hci_spec::UserPasskeyRequestReplyCommandParams));
  auto params = packet->mutable_payload<hci_spec::UserPasskeyRequestReplyCommandParams>();
  params->bd_addr = bd_addr;
  params->numeric_value = htole32(numeric_value);
  SendCommandWithStatusCallback(std::move(packet), std::move(cb));
}

void BrEdrConnectionManager::SendUserPasskeyRequestNegativeReply(DeviceAddressBytes bd_addr,
                                                                 hci::ResultFunction<> cb) {
  auto packet =
      hci::CommandPacket::New(hci_spec::kUserPasskeyRequestNegativeReply,
                              sizeof(hci_spec::UserPasskeyRequestNegativeReplyCommandParams));
  packet->mutable_payload<hci_spec::UserPasskeyRequestNegativeReplyCommandParams>()->bd_addr =
      bd_addr;
  SendCommandWithStatusCallback(std::move(packet), std::move(cb));
}

void BrEdrConnectionManager::SendLinkKeyRequestNegativeReply(DeviceAddressBytes bd_addr,
                                                             hci::ResultFunction<> cb) {
  auto negative_reply =
      hci::CommandPacket::New(hci_spec::kLinkKeyRequestNegativeReply,
                              sizeof(hci_spec::LinkKeyRequestNegativeReplyCommandParams));
  auto negative_reply_params =
      negative_reply->mutable_payload<hci_spec::LinkKeyRequestNegativeReplyCommandParams>();
  negative_reply_params->bd_addr = bd_addr;
  SendCommandWithStatusCallback(std::move(negative_reply), std::move(cb));
}

void BrEdrConnectionManager::SendLinkKeyRequestReply(DeviceAddressBytes bd_addr,
                                                     hci_spec::LinkKey link_key,
                                                     hci::ResultFunction<> cb) {
  auto reply = hci::CommandPacket::New(hci_spec::kLinkKeyRequestReply,
                                       sizeof(hci_spec::LinkKeyRequestReplyCommandParams));
  auto reply_params = reply->mutable_payload<hci_spec::LinkKeyRequestReplyCommandParams>();
  reply_params->bd_addr = bd_addr;
  const auto& key_value = link_key.value();
  std::copy(key_value.begin(), key_value.end(), reply_params->link_key);
  SendCommandWithStatusCallback(std::move(reply), std::move(cb));
}

void BrEdrConnectionManager::SendCommandWithStatusCallback(
    std::unique_ptr<hci::CommandPacket> command_packet, hci::ResultFunction<> cb) {
  hci::CommandChannel::CommandCallback command_cb;
  if (cb) {
    command_cb = [cb = std::move(cb)](auto, const hci::EventPacket& event) {
      cb(event.ToResult());
    };
  }
  hci_->command_channel()->SendCommand(std::move(command_packet), std::move(command_cb));
}

void BrEdrConnectionManager::SendAcceptConnectionRequest(DeviceAddressBytes addr,
                                                         hci::ResultFunction<> cb) {
  auto accept = hci::CommandPacket::New(hci_spec::kAcceptConnectionRequest,
                                        sizeof(hci_spec::AcceptConnectionRequestCommandParams));
  auto accept_params = accept->mutable_payload<hci_spec::AcceptConnectionRequestCommandParams>();
  accept_params->bd_addr = addr;
  // This role switch preference can fail. A HCI_Role_Change event will be generated if the role
  // switch is successful (Core Spec v5.2, Vol 2, Part F, Sec 3.1).
  accept_params->role = hci_spec::ConnectionRole::kCentral;

  hci::CommandChannel::CommandCallback command_cb;
  if (cb) {
    command_cb = [cb = std::move(cb)](auto, const hci::EventPacket& event) {
      cb(event.ToResult());
    };
  }

  hci_->command_channel()->SendCommand(std::move(accept), std::move(command_cb),
                                       hci_spec::kCommandStatusEventCode);
}

void BrEdrConnectionManager::SendRejectConnectionRequest(DeviceAddress addr,
                                                         hci_spec::StatusCode reason,
                                                         hci::ResultFunction<> cb) {
  auto reject = hci::CommandPacket::New(hci_spec::kRejectConnectionRequest,
                                        sizeof(hci_spec::RejectConnectionRequestCommandParams));
  auto reject_params = reject->mutable_payload<hci_spec::RejectConnectionRequestCommandParams>();
  reject_params->bd_addr = addr.value();
  reject_params->reason = reason;

  hci::CommandChannel::CommandCallback command_cb;
  if (cb) {
    command_cb = [cb = std::move(cb)](auto, const hci::EventPacket& event) {
      cb(event.ToResult());
    };
  }

  hci_->command_channel()->SendCommand(std::move(reject), std::move(command_cb),
                                       hci_spec::kCommandStatusEventCode);
}

void BrEdrConnectionManager::SendRejectSynchronousRequest(DeviceAddress addr,
                                                          hci_spec::StatusCode reason,
                                                          hci::ResultFunction<> cb) {
  auto reject =
      hci::CommandPacket::New(hci_spec::kRejectSynchronousConnectionRequest,
                              sizeof(hci_spec::RejectSynchronousConnectionRequestCommandParams));
  auto reject_params =
      reject->mutable_payload<hci_spec::RejectSynchronousConnectionRequestCommandParams>();
  reject_params->bd_addr = addr.value();
  reject_params->reason = reason;

  hci::CommandChannel::CommandCallback command_cb;
  if (cb) {
    command_cb = [cb = std::move(cb)](auto, const hci::EventPacket& event) {
      cb(event.ToResult());
    };
  }

  hci_->command_channel()->SendCommand(std::move(reject), std::move(command_cb),
                                       hci_spec::kCommandStatusEventCode);
}

void BrEdrConnectionManager::RecordDisconnectInspect(const BrEdrConnection& conn,
                                                     DisconnectReason reason) {
  // Add item to recent disconnections list.
  auto& inspect_item = inspect_properties_.last_disconnected_list.CreateItem();
  inspect_item.node.RecordString(kInspectLastDisconnectedItemPeerPropertyName,
                                 conn.peer_id().ToString());
  inspect_item.node.RecordUint(kInspectLastDisconnectedItemDurationPropertyName,
                               conn.duration().to_secs());
  inspect_item.node.RecordInt(kInspectTimestampPropertyName, async::Now(dispatcher_).get());

  switch (reason) {
    case DisconnectReason::kApiRequest:
      inspect_properties_.disconnect_local_api_request_count_.Add(1);
      break;
    case DisconnectReason::kInterrogationFailed:
      inspect_properties_.disconnect_interrogation_failed_count_.Add(1);
      break;
    case DisconnectReason::kPairingFailed:
      inspect_properties_.disconnect_pairing_failed_count_.Add(1);
      break;
    case DisconnectReason::kAclLinkError:
      inspect_properties_.disconnect_acl_link_error_count_.Add(1);
      break;
    case DisconnectReason::kPeerDisconnection:
      inspect_properties_.disconnect_peer_disconnection_count_.Add(1);
      break;
    default:
      break;
  }
}

}  // namespace bt::gap
