// Copyright 2023 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

#include "pw_bluetooth_sapphire/internal/host/hci/extended_low_energy_advertiser.h"

#include "pw_bluetooth_sapphire/internal/host/hci-spec/util.h"
#include "pw_bluetooth_sapphire/internal/host/transport/transport.h"

namespace bt::hci {

ExtendedLowEnergyAdvertiser::ExtendedLowEnergyAdvertiser(
    hci::Transport::WeakPtr hci_ptr)
    : LowEnergyAdvertiser(std::move(hci_ptr)), weak_self_(this) {
  auto self = weak_self_.GetWeakPtr();
  set_terminated_event_handler_id_ =
      hci()->command_channel()->AddLEMetaEventHandler(
          hci_spec::kLEAdvertisingSetTerminatedSubeventCode,
          [self](const EventPacket& event_packet) {
            if (self.is_alive()) {
              return self->OnAdvertisingSetTerminatedEvent(event_packet);
            }

            return CommandChannel::EventCallbackResult::kRemove;
          });
}

ExtendedLowEnergyAdvertiser::~ExtendedLowEnergyAdvertiser() {
  // This object is probably being destroyed because the stack is shutting down,
  // in which case the HCI layer may have already been destroyed.
  if (!hci().is_alive() || !hci()->command_channel()) {
    return;
  }
  hci()->command_channel()->RemoveEventHandler(
      set_terminated_event_handler_id_);
  // TODO(fxbug.dev/42063496): This will only cancel one advertisement, after
  // which the SequentialCommandRunner will have been destroyed and no further
  // commands will be sent.
  StopAdvertising();
}

EmbossCommandPacket ExtendedLowEnergyAdvertiser::BuildEnablePacket(
    const DeviceAddress& address,
    pw::bluetooth::emboss::GenericEnableParam enable) {
  // We only enable or disable a single address at a time. The multiply by 1 is
  // set explicitly to show that data[] within
  // LESetExtendedAdvertisingEnableData is of size 1.
  constexpr size_t kPacketSize =
      pw::bluetooth::emboss::LESetExtendedAdvertisingEnableCommand::
          MinSizeInBytes() +
      (1 * pw::bluetooth::emboss::LESetExtendedAdvertisingEnableData::
               IntrinsicSizeInBytes());
  auto packet = hci::EmbossCommandPacket::New<
      pw::bluetooth::emboss::LESetExtendedAdvertisingEnableCommandWriter>(
      hci_spec::kLESetExtendedAdvertisingEnable, kPacketSize);
  auto packet_view = packet.view_t();
  packet_view.enable().Write(enable);
  packet_view.num_sets().Write(1);

  std::optional<hci_spec::AdvertisingHandle> handle =
      advertising_handle_map_.GetHandle(address);
  BT_ASSERT(handle);

  packet_view.data()[0].advertising_handle().Write(handle.value());
  packet_view.data()[0].duration().Write(hci_spec::kNoAdvertisingDuration);
  packet_view.data()[0].max_extended_advertising_events().Write(
      hci_spec::kNoMaxExtendedAdvertisingEvents);

  return packet;
}

CommandChannel::CommandPacketVariant
ExtendedLowEnergyAdvertiser::BuildSetAdvertisingParams(
    const DeviceAddress& address,
    pw::bluetooth::emboss::LEAdvertisingType type,
    pw::bluetooth::emboss::LEOwnAddressType own_address_type,
    AdvertisingIntervalRange interval) {
  constexpr size_t kPacketSize = pw::bluetooth::emboss::
      LESetExtendedAdvertisingParametersV1CommandView::SizeInBytes();
  auto packet = hci::EmbossCommandPacket::New<
      pw::bluetooth::emboss::LESetExtendedAdvertisingParametersV1CommandWriter>(
      hci_spec::kLESetExtendedAdvertisingParameters, kPacketSize);
  auto packet_view = packet.view_t();

  // advertising handle
  std::optional<hci_spec::AdvertisingHandle> handle =
      advertising_handle_map_.MapHandle(address);
  if (!handle) {
    bt_log(WARN,
           "hci-le",
           "could not allocate a new advertising handle for address: %s (all "
           "in use)",
           bt_str(address));
    return std::unique_ptr<CommandPacket>();
  }
  packet_view.advertising_handle().Write(handle.value());

  // advertising event properties
  std::optional<hci_spec::AdvertisingEventBits> bits =
      hci_spec::AdvertisingTypeToEventBits(type);
  if (!bits) {
    bt_log(WARN,
           "hci-le",
           "could not generate event bits for type: %hhu",
           static_cast<unsigned char>(type));
    return std::unique_ptr<CommandPacket>();
  }
  uint16_t properties = bits.value();
  packet_view.advertising_event_properties().BackingStorage().WriteUInt(
      properties);

  // advertising interval, NOTE: LE advertising parameters allow for up to 3
  // octets (10 ms to 10428 s) to configure an advertising interval. However, we
  // expose only the recommended advertising interval configurations to users,
  // as specified in the Bluetooth Spec Volume 3, Part C, Appendix A. These
  // values are expressed as uint16_t so we simply copy them (taking care of
  // endianness) into the 3 octets as is.
  packet_view.primary_advertising_interval_min().Write(interval.min());
  packet_view.primary_advertising_interval_max().Write(interval.max());

  // advertise on all channels
  packet_view.primary_advertising_channel_map().channel_37().Write(true);
  packet_view.primary_advertising_channel_map().channel_38().Write(true);
  packet_view.primary_advertising_channel_map().channel_39().Write(true);

  packet_view.own_address_type().Write(own_address_type);
  packet_view.advertising_filter_policy().Write(
      pw::bluetooth::emboss::LEAdvertisingFilterPolicy::ALLOW_ALL);
  packet_view.advertising_tx_power().Write(
      hci_spec::kLEExtendedAdvertisingTxPowerNoPreference);
  packet_view.scan_request_notification_enable().Write(
      pw::bluetooth::emboss::GenericEnableParam::DISABLE);

  // TODO(fxbug.dev/42161929): using legacy PDUs requires advertisements on the
  // LE 1M PHY.
  packet_view.primary_advertising_phy().Write(
      pw::bluetooth::emboss::LEPrimaryAdvertisingPHY::LE_1M);
  packet_view.secondary_advertising_phy().Write(
      pw::bluetooth::emboss::LESecondaryAdvertisingPHY::LE_1M);

  // Payload values were initialized to zero above. By not setting the values
  // for the following fields, we are purposely ignoring them:
  //
  // advertising_sid: We use only legacy PDUs, the controller ignores this field
  // in that case peer_address: We don't support directed advertising yet
  // peer_address_type: We don't support directed advertising yet
  // secondary_adv_max_skip: We use only legacy PDUs, the controller ignores
  // this field in that case

  return packet;
}

CommandChannel::CommandPacketVariant
ExtendedLowEnergyAdvertiser::BuildSetAdvertisingData(
    const DeviceAddress& address, const AdvertisingData& data, AdvFlags flags) {
  AdvertisingData adv_data;
  data.Copy(&adv_data);
  if (staged_advertising_parameters_.include_tx_power_level) {
    adv_data.SetTxPower(staged_advertising_parameters_.selected_tx_power_level);
  }
  size_t block_size = adv_data.CalculateBlockSize(/*include_flags=*/true);

  size_t kPayloadSize =
      pw::bluetooth::emboss::LESetExtendedAdvertisingDataCommandView::
          MinSizeInBytes()
              .Read() +
      block_size;
  auto packet = EmbossCommandPacket::New<
      pw::bluetooth::emboss::LESetExtendedAdvertisingDataCommandWriter>(
      hci_spec::kLESetExtendedAdvertisingData, kPayloadSize);
  auto params = packet.view_t();

  // advertising handle
  std::optional<hci_spec::AdvertisingHandle> handle =
      advertising_handle_map_.GetHandle(address);
  BT_ASSERT(handle);
  params.advertising_handle().Write(handle.value());

  // TODO(fxbug.dev/42161929): We support only legacy PDUs and do not support
  // fragmented extended advertising data at this time.
  params.operation().Write(
      pw::bluetooth::emboss::LESetExtendedAdvDataOp::COMPLETE);
  params.fragment_preference().Write(
      pw::bluetooth::emboss::LEExtendedAdvFragmentPreference::
          SHOULD_NOT_FRAGMENT);

  // advertising data
  params.advertising_data_length().Write(static_cast<uint8_t>(block_size));
  MutableBufferView data_view(params.advertising_data().BackingStorage().data(),
                              params.advertising_data_length().Read());
  adv_data.WriteBlock(&data_view, flags);

  return packet;
}

CommandChannel::CommandPacketVariant
ExtendedLowEnergyAdvertiser::BuildUnsetAdvertisingData(
    const DeviceAddress& address) {
  constexpr size_t kPacketSize =
      pw::bluetooth::emboss::LESetExtendedAdvertisingDataCommandView::
          MinSizeInBytes()
              .Read();
  auto packet = EmbossCommandPacket::New<
      pw::bluetooth::emboss::LESetExtendedAdvertisingDataCommandWriter>(
      hci_spec::kLESetExtendedAdvertisingData, kPacketSize);
  auto payload = packet.view_t();

  // advertising handle
  std::optional<hci_spec::AdvertisingHandle> handle =
      advertising_handle_map_.GetHandle(address);
  BT_ASSERT(handle);
  payload.advertising_handle().Write(handle.value());

  // TODO(fxbug.dev/42161929): We support only legacy PDUs and do not support
  // fragmented extended advertising data at this time.
  payload.operation().Write(
      pw::bluetooth::emboss::LESetExtendedAdvDataOp::COMPLETE);
  payload.fragment_preference().Write(
      pw::bluetooth::emboss::LEExtendedAdvFragmentPreference::
          SHOULD_NOT_FRAGMENT);
  payload.advertising_data_length().Write(0);

  return packet;
}

CommandChannel::CommandPacketVariant
ExtendedLowEnergyAdvertiser::BuildSetScanResponse(const DeviceAddress& address,
                                                  const AdvertisingData& data) {
  AdvertisingData scan_rsp;
  data.Copy(&scan_rsp);
  if (staged_advertising_parameters_.include_tx_power_level) {
    scan_rsp.SetTxPower(staged_advertising_parameters_.selected_tx_power_level);
  }
  size_t block_size = scan_rsp.CalculateBlockSize();

  size_t kPayloadSize =
      pw::bluetooth::emboss::LESetExtendedScanResponseDataCommandView::
          MinSizeInBytes()
              .Read() +
      block_size;
  auto packet = EmbossCommandPacket::New<
      pw::bluetooth::emboss::LESetExtendedScanResponseDataCommandWriter>(
      hci_spec::kLESetExtendedScanResponseData, kPayloadSize);
  auto params = packet.view_t();

  // advertising handle
  std::optional<hci_spec::AdvertisingHandle> handle =
      advertising_handle_map_.GetHandle(address);
  BT_ASSERT(handle);
  params.advertising_handle().Write(handle.value());

  // TODO(fxbug.dev/42161929): We support only legacy PDUs and do not support
  // fragmented extended advertising data at this time.
  params.operation().Write(
      pw::bluetooth::emboss::LESetExtendedAdvDataOp::COMPLETE);
  params.fragment_preference().Write(
      pw::bluetooth::emboss::LEExtendedAdvFragmentPreference::
          SHOULD_NOT_FRAGMENT);

  // scan response data
  params.scan_response_data_length().Write(static_cast<uint8_t>(block_size));
  MutableBufferView scan_rsp_view(
      params.scan_response_data().BackingStorage().data(),
      params.scan_response_data_length().Read());
  scan_rsp.WriteBlock(&scan_rsp_view, std::nullopt);

  return packet;
}

CommandChannel::CommandPacketVariant
ExtendedLowEnergyAdvertiser::BuildUnsetScanResponse(
    const DeviceAddress& address) {
  constexpr size_t kPacketSize =
      pw::bluetooth::emboss::LESetExtendedScanResponseDataCommandView::
          MinSizeInBytes()
              .Read();
  auto packet = EmbossCommandPacket::New<
      pw::bluetooth::emboss::LESetExtendedScanResponseDataCommandWriter>(
      hci_spec::kLESetExtendedScanResponseData, kPacketSize);
  auto payload = packet.view_t();

  // advertising handle
  std::optional<hci_spec::AdvertisingHandle> handle =
      advertising_handle_map_.GetHandle(address);
  BT_ASSERT(handle);
  payload.advertising_handle().Write(handle.value());

  // TODO(fxbug.dev/42161929): We support only legacy PDUs and do not support
  // fragmented extended advertising data at this time.
  payload.operation().Write(
      pw::bluetooth::emboss::LESetExtendedAdvDataOp::COMPLETE);
  payload.fragment_preference().Write(
      pw::bluetooth::emboss::LEExtendedAdvFragmentPreference::
          SHOULD_NOT_FRAGMENT);
  payload.scan_response_data_length().Write(0);

  return packet;
}

EmbossCommandPacket ExtendedLowEnergyAdvertiser::BuildRemoveAdvertisingSet(
    const DeviceAddress& address) {
  std::optional<hci_spec::AdvertisingHandle> handle =
      advertising_handle_map_.GetHandle(address);
  BT_ASSERT(handle);
  auto packet = hci::EmbossCommandPacket::New<
      pw::bluetooth::emboss::LERemoveAdvertisingSetCommandWriter>(
      hci_spec::kLERemoveAdvertisingSet);
  auto packet_view = packet.view_t();
  packet_view.advertising_handle().Write(handle.value());

  return packet;
}

void ExtendedLowEnergyAdvertiser::OnSetAdvertisingParamsComplete(
    const EventPacket& event) {
  BT_ASSERT(event.event_code() == hci_spec::kCommandCompleteEventCode);
  BT_ASSERT(
      event.params<hci_spec::CommandCompleteEventParams>().command_opcode ==
      hci_spec::kLESetExtendedAdvertisingParameters);

  Result<> result = event.ToResult();
  if (bt_is_error(result,
                  WARN,
                  "hci-le",
                  "set advertising parameters, error received: %s",
                  bt_str(result))) {
    return;  // full error handling done in super class, can just return here
  }

  auto params = event.return_params<
      hci_spec::LESetExtendedAdvertisingParametersReturnParams>();
  BT_ASSERT(params);

  if (staged_advertising_parameters_.include_tx_power_level) {
    staged_advertising_parameters_.selected_tx_power_level =
        params->selected_tx_power;
  }
}

void ExtendedLowEnergyAdvertiser::StartAdvertising(
    const DeviceAddress& address,
    const AdvertisingData& data,
    const AdvertisingData& scan_rsp,
    AdvertisingOptions options,
    ConnectionCallback connect_callback,
    ResultFunction<> result_callback) {
  // if there is an operation currently in progress, enqueue this operation and
  // we will get to it the next time we have a chance
  if (!hci_cmd_runner().IsReady()) {
    bt_log(INFO,
           "hci-le",
           "hci cmd runner not ready, queuing advertisement commands for now");

    AdvertisingData copied_data;
    data.Copy(&copied_data);

    AdvertisingData copied_scan_rsp;
    scan_rsp.Copy(&copied_scan_rsp);

    op_queue_.push([this,
                    address,
                    data = std::move(copied_data),
                    scan_rsp = std::move(copied_scan_rsp),
                    options,
                    conn_cb = std::move(connect_callback),
                    result_cb = std::move(result_callback)]() mutable {
      StartAdvertising(address,
                       data,
                       scan_rsp,
                       options,
                       std::move(conn_cb),
                       std::move(result_cb));
    });

    return;
  }

  fit::result<HostError> result =
      CanStartAdvertising(address, data, scan_rsp, options);
  if (result.is_error()) {
    result_callback(ToResult(result.error_value()));
    return;
  }

  if (IsAdvertising(address)) {
    bt_log(DEBUG,
           "hci-le",
           "updating existing advertisement for %s",
           bt_str(address));
  }

  std::memset(&staged_advertising_parameters_,
              0,
              sizeof(staged_advertising_parameters_));
  staged_advertising_parameters_.include_tx_power_level =
      options.include_tx_power_level;

  // Core Spec, Volume 4, Part E, Section 7.8.58: "the number of advertising
  // sets that can be supported is not fixed and the Controller can change it at
  // any time. The memory used to store advertising sets can also be used for
  // other purposes."
  //
  // Depending on the memory profile of the controller, a new advertising set
  // may or may not be accepted. We could use
  // HCI_LE_Read_Number_of_Supported_Advertising_Sets to check if the controller
  // has space for another advertising set. However, the value may change after
  // the read and before the addition of the advertising set. Furthermore,
  // sending an extra HCI command increases the latency of our stack. Instead,
  // we simply attempt to add. If the controller is unable to support another
  // advertising set, it will respond with a memory capacity exceeded error.
  StartAdvertisingInternal(address,
                           data,
                           scan_rsp,
                           options.interval,
                           options.flags,
                           std::move(connect_callback),
                           std::move(result_callback));
}

void ExtendedLowEnergyAdvertiser::StopAdvertising() {
  LowEnergyAdvertiser::StopAdvertising();
  advertising_handle_map_.Clear();

  // std::queue doesn't have a clear method so we have to resort to this
  // tomfoolery :(
  decltype(op_queue_) empty;
  std::swap(op_queue_, empty);
}

void ExtendedLowEnergyAdvertiser::StopAdvertising(
    const DeviceAddress& address) {
  // if there is an operation currently in progress, enqueue this operation and
  // we will get to it the next time we have a chance
  if (!hci_cmd_runner().IsReady()) {
    bt_log(
        INFO,
        "hci-le",
        "hci cmd runner not ready, queueing stop advertising command for now");
    op_queue_.push([this, address]() { StopAdvertising(address); });
    return;
  }

  LowEnergyAdvertiser::StopAdvertisingInternal(address);
  advertising_handle_map_.RemoveAddress(address);
}

void ExtendedLowEnergyAdvertiser::OnIncomingConnection(
    hci_spec::ConnectionHandle handle,
    pw::bluetooth::emboss::ConnectionRole role,
    const DeviceAddress& peer_address,
    const hci_spec::LEConnectionParameters& conn_params) {
  // Core Spec Volume 4, Part E, Section 7.8.56: Incoming connections to LE
  // Extended Advertising occur through two events: HCI_LE_Connection_Complete
  // and HCI_LE_Advertising_Set_Terminated. This method is called as a result of
  // the HCI_LE_Connection_Complete event. At this point, we only have a
  // connection handle but don't know the locally advertised address that the
  // connection is for. Until we receive the HCI_LE_Advertising_Set_Terminated
  // event, we stage these parameters.
  staged_connections_map_[handle] = {role, peer_address, conn_params};
}

// The HCI_LE_Advertising_Set_Terminated event contains the mapping between
// connection handle and advertising handle. After the
// HCI_LE_Advertising_Set_Terminated event, we have all the information
// necessary to create a connection object within the Host layer.
CommandChannel::EventCallbackResult
ExtendedLowEnergyAdvertiser::OnAdvertisingSetTerminatedEvent(
    const EventPacket& event) {
  BT_ASSERT(event.event_code() == hci_spec::kLEMetaEventCode);
  BT_ASSERT(event.params<hci_spec::LEMetaEventParams>().subevent_code ==
            hci_spec::kLEAdvertisingSetTerminatedSubeventCode);

  Result<> result = event.ToResult();
  if (bt_is_error(result,
                  ERROR,
                  "hci-le",
                  "advertising set terminated event, error received %s",
                  bt_str(result))) {
    return CommandChannel::EventCallbackResult::kContinue;
  }

  auto params = event.subevent_params<
      hci_spec::LEAdvertisingSetTerminatedSubeventParams>();
  BT_ASSERT(params);

  hci_spec::ConnectionHandle connection_handle = params->connection_handle;
  auto staged_parameters_node =
      staged_connections_map_.extract(connection_handle);

  if (staged_parameters_node.empty()) {
    bt_log(ERROR,
           "hci-le",
           "advertising set terminated event, staged params not available "
           "(handle: %d)",
           params->adv_handle);
    return CommandChannel::EventCallbackResult::kContinue;
  }

  hci_spec::AdvertisingHandle adv_handle = params->adv_handle;
  std::optional<DeviceAddress> opt_local_address =
      advertising_handle_map_.GetAddress(adv_handle);

  // We use the identity address as the local address if we aren't advertising
  // or otherwise don't know about this advertising set. This is obviously
  // wrong. However, the link will be disconnected in that case before it can
  // propagate to higher layers.
  static DeviceAddress identity_address =
      DeviceAddress(DeviceAddress::Type::kLEPublic, {0});
  DeviceAddress local_address = identity_address;
  if (opt_local_address) {
    local_address = opt_local_address.value();
  }

  StagedConnectionParameters staged = staged_parameters_node.mapped();

  CompleteIncomingConnection(connection_handle,
                             staged.role,
                             local_address,
                             staged.peer_address,
                             staged.conn_params);

  std::memset(&staged_advertising_parameters_,
              0,
              sizeof(staged_advertising_parameters_));
  return CommandChannel::EventCallbackResult::kContinue;
}

void ExtendedLowEnergyAdvertiser::OnCurrentOperationComplete() {
  if (op_queue_.empty()) {
    return;  // no more queued operations so nothing to do
  }

  fit::closure closure = std::move(op_queue_.front());
  op_queue_.pop();
  closure();
}

}  // namespace bt::hci
