// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/peer_cache.h"

#include <lib/fit/function.h>

#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/assert.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/random.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/peer.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/connection.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/low_energy_scanner.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/sm/types.h"

namespace bt::gap {

namespace {

// Return an address with the same value as given, but with type kBREDR for
// kLEPublic addresses and vice versa.
DeviceAddress GetAliasAddress(const DeviceAddress& address) {
  if (address.type() == DeviceAddress::Type::kBREDR) {
    return {DeviceAddress::Type::kLEPublic, address.value()};
  } else if (address.type() == DeviceAddress::Type::kLEPublic) {
    return {DeviceAddress::Type::kBREDR, address.value()};
  }
  return address;
}

}  // namespace

Peer* PeerCache::NewPeer(const DeviceAddress& address, bool connectable) {
  auto* const peer = InsertPeerRecord(RandomPeerId(), address, connectable);
  if (peer) {
    UpdateExpiry(*peer);
    NotifyPeerUpdated(*peer, Peer::NotifyListenersChange::kBondNotUpdated);
  }
  return peer;
}

void PeerCache::ForEach(PeerCallback f) {
  BT_DEBUG_ASSERT(f);
  for (const auto& iter : peers_) {
    f(*iter.second.peer());
  }
}

bool PeerCache::AddBondedPeer(BondingData bd) {
  BT_DEBUG_ASSERT(bd.address.type() != DeviceAddress::Type::kLEAnonymous);

  const bool bond_le = bd.le_pairing_data.peer_ltk ||
                       bd.le_pairing_data.local_ltk || bd.le_pairing_data.csrk;
  const bool bond_bredr = bd.bredr_link_key.has_value();

  // |bd.le_pairing_data| must contain either a LTK or CSRK for LE Security Mode
  // 1 or 2.
  //
  // TODO(https://fxbug.dev/42102158): the address type checks here don't add
  // much value because the address type is derived from the presence of FIDL
  // bredr_bond and le_bond fields, so the check really should be whether at
  // least one of the mandatory bond secrets is present.
  if (bd.address.IsLowEnergy() && !bond_le) {
    bt_log(ERROR,
           "gap-le",
           "mandatory keys missing: no LTK or CSRK (id: %s)",
           bt_str(bd.identifier));
    return false;
  }

  if (bd.address.IsBrEdr() && !bond_bredr) {
    bt_log(ERROR,
           "gap-bredr",
           "mandatory link key missing (id: %s)",
           bt_str(bd.identifier));
    return false;
  }

  auto* peer =
      InsertPeerRecord(bd.identifier, bd.address, /*connectable=*/true);
  if (!peer) {
    return false;
  }

  // A bonded peer must have its identity known.
  peer->set_identity_known(true);

  if (bd.name.has_value()) {
    peer->RegisterName(bd.name.value(), Peer::NameSource::kUnknown);
  }

  if (bond_le) {
    BT_ASSERT(bd.le_pairing_data.irk.has_value() ==
              bd.le_pairing_data.identity_address.has_value());
    peer->MutLe().SetBondData(bd.le_pairing_data);
    BT_ASSERT(peer->le()->bonded());

    // Add the peer to the resolving list if it has an IRK.
    if (bd.le_pairing_data.irk) {
      le_resolving_list_.Add(bd.le_pairing_data.identity_address.value(),
                             bd.le_pairing_data.irk.value().value());
    }
  }

  if (bond_bredr) {
    for (auto& service : bd.bredr_services) {
      peer->MutBrEdr().AddService(std::move(service));
    }

    peer->MutBrEdr().SetBondData(*bd.bredr_link_key);
    BT_DEBUG_ASSERT(peer->bredr()->bonded());
  }

  if (peer->technology() == TechnologyType::kDualMode) {
    address_map_[GetAliasAddress(bd.address)] = bd.identifier;
  }

  BT_DEBUG_ASSERT(!peer->temporary());
  BT_DEBUG_ASSERT(peer->bonded());
  bt_log(TRACE,
         "gap",
         "restored bonded peer: %s, id: %s",
         bt_str(bd.address),
         bt_str(bd.identifier));

  // Don't call UpdateExpiry(). Since a bonded peer starts out as
  // non-temporary it is not necessary to ever set up the expiration callback.
  NotifyPeerUpdated(*peer, Peer::NotifyListenersChange::kBondNotUpdated);
  return true;
}

bool PeerCache::StoreLowEnergyBond(PeerId identifier,
                                   const sm::PairingData& bond_data) {
  BT_ASSERT(bond_data.irk.has_value() ==
            bond_data.identity_address.has_value());

  auto log_bond_failure =
      fit::defer([this] { peer_metrics_.LogLeBondFailureEvent(); });

  auto* peer = FindById(identifier);
  if (!peer) {
    bt_log(WARN,
           "gap-le",
           "failed to store bond for unknown peer (peer: %s)",
           bt_str(identifier));
    return false;
  }

  // Either a LTK or CSRK is mandatory for bonding (the former is needed for LE
  // Security Mode 1 and the latter is needed for Mode 2).
  if (!bond_data.peer_ltk && !bond_data.local_ltk && !bond_data.csrk) {
    bt_log(WARN,
           "gap-le",
           "mandatory keys missing: no LTK or CSRK (peer: %s)",
           bt_str(identifier));
    return false;
  }

  if (bond_data.identity_address) {
    auto existing_id = FindIdByAddress(*bond_data.identity_address);
    if (!existing_id) {
      // Map the new address to |peer|. We leave old addresses that map to
      // this peer in the cache in case there are any pending controller
      // procedures that expect them.
      // TODO(armansito): Maybe expire the old address after a while?
      address_map_[*bond_data.identity_address] = identifier;
    } else if (*existing_id != identifier) {
      bt_log(WARN,
             "gap-le",
             "identity address %s for peer %s belongs to another peer %s!",
             bt_str(*bond_data.identity_address),
             bt_str(identifier),
             bt_str(*existing_id));
      return false;
    }
    // We have either created a new mapping or the identity address already
    // maps to this peer.
  }

  // TODO(https://fxbug.dev/42072204): Check that we're not downgrading the
  // security level before overwriting the bond.
  peer->MutLe().SetBondData(bond_data);
  BT_DEBUG_ASSERT(!peer->temporary());
  BT_DEBUG_ASSERT(peer->le()->bonded());

  // Add the peer to the resolving list if it has an IRK.
  if (peer->identity_known() && bond_data.irk) {
    le_resolving_list_.Add(*bond_data.identity_address, bond_data.irk->value());
  }

  if (bond_data.cross_transport_key) {
    peer->StoreBrEdrCrossTransportKey(*bond_data.cross_transport_key);
  }

  // Report the bond for persisting only if the identity of the peer is known.
  if (peer->identity_known()) {
    NotifyPeerBonded(*peer);
  }

  log_bond_failure.cancel();
  peer_metrics_.LogLeBondSuccessEvent();
  return true;
}

bool PeerCache::StoreBrEdrBond(const DeviceAddress& address,
                               const sm::LTK& link_key) {
  BT_DEBUG_ASSERT(address.type() == DeviceAddress::Type::kBREDR);
  auto* peer = FindByAddress(address);
  if (!peer) {
    bt_log(WARN,
           "gap-bredr",
           "failed to store bond for unknown peer (address: %s)",
           bt_str(address));
    return false;
  }

  // TODO(https://fxbug.dev/42072204): Check that we're not downgrading the
  // security level before overwriting the bond.
  peer->MutBrEdr().SetBondData(link_key);
  BT_DEBUG_ASSERT(!peer->temporary());
  BT_DEBUG_ASSERT(peer->bredr()->bonded());

  NotifyPeerBonded(*peer);
  return true;
}

bool PeerCache::SetAutoConnectBehaviorForIntentionalDisconnect(PeerId peer_id) {
  Peer* const peer = FindById(peer_id);
  if (!peer) {
    bt_log(WARN,
           "gap-le",
           "failed to update auto-connect behavior to kSkipUntilNextConnection "
           "for "
           "unknown peer: %s",
           bt_str(peer_id));
    return false;
  }

  bt_log(DEBUG,
         "gap-le",
         "updated auto-connect behavior to kSkipUntilNextConnection (peer: %s)",
         bt_str(peer_id));

  peer->MutLe().set_auto_connect_behavior(
      Peer::AutoConnectBehavior::kSkipUntilNextConnection);

  // TODO(https://fxbug.dev/42113239): When implementing auto-connect behavior
  // tracking for classic bluetooth, consider tracking this policy for the peer
  // as a whole unless we think this policy should be applied separately for
  // each transport (per armansito@).

  return true;
}

bool PeerCache::SetAutoConnectBehaviorForSuccessfulConnection(PeerId peer_id) {
  Peer* const peer = FindById(peer_id);
  if (!peer) {
    bt_log(WARN,
           "gap-le",
           "failed to update auto-connect behavior to kAlways for unknown "
           "peer: %s",
           bt_str(peer_id));
    return false;
  }

  bt_log(DEBUG,
         "gap-le",
         "updated auto-connect behavior to kAlways (peer: %s)",
         bt_str(peer_id));

  peer->MutLe().set_auto_connect_behavior(Peer::AutoConnectBehavior::kAlways);

  // TODO(https://fxbug.dev/42113239): Implement auto-connect behavior tracking
  // for classic bluetooth.

  return true;
}

bool PeerCache::RemoveDisconnectedPeer(PeerId peer_id) {
  Peer* const peer = FindById(peer_id);
  if (!peer) {
    return true;
  }

  if (peer->connected()) {
    return false;
  }

  RemovePeer(peer);
  return true;
}

Peer* PeerCache::FindById(PeerId peer_id) const {
  auto iter = peers_.find(peer_id);
  return iter != peers_.end() ? iter->second.peer() : nullptr;
}

Peer* PeerCache::FindByAddress(const DeviceAddress& in_address) const {
  std::optional<DeviceAddress> address;
  if (in_address.IsResolvablePrivate()) {
    address = le_resolving_list_.Resolve(in_address);
  }

  // Fall back to the input if an identity wasn't resolved.
  if (!address) {
    address = in_address;
  }

  BT_DEBUG_ASSERT(address);
  auto identifier = FindIdByAddress(*address);
  if (!identifier) {
    return nullptr;
  }

  auto* p = FindById(*identifier);
  BT_DEBUG_ASSERT(p);
  return p;
}

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

  if (!node_) {
    return;
  }

  peer_metrics_.AttachInspect(node_);

  for (auto& [_, record] : peers_) {
    record.peer()->AttachInspect(node_, node_.UniqueName("peer_"));
  }
}

PeerCache::CallbackId PeerCache::add_peer_updated_callback(
    PeerCallback callback) {
  auto [iter, success] =
      peer_updated_callbacks_.emplace(next_callback_id_++, std::move(callback));
  BT_ASSERT(success);
  return iter->first;
}

bool PeerCache::remove_peer_updated_callback(CallbackId id) {
  return peer_updated_callbacks_.erase(id);
}

// Private methods below.

Peer* PeerCache::InsertPeerRecord(PeerId identifier,
                                  const DeviceAddress& address,
                                  bool connectable) {
  if (FindIdByAddress(address)) {
    bt_log(WARN,
           "gap",
           "tried to insert peer with existing address: %s",
           address.ToString().c_str());
    return nullptr;
  }

  auto store_le_bond_cb = [this, identifier](const sm::PairingData& data) {
    return StoreLowEnergyBond(identifier, data);
  };

  std::unique_ptr<Peer> peer(
      new Peer(fit::bind_member<&PeerCache::NotifyPeerUpdated>(this),
               fit::bind_member<&PeerCache::UpdateExpiry>(this),
               fit::bind_member<&PeerCache::MakeDualMode>(this),
               std::move(store_le_bond_cb),
               identifier,
               address,
               connectable,
               &peer_metrics_,
               dispatcher_));
  if (node_) {
    peer->AttachInspect(node_, node_.UniqueName("peer_"));
  }

  // Note: we must construct the PeerRecord in-place, because it doesn't
  // support copy or move.
  auto [iter, inserted] = peers_.try_emplace(
      peer->identifier(),
      std::move(peer),
      [this, p = peer.get()] { RemovePeer(p); },
      dispatcher_);
  if (!inserted) {
    bt_log(WARN,
           "gap",
           "tried to insert peer with existing ID: %s",
           bt_str(identifier));
    return nullptr;
  }

  address_map_[address] = identifier;
  return iter->second.peer();
}

void PeerCache::NotifyPeerBonded(const Peer& peer) {
  BT_DEBUG_ASSERT(peers_.find(peer.identifier()) != peers_.end());
  BT_DEBUG_ASSERT(peers_.at(peer.identifier()).peer() == &peer);
  BT_DEBUG_ASSERT_MSG(peer.identity_known(),
                      "peers not allowed to bond with unknown identity!");

  bt_log(INFO, "gap", "successfully bonded (peer: %s)", bt_str(peer));
  if (peer_bonded_callback_) {
    peer_bonded_callback_(peer);
  }
}

void PeerCache::NotifyPeerUpdated(const Peer& peer,
                                  Peer::NotifyListenersChange change) {
  BT_DEBUG_ASSERT(peers_.find(peer.identifier()) != peers_.end());
  BT_DEBUG_ASSERT(peers_.at(peer.identifier()).peer() == &peer);

  for (auto& [_, peer_updated_callback] : peer_updated_callbacks_) {
    peer_updated_callback(peer);
  }

  if (change == Peer::NotifyListenersChange::kBondUpdated) {
    BT_ASSERT(peer.bonded());
    bt_log(INFO, "gap", "peer bond updated %s", bt_str(peer));
    if (peer_bonded_callback_) {
      peer_bonded_callback_(peer);
    }
  }
}

void PeerCache::UpdateExpiry(const Peer& peer) {
  auto peer_record_iter = peers_.find(peer.identifier());
  BT_DEBUG_ASSERT(peer_record_iter != peers_.end());

  auto& peer_record = peer_record_iter->second;
  BT_DEBUG_ASSERT(peer_record.peer() == &peer);

  peer_record.removal_task()->Cancel();

  // Previous expiry task has been canceled. Re-schedule only if the peer is
  // temporary.
  if (peer.temporary()) {
    peer_record.removal_task()->PostAfter(kCacheTimeout);
  }
}

void PeerCache::MakeDualMode(const Peer& peer) {
  BT_ASSERT(address_map_.at(peer.address()) == peer.identifier());
  const auto address_alias = GetAliasAddress(peer.address());
  auto [iter, inserted] =
      address_map_.try_emplace(address_alias, peer.identifier());
  BT_ASSERT_MSG(inserted || iter->second == peer.identifier(),
                "%s can't become dual-mode because %s maps to %s",
                bt_str(peer.identifier()),
                bt_str(address_alias),
                bt_str(iter->second));
  bt_log(INFO,
         "gap",
         "peer became dual mode (peer: %s, address: %s, alias: %s)",
         bt_str(peer.identifier()),
         bt_str(peer.address()),
         bt_str(address_alias));

  // The peer became dual mode in lieu of adding a new peer but is as
  // significant, so notify listeners of the change.
  NotifyPeerUpdated(peer, Peer::NotifyListenersChange::kBondNotUpdated);
}

void PeerCache::RemovePeer(Peer* peer) {
  BT_DEBUG_ASSERT(peer);

  auto peer_record_it = peers_.find(peer->identifier());
  BT_DEBUG_ASSERT(peer_record_it != peers_.end());
  BT_DEBUG_ASSERT(peer_record_it->second.peer() == peer);

  PeerId id = peer->identifier();
  bt_log(DEBUG, "gap", "removing peer %s", bt_str(id));
  for (auto iter = address_map_.begin(); iter != address_map_.end();) {
    if (iter->second == id) {
      iter = address_map_.erase(iter);
    } else {
      iter++;
    }
  }

  if (peer->le() && peer->le()->bonded()) {
    if (auto& address = peer->le()->bond_data()->identity_address) {
      le_resolving_list_.Remove(*address);
    }
  }

  peers_.erase(peer_record_it);  // Destroys |peer|.
  if (peer_removed_callback_) {
    peer_removed_callback_(id);
  }
}

std::optional<PeerId> PeerCache::FindIdByAddress(
    const DeviceAddress& address) const {
  auto iter = address_map_.find(address);
  if (iter == address_map_.end()) {
    // Search again using the other technology's address. This is necessary when
    // a dual-mode peer is known by only one technology and is then discovered
    // or connected on its other technology.
    iter = address_map_.find(GetAliasAddress(address));
  }

  if (iter == address_map_.end()) {
    return {};
  }
  return {iter->second};
}

}  // namespace bt::gap
