// 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 <zircon/assert.h>

#include "src/connectivity/bluetooth/core/bt-host/common/log.h"
#include "src/connectivity/bluetooth/core/bt-host/gap/peer_cache.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/connection.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/hci_constants.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/sequential_command_runner.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/transport.h"

namespace bt {
namespace gap {

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

namespace {

void SetPageScanEnabled(bool enabled, fxl::RefPtr<hci::Transport> hci,
                        async_dispatcher_t* dispatcher,
                        hci::StatusCallback cb) {
  ZX_DEBUG_ASSERT(cb);
  auto read_enable = hci::CommandPacket::New(hci::kReadScanEnable);
  auto finish_enable_cb = [enabled, dispatcher, 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.ToStatus());
      return;
    }

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

}  // namespace

hci::CommandChannel::EventHandlerId BrEdrConnectionManager::AddEventHandler(
    const hci::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) {
          callback(event);
        }
      },
      dispatcher_);
  ZX_DEBUG_ASSERT(event_id);
  return event_id;
}

BrEdrConnectionManager::BrEdrConnectionManager(
    fxl::RefPtr<hci::Transport> hci, PeerCache* peer_cache,
    DeviceAddress local_address, fbl::RefPtr<data::Domain> data_domain,
    bool use_interlaced_scan)
    : hci_(hci),
      cache_(peer_cache),
      local_address_(local_address),
      data_domain_(data_domain),
      interrogator_(cache_, hci_, async_get_default_dispatcher()),
      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(data_domain_);
  ZX_DEBUG_ASSERT(dispatcher_);

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

  // Register event handlers
  conn_complete_handler_id_ = AddEventHandler(
      hci::kConnectionCompleteEventCode,
      fbl::BindMember(this, &BrEdrConnectionManager::OnConnectionComplete));
  conn_request_handler_id_ = AddEventHandler(
      hci::kConnectionRequestEventCode,
      fbl::BindMember(this, &BrEdrConnectionManager::OnConnectionRequest));
  disconn_cmpl_handler_id_ = AddEventHandler(
      hci::kDisconnectionCompleteEventCode,
      fbl::BindMember(this, &BrEdrConnectionManager::OnDisconnectionComplete));
  link_key_request_handler_id_ = AddEventHandler(
      hci::kLinkKeyRequestEventCode,
      fbl::BindMember(this, &BrEdrConnectionManager::OnLinkKeyRequest));
  link_key_notification_handler_id_ = AddEventHandler(
      hci::kLinkKeyNotificationEventCode,
      fbl::BindMember(this, &BrEdrConnectionManager::OnLinkKeyNotification));
  io_cap_req_handler_id_ = AddEventHandler(
      hci::kIOCapabilityRequestEventCode,
      fbl::BindMember(this, &BrEdrConnectionManager::OnIOCapabilitiesRequest));
  user_conf_handler_id_ = AddEventHandler(
      hci::kUserConfirmationRequestEventCode,
      fbl::BindMember(this,
                      &BrEdrConnectionManager::OnUserConfirmationRequest));
}

BrEdrConnectionManager::~BrEdrConnectionManager() {
  if (pending_request_ && pending_request_->Cancel())
    SendCreateConnectionCancelCommand(pending_request_->peer_address());

  // Disconnect any connections that we're holding.
  connections_.clear();
  SetPageScanEnabled(false, hci_, dispatcher_, [](const auto) {});
  hci_->command_channel()->RemoveEventHandler(conn_request_handler_id_);
  hci_->command_channel()->RemoveEventHandler(conn_complete_handler_id_);
  hci_->command_channel()->RemoveEventHandler(disconn_cmpl_handler_id_);
  hci_->command_channel()->RemoveEventHandler(link_key_request_handler_id_);
  hci_->command_channel()->RemoveEventHandler(
      link_key_notification_handler_id_);
  hci_->command_channel()->RemoveEventHandler(io_cap_req_handler_id_);
  hci_->command_channel()->RemoveEventHandler(user_conf_handler_id_);
}

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

  WritePageScanSettings(
      hci::kPageScanR1Interval, hci::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(hci::Status(HostError::kFailed));
          return;
        }
        SetPageScanEnabled(true, self->hci_, self->dispatcher_, std::move(cb));
      });
}

void BrEdrConnectionManager::SetPairingDelegate(
    fxl::WeakPtr<PairingDelegate> delegate) {
  // TODO(armansito): implement
}

PeerId BrEdrConnectionManager::GetPeerId(hci::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();
}

bool BrEdrConnectionManager::OpenL2capChannel(PeerId peer_id, l2cap::PSM psm,
                                              SocketCallback cb,
                                              async_dispatcher_t* dispatcher) {
  auto handle = FindConnectionById(peer_id);
  if (!handle) {
    return false;
  }

  data_domain_->OpenL2capChannel(
      handle->first, psm,
      [cb = std::move(cb)](zx::socket s, auto) { cb(std::move(s)); },
      dispatcher);
  return true;
}

BrEdrConnectionManager::SearchId BrEdrConnectionManager::AddServiceSearch(
    const UUID& uuid, std::unordered_set<sdp::AttributeId> attributes,
    BrEdrConnectionManager::SearchCallback callback) {
  return discoverer_.AddSearch(uuid, std::move(attributes),
                               std::move(callback));
}

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

bool BrEdrConnectionManager::Disconnect(PeerId peer_id) {
  auto handle = FindConnectionById(peer_id);
  if (!handle) {
    return false;
  }

  auto& connection = connections_.find(handle->first)->second.link();
  if (!connection.is_open()) {
    return false;
  }

  connection.Close();
  return true;
}

void BrEdrConnectionManager::WritePageScanSettings(uint16_t interval,
                                                   uint16_t window,
                                                   bool interlaced,
                                                   hci::StatusCallback 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(hci::Status(HostError::kInProgress));
    return;
  }

  auto write_activity =
      hci::CommandPacket::New(hci::kWritePageScanActivity,
                              sizeof(hci::WritePageScanActivityCommandParams));
  auto* activity_params =
      write_activity->mutable_view()
          ->mutable_payload<hci::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(SPEW, "gap-bredr", "page scan activity updated");
      });

  auto write_type = hci::CommandPacket::New(
      hci::kWritePageScanType, sizeof(hci::WritePageScanTypeCommandParams));
  auto* type_params =
      write_type->mutable_view()
          ->mutable_payload<hci::WritePageScanTypeCommandParams>();
  type_params->page_scan_type = (interlaced ? hci::PageScanType::kInterlacedScan
                                            : hci::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::PageScanType::kInterlacedScan
                                            : hci::PageScanType::kStandardScan);

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

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

std::optional<std::pair<hci::ConnectionHandle, BrEdrConnection*>>
BrEdrConnectionManager::FindConnectionById(PeerId peer_id) {
  auto* const peer = cache_->FindById(peer_id);
  if (!peer || !peer->bredr() || !peer->bredr()->connected()) {
    return std::nullopt;
  }

  auto it = std::find_if(
      connections_.begin(), connections_.end(),
      [peer_id](const auto& c) { return c.second.peer_id() == peer_id; });

  // If we're connected, we must have an ID.
  ZX_ASSERT_MSG(it != connections_.end(), "couldn't find handle for peer %s",
                bt_str(peer_id));

  auto& [handle, conn_ptr] = *it;
  ZX_ASSERT(conn_ptr.link().ll_type() != hci::Connection::LinkType::kLE);

  return std::pair(handle, &conn_ptr);
}

void BrEdrConnectionManager::OnConnectionRequest(
    const hci::EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == hci::kConnectionRequestEventCode);
  const auto& params =
      event.view().payload<hci::ConnectionRequestEventParams>();
  std::string link_type_str =
      params.link_type == hci::LinkType::kACL ? "ACL" : "(e)SCO";

  bt_log(TRACE, "gap-bredr", "%s conn request from %s (%s)",
         link_type_str.c_str(), params.bd_addr.ToString().c_str(),
         params.class_of_device.ToString().c_str());

  if (params.link_type == hci::LinkType::kACL) {
    // 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", "accept incoming connection");

    auto accept = hci::CommandPacket::New(
        hci::kAcceptConnectionRequest,
        sizeof(hci::AcceptConnectionRequestCommandParams));
    auto accept_params =
        accept->mutable_view()
            ->mutable_payload<hci::AcceptConnectionRequestCommandParams>();
    accept_params->bd_addr = params.bd_addr;
    accept_params->role = hci::ConnectionRole::kMaster;

    hci_->command_channel()->SendCommand(std::move(accept), dispatcher_,
                                         nullptr, hci::kCommandStatusEventCode);
    return;
  }

  // Reject this connection.
  bt_log(INFO, "gap-bredr", "reject unsupported connection");

  auto reject = hci::CommandPacket::New(
      hci::kRejectConnectionRequest,
      sizeof(hci::RejectConnectionRequestCommandParams));
  auto reject_params =
      reject->mutable_view()
          ->mutable_payload<hci::RejectConnectionRequestCommandParams>();
  reject_params->bd_addr = params.bd_addr;
  reject_params->reason = hci::StatusCode::kConnectionRejectedBadBdAddr;

  hci_->command_channel()->SendCommand(std::move(reject), dispatcher_, nullptr,
                                       hci::kCommandStatusEventCode);
}

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

void BrEdrConnectionManager::OnConnectionComplete(
    const hci::EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == hci::kConnectionCompleteEventCode);

  const auto& params =
      event.view().payload<hci::ConnectionCompleteEventParams>();
  auto connection_handle = letoh16(params.connection_handle);
  DeviceAddress addr(DeviceAddress::Type::kBREDR, params.bd_addr);

  bt_log(TRACE, "gap-bredr",
         "%s connection complete (status %#.2x, handle: %#.4x)",
         bt_str(params.bd_addr), params.status, connection_handle);

  if (pending_request_ && pending_request_->peer_address() == addr) {
    auto status = hci::Status(params.status);
    status = pending_request_->CompleteRequest(status);

    if (!status)
      OnConnectFailure(status, pending_request_->peer_id());
  }

  if (params.link_type != hci::LinkType::kACL) {
    // Drop the connection if we don't support it.
    return;
  }

  if (!hci_is_error(event, WARN, "gap-bredr", "connection error")) {
    InitializeConnection(addr, std::move(connection_handle));
  }
}

// Initialize a full Br/Edr connection from the hci::Connection |link|
// Initialization begins the interrogation process, once completed we establish
// a fully usable Br/Edr connection
void BrEdrConnectionManager::InitializeConnection(DeviceAddress addr,
                                                  uint16_t connection_handle) {
  // TODO(BT-288): support non-master connections.
  auto link = hci::Connection::CreateACL(connection_handle,
                                         hci::Connection::Role::kMaster,
                                         local_address_, addr, hci_);

  Peer* peer = FindOrInitPeer(addr);
  // In Br/Edr, we should never establish more than one link to a given peer
  ZX_DEBUG_ASSERT(!FindConnectionById(peer->identifier()));
  peer->MutBrEdr().SetConnectionState(ConnectionState::kInitializing);

  // Interrogate this peer to find out its version/capabilities.
  auto self = weak_ptr_factory_.GetWeakPtr();
  interrogator_.Start(
      peer->identifier(), std::move(link),
      [peer, self](auto status, auto conn_ptr) {
        if (bt_is_error(status, WARN, "gap-bredr",
                        "interrogate failed, dropping connection"))
          return;
        bt_log(SPEW, "gap-bredr", "interrogation complete for %#.4x",
               conn_ptr->handle());
        if (!self)
          return;
        self->EstablishConnection(peer, status, std::move(conn_ptr));
      });
}

// Establish a full BrEdrConnection for a link that has been interrogated
void BrEdrConnectionManager::EstablishConnection(
    Peer* peer, hci::Status status, unique_ptr<hci::Connection> connection) {
  auto self = weak_ptr_factory_.GetWeakPtr();

  auto error_handler = [self, connection = connection->WeakPtr()] {
    if (!self || !connection)
      return;
    bt_log(ERROR, "gap-bredr", "Link error received, closing connection %#.4x",
           connection->handle());

    // Clean up after receiving the DisconnectComplete event.
    // TODO(BT-70): Test link error behavior using FakePeer.
    connection->Close();
  };

  // TODO(armansito): Implement this callback.
  auto security_callback = [](hci::ConnectionHandle handle,
                              sm::SecurityLevel level, auto cb) {
    bt_log(INFO, "gap-bredr",
           "Ignoring security upgrade request; not implemented");
    cb(sm::Status(HostError::kNotSupported));
  };

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

  auto handle = connection->handle();

  auto conn =
      connections_
          .try_emplace(handle, peer->identifier(), std::move(connection))
          .first;
  peer->MutBrEdr().SetConnectionState(ConnectionState::kConnected);

  if (discoverer_.search_count()) {
    data_domain_->OpenL2capChannel(
        handle, l2cap::kSDP,
        [self, peer_id = peer->identifier()](auto channel) {
          if (!self)
            return;
          auto client = sdp::Client::Create(std::move(channel));

          self->discoverer_.StartServiceDiscovery(peer_id, std::move(client));
        },
        dispatcher_);
  }

  auto request = connection_requests_.extract(peer->identifier());
  if (request) {
    auto conn_ptr = &(conn->second);
    request.mapped().NotifyCallbacks(hci::Status(),
                                     [conn_ptr] { return conn_ptr; });
    // If this was our in-flight request, close it
    if (peer->address() == pending_request_->peer_address()) {
      pending_request_.reset();
    }
    TryCreateNextConnection();
  }
}

void BrEdrConnectionManager::OnDisconnectionComplete(
    const hci::EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == hci::kDisconnectionCompleteEventCode);
  const auto& params =
      event.view().payload<hci::DisconnectionCompleteEventParams>();

  hci::ConnectionHandle handle = le16toh(params.connection_handle);
  if (hci_is_error(event, WARN, "gap-bredr",
                   "HCI disconnection error handle %#.4x", handle)) {
    return;
  }

  auto it = connections_.find(handle);

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

  auto* peer = cache_->FindByAddress(it->second.link().peer_address());
  bt_log(INFO, "gap-bredr",
         "%s disconnected - %s, handle: %#.4x, reason: %#.2x",
         bt_str(peer->identifier()), bt_str(event.ToStatus()), handle,
         params.reason);

  CleanupConnection(handle, connections_.extract(handle).mapped(), true);
}

void BrEdrConnectionManager::CleanupConnection(hci::ConnectionHandle handle,
                                               BrEdrConnection& conn,
                                               bool link_already_closed) {
  auto* peer = cache_->FindByAddress(conn.link().peer_address());
  ZX_DEBUG_ASSERT_MSG(peer, "Couldn't find peer for handle: %#.4x", handle);
  peer->MutBrEdr().SetConnectionState(ConnectionState::kNotConnected);

  data_domain_->RemoveConnection(handle);

  if (link_already_closed) {
    // Connection is already closed, so we don't need to send a disconnect.
    conn.link().set_closed();
  }
}

void BrEdrConnectionManager::OnLinkKeyRequest(const hci::EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == hci::kLinkKeyRequestEventCode);
  const auto& params = event.view().payload<hci::LinkKeyRequestParams>();

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

  auto* peer = cache_->FindByAddress(addr);
  if (!peer || !peer->bredr()->bonded()) {
    bt_log(INFO, "gap-bredr", "no known peer with address %s found",
           addr.ToString().c_str());

    auto reply = hci::CommandPacket::New(
        hci::kLinkKeyRequestNegativeReply,
        sizeof(hci::LinkKeyRequestNegativeReplyCommandParams));
    auto reply_params =
        reply->mutable_view()
            ->mutable_payload<hci::LinkKeyRequestNegativeReplyCommandParams>();

    reply_params->bd_addr = params.bd_addr;

    hci_->command_channel()->SendCommand(std::move(reply), dispatcher_,
                                         nullptr);
    return;
  }

  bt_log(INFO, "gap-bredr", "recalling link key for bonded peer %s",
         bt_str(peer->identifier()));

  auto reply = hci::CommandPacket::New(
      hci::kLinkKeyRequestReply, sizeof(hci::LinkKeyRequestReplyCommandParams));
  auto reply_params =
      reply->mutable_view()
          ->mutable_payload<hci::LinkKeyRequestReplyCommandParams>();

  reply_params->bd_addr = params.bd_addr;
  const sm::LTK& link_key = *peer->bredr()->link_key();
  ZX_DEBUG_ASSERT(link_key.security().enc_key_size() == 16);
  const auto& key_value = link_key.key().value();
  std::copy(key_value.begin(), key_value.end(), reply_params->link_key);

  hci_->command_channel()->SendCommand(
      std::move(reply), dispatcher_, [](auto, const hci::EventPacket& event) {
        bt_log(SPEW, "gap-bredr", "completed Link Key Request Reply");
      });
}

void BrEdrConnectionManager::OnLinkKeyNotification(
    const hci::EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == hci::kLinkKeyNotificationEventCode);
  const auto& params =
      event.view().payload<hci::LinkKeyNotificationEventParams>();

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

  bt_log(TRACE, "gap-bredr", "got link key (type %u) for address %s",
         params.key_type, addr.ToString().c_str());

  auto* peer = cache_->FindByAddress(addr);
  if (!peer) {
    bt_log(WARN, "gap-bredr",
           "no known peer with address %s found; link key not stored",
           addr.ToString().c_str());
    return;
  }

  const auto key_type = static_cast<hci::LinkKeyType>(params.key_type);
  sm::SecurityProperties sec_props;
  if (key_type == hci::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()));
      return;
    }

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

  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->identifier()));
    return;
  }

  UInt128 key_value;
  std::copy(params.link_key, &params.link_key[key_value.size()],
            key_value.begin());
  sm::LTK key(sec_props, hci::LinkKey(key_value, 0, 0));
  if (!cache_->StoreBrEdrBond(addr, key)) {
    bt_log(ERROR, "gap-bredr", "failed to cache bonding data (id: %s)",
           bt_str(peer->identifier()));
  }
}

void BrEdrConnectionManager::OnIOCapabilitiesRequest(
    const hci::EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == hci::kIOCapabilityRequestEventCode);
  const auto& params =
      event.view().payload<hci::IOCapabilityRequestEventParams>();

  auto reply = hci::CommandPacket::New(
      hci::kIOCapabilityRequestReply,
      sizeof(hci::IOCapabilityRequestReplyCommandParams));
  auto reply_params =
      reply->mutable_view()
          ->mutable_payload<hci::IOCapabilityRequestReplyCommandParams>();

  reply_params->bd_addr = params.bd_addr;
  // TODO(jamuraa, BT-169): ask the PairingDelegate if it's set what the IO
  // capabilities it has.
  reply_params->io_capability = hci::IOCapability::kNoInputNoOutput;
  // TODO(BT-8): Add OOB status from PeerCache.
  reply_params->oob_data_present = 0x00;  // None present.
  // TODO(BT-656): Determine this based on the service requirements.
  reply_params->auth_requirements = hci::AuthRequirements::kGeneralBonding;

  hci_->command_channel()->SendCommand(std::move(reply), dispatcher_, nullptr);
}

void BrEdrConnectionManager::OnUserConfirmationRequest(
    const hci::EventPacket& event) {
  ZX_DEBUG_ASSERT(event.event_code() == hci::kUserConfirmationRequestEventCode);
  const auto& params =
      event.view().payload<hci::UserConfirmationRequestEventParams>();

  bt_log(INFO, "gap-bredr", "auto-confirming pairing from %s (%u)",
         bt_str(params.bd_addr), params.numeric_value);

  // TODO(jamuraa, BT-169): if we are not NoInput/NoOutput then we need to ask
  // the pairing delegate.  This currently will auto accept any pairing
  // (JustWorks)
  auto reply = hci::CommandPacket::New(
      hci::kUserConfirmationRequestReply,
      sizeof(hci::UserConfirmationRequestReplyCommandParams));
  auto reply_params =
      reply->mutable_view()
          ->mutable_payload<hci::UserConfirmationRequestReplyCommandParams>();

  reply_params->bd_addr = params.bd_addr;

  hci_->command_channel()->SendCommand(std::move(reply), dispatcher_, nullptr);
}

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

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

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

  // Succeed immediately if there is already an active connection.
  auto conn = FindConnectionById(peer_id);
  if (conn) {
    async::PostTask(dispatcher_,
                    [conn = conn->second,
                     on_result = std::move(on_connection_result)]() mutable {
                      on_result(hci::Status(), conn);
                    });
    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
  peer->MutBrEdr().SetConnectionState(ConnectionState::kInitializing);
  connection_requests_.try_emplace(peer_id, peer->address(),
                                   std::move(on_connection_result));

  TryCreateNextConnection();

  return true;
}

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

  if (connection_requests_.empty()) {
    bt_log(SPEW, "gap-bredr", "no pending requests remaining");
    return;
  }

  Peer* peer = nullptr;
  for (auto& request : connection_requests_) {
    const auto& next_peer_addr = request.second.address();
    peer = cache_->FindByAddress(next_peer_addr);
    if (peer && peer->bredr())
      break;
  }

  auto self = weak_ptr_factory_.GetWeakPtr();
  auto on_failure = [self](hci::Status status, auto peer_id) {
    if (self && !status)
      self->OnConnectFailure(status, peer_id);
  };
  auto on_timeout = [self] {
    if (self)
      self->OnRequestTimeout();
  };

  if (peer) {
    pending_request_.emplace(peer->identifier(), peer->address(), on_timeout);
    pending_request_->CreateConnection(
        hci_->command_channel(), dispatcher_, peer->bredr()->clock_offset(),
        peer->bredr()->page_scan_repetition_mode(), request_timeout_,
        on_failure);
  } else {
    // If there are no pending requests for peers which are in the cache, try
    // to connect to a peer which has left the cache, in case it is still
    // possible
    auto request = connection_requests_.begin();
    if (request != connection_requests_.end()) {
      auto identifier = request->first;
      auto address = request->second.address();

      pending_request_.emplace(identifier, address, on_timeout);
      pending_request_->CreateConnection(hci_->command_channel(), dispatcher_,
                                         std::nullopt, std::nullopt,
                                         request_timeout_, on_failure);
    }
  }
}

void BrEdrConnectionManager::OnConnectFailure(hci::Status status,
                                              PeerId peer_id) {
  // The request failed or timed out.
  bt_log(ERROR, "gap-bredr", "failed to connect to peer (id: %s)",
         bt_str(peer_id));
  Peer* peer = cache_->FindById(peer_id);
  // The peer may no longer be in the cache by the time this function is called
  if (peer) {
    peer->MutBrEdr().SetConnectionState(ConnectionState::kNotConnected);
  }

  pending_request_.reset();

  // Notify the matching pending callbacks about the failure.
  auto request = connection_requests_.extract(peer_id);
  ZX_DEBUG_ASSERT(request);
  request.mapped().NotifyCallbacks(status, [] { return nullptr; });

  // Process the next pending attempt.
  TryCreateNextConnection();
}

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::kCreateConnectionCancel,
                              sizeof(hci::CreateConnectionCancelCommandParams));
  auto params =
      cancel->mutable_view()
          ->mutable_payload<hci::CreateConnectionCancelCommandParams>();
  params->bd_addr = addr.value();
  hci_->command_channel()->SendCommand(
      std::move(cancel), dispatcher_, [](auto, const hci::EventPacket& event) {
        hci_is_error(event, WARN, "hci-bredr",
                     "failed to cancel connection request");
      });
}

}  // namespace gap
}  // namespace bt
