// 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/testing/test_packets.h"

#include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
#include "pw_bluetooth_sapphire/internal/host/hci-spec/constants.h"
#include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
#include "pw_bluetooth_sapphire/internal/host/hci/bredr_connection_request.h"
#include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"

namespace bt::testing {

namespace hci_android = bt::hci_spec::vendor::android;

// clang-format off
#define COMMAND_STATUS_RSP(opcode, statuscode)                       \
StaticByteBuffer( hci_spec::kCommandStatusEventCode, 0x04,         \
                                (statuscode), 0xF0,                 \
                                LowerBits((opcode)), UpperBits((opcode)))

#define UINT32_TO_LE(bits)                      \
  static_cast<uint32_t>(bits),                  \
  static_cast<uint32_t>(bits) >> CHAR_BIT,      \
  static_cast<uint32_t>(bits) >> 2 * CHAR_BIT,  \
  static_cast<uint32_t>(bits) >> 3 * CHAR_BIT
// clang-format on

DynamicByteBuffer EmptyCommandPacket(hci_spec::OpCode opcode) {
  return DynamicByteBuffer(
      StaticByteBuffer(LowerBits(opcode), UpperBits(opcode), /*length=*/0));
}

DynamicByteBuffer CommandCompletePacket(
    hci_spec::OpCode opcode, pw::bluetooth::emboss::StatusCode status) {
  return DynamicByteBuffer(StaticByteBuffer(hci_spec::kCommandCompleteEventCode,
                                            0x04,  // size
                                            0x01,  // Num HCI command packets
                                            LowerBits(opcode),
                                            UpperBits(opcode),  // Op code
                                            status));
}

DynamicByteBuffer AcceptConnectionRequestPacket(DeviceAddress address) {
  const auto addr = address.value().bytes();
  return DynamicByteBuffer(StaticByteBuffer(
      LowerBits(hci_spec::kAcceptConnectionRequest),
      UpperBits(hci_spec::kAcceptConnectionRequest),
      0x07,  // parameter_total_size (7 bytes)
      addr[0],
      addr[1],
      addr[2],
      addr[3],
      addr[4],
      addr[5],  // peer address
      0x00      // role (become central)
      ));
}

DynamicByteBuffer RejectConnectionRequestPacket(
    DeviceAddress address, pw::bluetooth::emboss::StatusCode reason) {
  const auto addr = address.value().bytes();
  return DynamicByteBuffer(StaticByteBuffer(
      LowerBits(hci_spec::kRejectConnectionRequest),
      UpperBits(hci_spec::kRejectConnectionRequest),
      0x07,  // parameter_total_size (7 bytes)
      addr[0],
      addr[1],
      addr[2],
      addr[3],
      addr[4],
      addr[5],  // peer address
      reason    // reason
      ));
}

DynamicByteBuffer AuthenticationRequestedPacket(
    hci_spec::ConnectionHandle conn) {
  return DynamicByteBuffer(StaticByteBuffer(
      LowerBits(hci_spec::kAuthenticationRequested),
      UpperBits(hci_spec::kAuthenticationRequested),
      0x02,  // parameter_total_size (2 bytes)
      LowerBits(conn),
      UpperBits(conn)  // Connection_Handle
      ));
}

DynamicByteBuffer ConnectionRequestPacket(DeviceAddress address,
                                          hci_spec::LinkType link_type) {
  const auto addr = address.value().bytes();
  return DynamicByteBuffer(StaticByteBuffer(
      hci_spec::kConnectionRequestEventCode,
      0x0A,  // parameter_total_size (10 byte payload)
      addr[0],
      addr[1],
      addr[2],
      addr[3],
      addr[4],
      addr[5],  // peer address
      0x00,
      0x1F,
      0x00,      // class_of_device (unspecified)
      link_type  // link_type
      ));
}

DynamicByteBuffer CreateConnectionPacket(DeviceAddress address) {
  auto addr = address.value().bytes();
  return DynamicByteBuffer(StaticByteBuffer(
      LowerBits(hci_spec::kCreateConnection),
      UpperBits(hci_spec::kCreateConnection),
      0x0d,  // parameter_total_size (13 bytes)
      addr[0],
      addr[1],
      addr[2],
      addr[3],
      addr[4],
      addr[5],                                // peer address
      LowerBits(hci::kEnableAllPacketTypes),  // allowable packet types
      UpperBits(hci::kEnableAllPacketTypes),  // allowable packet types
      0x02,                                   // page_scan_repetition_mode (R2)
      0x00,                                   // reserved
      0x00,
      0x00,  // clock_offset
      0x00   // allow_role_switch (don't)
      ));
}

DynamicByteBuffer ConnectionCompletePacket(
    DeviceAddress address,
    hci_spec::ConnectionHandle conn,
    pw::bluetooth::emboss::StatusCode status) {
  auto addr = address.value().bytes();
  return DynamicByteBuffer(StaticByteBuffer(
      hci_spec::kConnectionCompleteEventCode,
      0x0B,    // parameter_total_size (11 byte payload)
      status,  // status
      LowerBits(conn),
      UpperBits(conn),  // Little-Endian Connection_handle
      addr[0],
      addr[1],
      addr[2],
      addr[3],
      addr[4],
      addr[5],  // peer address
      0x01,     // link_type (ACL)
      0x00      // encryption not enabled
      ));
}

DynamicByteBuffer DisconnectPacket(hci_spec::ConnectionHandle conn,
                                   pw::bluetooth::emboss::StatusCode reason) {
  return DynamicByteBuffer(StaticByteBuffer(
      LowerBits(hci_spec::kDisconnect),
      UpperBits(hci_spec::kDisconnect),
      0x03,  // parameter_total_size (3 bytes)
      LowerBits(conn),
      UpperBits(conn),  // Little-Endian Connection_handle
      reason            // Reason
      ));
}

DynamicByteBuffer DisconnectStatusResponsePacket() {
  return DynamicByteBuffer(COMMAND_STATUS_RSP(
      hci_spec::kDisconnect, pw::bluetooth::emboss::StatusCode::SUCCESS));
}

DynamicByteBuffer DisconnectionCompletePacket(
    hci_spec::ConnectionHandle conn, pw::bluetooth::emboss::StatusCode reason) {
  return DynamicByteBuffer(StaticByteBuffer(
      hci_spec::kDisconnectionCompleteEventCode,
      0x04,  // parameter_total_size (4 bytes)
      pw::bluetooth::emboss::StatusCode::SUCCESS,  // status
      LowerBits(conn),
      UpperBits(conn),  // Little-Endian Connection_handle
      reason            // Reason
      ));
}

DynamicByteBuffer EncryptionChangeEventPacket(
    pw::bluetooth::emboss::StatusCode status_code,
    hci_spec::ConnectionHandle conn,
    hci_spec::EncryptionStatus encryption_enabled) {
  return DynamicByteBuffer(StaticByteBuffer(
      hci_spec::kEncryptionChangeEventCode,
      0x04,         // parameter_total_size (4 bytes)
      status_code,  // status
      LowerBits(conn),
      UpperBits(conn),  // Little-Endian Connection_Handle
      static_cast<uint8_t>(encryption_enabled)  // Encryption_Enabled
      ));
}

DynamicByteBuffer EnhancedAcceptSynchronousConnectionRequestPacket(
    DeviceAddress peer_address,
    bt::StaticPacket<
        pw::bluetooth::emboss::SynchronousConnectionParametersWriter> params) {
  auto packet = hci::EmbossCommandPacket::New<
      pw::bluetooth::emboss::
          EnhancedAcceptSynchronousConnectionRequestCommandWriter>(
      hci_spec::kEnhancedAcceptSynchronousConnectionRequest);
  auto view = packet.view_t();

  view.bd_addr().CopyFrom(peer_address.value().view());
  view.connection_parameters().CopyFrom(params.view());

  return DynamicByteBuffer(packet.data());
}

DynamicByteBuffer EnhancedSetupSynchronousConnectionPacket(
    hci_spec::ConnectionHandle conn,
    bt::StaticPacket<
        pw::bluetooth::emboss::SynchronousConnectionParametersWriter> params) {
  auto packet = hci::EmbossCommandPacket::New<
      pw::bluetooth::emboss::EnhancedSetupSynchronousConnectionCommandWriter>(
      hci_spec::kEnhancedSetupSynchronousConnection);

  auto view = packet.view_t();
  view.connection_handle().Write(conn);
  view.connection_parameters().CopyFrom(params.view());

  return DynamicByteBuffer(packet.data());
}

DynamicByteBuffer NumberOfCompletedPacketsPacket(
    hci_spec::ConnectionHandle conn, uint16_t num_packets) {
  return DynamicByteBuffer(StaticByteBuffer(
      0x13,
      0x05,  // Number Of Completed Packet HCI event header, parameters length
      0x01,  // Number of handles
      LowerBits(conn),
      UpperBits(conn),
      LowerBits(num_packets),
      UpperBits(num_packets)));
}

DynamicByteBuffer CommandStatusPacket(
    hci_spec::OpCode op_code, pw::bluetooth::emboss::StatusCode status_code) {
  return DynamicByteBuffer(
      StaticByteBuffer(hci_spec::kCommandStatusEventCode,
                       0x04,  // parameter size (4 bytes)
                       status_code,
                       0xF0,  // number of HCI command packets allowed to be
                              // sent to controller (240)
                       LowerBits(op_code),
                       UpperBits(op_code)));
}

DynamicByteBuffer RemoteNameRequestPacket(DeviceAddress address) {
  auto addr = address.value().bytes();
  return DynamicByteBuffer(StaticByteBuffer(
      LowerBits(hci_spec::kRemoteNameRequest),
      UpperBits(hci_spec::kRemoteNameRequest),
      0x0a,  // parameter_total_size (10 bytes)
      addr[0],
      addr[1],
      addr[2],
      addr[3],
      addr[4],
      addr[5],  // peer address
      0x00,     // page_scan_repetition_mode (R0)
      0x00,     // reserved
      0x00,
      0x00  // clock_offset
      ));
}

DynamicByteBuffer RemoteNameRequestCompletePacket(DeviceAddress address,
                                                  const std::string& name) {
  auto addr = address.value().bytes();
  auto event = DynamicByteBuffer(
      pw::bluetooth::emboss::RemoteNameRequestCompleteEventView::
          IntrinsicSizeInBytes()
              .Read());
  event.SetToZeros();
  const StaticByteBuffer header(
      hci_spec::kRemoteNameRequestCompleteEventCode,
      0xff,                                        // parameter_total_size (255)
      pw::bluetooth::emboss::StatusCode::SUCCESS,  // status
      addr[0],
      addr[1],
      addr[2],
      addr[3],
      addr[4],
      addr[5]  // peer address
  );
  header.Copy(&event);
  event.Write(reinterpret_cast<const uint8_t*>(name.data()),
              name.size(),
              header.size());
  return event;
}

DynamicByteBuffer ReadRemoteVersionInfoPacket(hci_spec::ConnectionHandle conn) {
  return DynamicByteBuffer(StaticByteBuffer(
      LowerBits(hci_spec::kReadRemoteVersionInfo),
      UpperBits(hci_spec::kReadRemoteVersionInfo),
      0x02,  // Parameter_total_size (2 bytes)
      LowerBits(conn),
      UpperBits(conn)  // Little-Endian Connection_handle
      ));
}

DynamicByteBuffer ReadRemoteVersionInfoCompletePacket(
    hci_spec::ConnectionHandle conn) {
  return DynamicByteBuffer(StaticByteBuffer(
      hci_spec::kReadRemoteVersionInfoCompleteEventCode,
      0x08,  // parameter_total_size (8 bytes)
      pw::bluetooth::emboss::StatusCode::SUCCESS,  // status
      LowerBits(conn),
      UpperBits(conn),  // Little-Endian Connection_handle
      pw::bluetooth::emboss::CoreSpecificationVersion::V4_2,  // version
      0xE0,
      0x00,  // company_identifier (Google)
      0xAD,
      0xDE  // subversion (anything)
      ));
}

DynamicByteBuffer ReadRemoteSupportedFeaturesPacket(
    hci_spec::ConnectionHandle conn) {
  return DynamicByteBuffer(
      StaticByteBuffer(LowerBits(hci_spec::kReadRemoteSupportedFeatures),
                       UpperBits(hci_spec::kReadRemoteSupportedFeatures),
                       0x02,             // parameter_total_size (2 bytes)
                       LowerBits(conn),  // Little-Endian Connection_handle
                       UpperBits(conn)));
}

DynamicByteBuffer ReadRemoteSupportedFeaturesCompletePacket(
    hci_spec::ConnectionHandle conn, bool extended_features) {
  return DynamicByteBuffer(StaticByteBuffer(
      hci_spec::kReadRemoteSupportedFeaturesCompleteEventCode,
      0x0B,  // parameter_total_size (11 bytes)
      pw::bluetooth::emboss::StatusCode::SUCCESS,  // status
      LowerBits(conn),
      UpperBits(conn),  // Little-Endian Connection_handle
      0xFF,
      0x00,
      0x00,
      0x00,
      0x02,
      0x00,
      0x00,
      (extended_features ? 0x80 : 0x00)
      // lmp_features
      // Set: 3 slot packets, 5 slot packets, Encryption,
      // Timing Accuracy, Role Switch, Hold Mode, Sniff Mode,
      // LE Supported Extended Features if enabled
      ));
}

DynamicByteBuffer RejectSynchronousConnectionRequest(
    DeviceAddress address, pw::bluetooth::emboss::StatusCode status_code) {
  auto addr_bytes = address.value().bytes();
  return DynamicByteBuffer(StaticByteBuffer(
      LowerBits(hci_spec::kRejectSynchronousConnectionRequest),
      UpperBits(hci_spec::kRejectSynchronousConnectionRequest),
      0x07,  // parameter total size
      addr_bytes[0],
      addr_bytes[1],
      addr_bytes[2],
      addr_bytes[3],
      addr_bytes[4],
      addr_bytes[5],  // peer address
      status_code     // reason
      ));
}

DynamicByteBuffer RoleChangePacket(DeviceAddress address,
                                   pw::bluetooth::emboss::ConnectionRole role,
                                   pw::bluetooth::emboss::StatusCode status) {
  auto addr_bytes = address.value().bytes();
  return DynamicByteBuffer(StaticByteBuffer(hci_spec::kRoleChangeEventCode,
                                            0x08,    // parameter_total_size
                                            status,  // status
                                            addr_bytes[0],
                                            addr_bytes[1],
                                            addr_bytes[2],
                                            addr_bytes[3],
                                            addr_bytes[4],
                                            addr_bytes[5],  // peer address
                                            role));
}

DynamicByteBuffer SetConnectionEncryption(hci_spec::ConnectionHandle conn,
                                          bool enable) {
  return DynamicByteBuffer(
      StaticByteBuffer(LowerBits(hci_spec::kSetConnectionEncryption),
                       UpperBits(hci_spec::kSetConnectionEncryption),
                       0x03,  // parameter total size (3 bytes)
                       LowerBits(conn),
                       UpperBits(conn),
                       static_cast<uint8_t>(enable)));
}

DynamicByteBuffer SynchronousConnectionCompletePacket(
    hci_spec::ConnectionHandle conn,
    DeviceAddress address,
    hci_spec::LinkType link_type,
    pw::bluetooth::emboss::StatusCode status) {
  auto addr_bytes = address.value().bytes();
  return DynamicByteBuffer(StaticByteBuffer(
      hci_spec::kSynchronousConnectionCompleteEventCode,
      0x11,  // parameter_total_size (17 bytes)
      status,
      LowerBits(conn),
      UpperBits(conn),
      addr_bytes[0],
      addr_bytes[1],
      addr_bytes[2],
      addr_bytes[3],
      addr_bytes[4],
      addr_bytes[5],
      link_type,  // peer address
      0x00,       // transmission interval
      0x00,       // retransmission window
      0x00,
      0x00,  // rx packet length
      0x00,
      0x00,  // tx packet length
      0x00   // coding format
      ));
}

DynamicByteBuffer LEReadRemoteFeaturesPacket(hci_spec::ConnectionHandle conn) {
  return DynamicByteBuffer(
      StaticByteBuffer(LowerBits(hci_spec::kLEReadRemoteFeatures),
                       UpperBits(hci_spec::kLEReadRemoteFeatures),
                       0x02,             // parameter_total_size (2 bytes)
                       LowerBits(conn),  // Little-Endian Connection_handle
                       UpperBits(conn)));
}

DynamicByteBuffer LEReadRemoteFeaturesCompletePacket(
    hci_spec::ConnectionHandle conn,
    hci_spec::LESupportedFeatures le_features) {
  const BufferView features(&le_features, sizeof(le_features));
  return DynamicByteBuffer(
      StaticByteBuffer(hci_spec::kLEMetaEventCode,
                       0x0c,  // parameter total size (12 bytes)
                       hci_spec::kLEReadRemoteFeaturesCompleteSubeventCode,
                       pw::bluetooth::emboss::StatusCode::SUCCESS,  // status
                       // Little-Endian connection handle
                       LowerBits(conn),
                       UpperBits(conn),
                       // bit mask of LE features
                       features[0],
                       features[1],
                       features[2],
                       features[3],
                       features[4],
                       features[5],
                       features[6],
                       features[7]));
}

DynamicByteBuffer LEStartEncryptionPacket(hci_spec::ConnectionHandle conn,
                                          uint64_t random_number,
                                          uint16_t encrypted_diversifier,
                                          UInt128 ltk) {
  const BufferView rand(&random_number, sizeof(random_number));
  return DynamicByteBuffer(
      StaticByteBuffer(LowerBits(hci_spec::kLEStartEncryption),
                       UpperBits(hci_spec::kLEStartEncryption),
                       0x1c,  // parameter total size (28 bytes)
                       LowerBits(conn),
                       UpperBits(conn),  // Connection_handle
                       rand[0],
                       rand[1],
                       rand[2],
                       rand[3],
                       rand[4],
                       rand[5],
                       rand[6],
                       rand[7],
                       LowerBits(encrypted_diversifier),
                       UpperBits(encrypted_diversifier),
                       // LTK
                       ltk[0],
                       ltk[1],
                       ltk[2],
                       ltk[3],
                       ltk[4],
                       ltk[5],
                       ltk[6],
                       ltk[7],
                       ltk[8],
                       ltk[9],
                       ltk[10],
                       ltk[11],
                       ltk[12],
                       ltk[13],
                       ltk[14],
                       ltk[15]));
}

DynamicByteBuffer ReadRemoteExtended1Packet(hci_spec::ConnectionHandle conn) {
  return DynamicByteBuffer(StaticByteBuffer(
      LowerBits(hci_spec::kReadRemoteExtendedFeatures),
      UpperBits(hci_spec::kReadRemoteExtendedFeatures),
      0x03,             // parameter_total_size (3 bytes)
      LowerBits(conn),  // Little-Endian Connection_handle
      UpperBits(conn),
      0x01  // page_number (1)
      ));
}

DynamicByteBuffer ReadRemoteExtended1CompletePacket(
    hci_spec::ConnectionHandle conn) {
  return DynamicByteBuffer(StaticByteBuffer(
      hci_spec::kReadRemoteExtendedFeaturesCompleteEventCode,
      0x0D,  // parameter_total_size (13 bytes)
      pw::bluetooth::emboss::StatusCode::SUCCESS,  // status
      LowerBits(conn),
      UpperBits(conn),  // Little-Endian Connection_handle
      0x01,             // page_number
      0x03,             // max_page_number (3 pages)
      0x0F,
      0x00,
      0x00,
      0x00,
      0x02,
      0x00,
      0x00,
      0x00
      // lmp_features (page 1)
      // Set: Secure Simple Pairing (Host Support), LE Supported (Host),
      // SimultaneousLEAndBREDR, Secure Connections (Host Support)
      ));
}

DynamicByteBuffer ReadRemoteExtended2Packet(hci_spec::ConnectionHandle conn) {
  return DynamicByteBuffer(StaticByteBuffer(
      LowerBits(hci_spec::kReadRemoteExtendedFeatures),
      UpperBits(hci_spec::kReadRemoteExtendedFeatures),
      0x03,  // parameter_total_size (3 bytes)
      LowerBits(conn),
      UpperBits(conn),  // Little-Endian Connection_handle
      0x02              // page_number (2)
      ));
}

DynamicByteBuffer ReadRemoteExtended2CompletePacket(
    hci_spec::ConnectionHandle conn) {
  return DynamicByteBuffer(StaticByteBuffer(
      hci_spec::kReadRemoteExtendedFeaturesCompleteEventCode,
      0x0D,  // parameter_total_size (13 bytes)
      pw::bluetooth::emboss::StatusCode::SUCCESS,  // status
      LowerBits(conn),
      UpperBits(conn),  // Little-Endian Connection_handle
      0x02,             // page_number
      0x03,             // max_page_number (3 pages)
      0x00,
      0x00,
      0x00,
      0x00,
      0x02,
      0x00,
      0xFF,
      0x00
      // lmp_features  - All the bits should be ignored.
      ));
}

DynamicByteBuffer WriteAutomaticFlushTimeoutPacket(
    hci_spec::ConnectionHandle conn, uint16_t flush_timeout) {
  return DynamicByteBuffer(StaticByteBuffer(
      LowerBits(hci_spec::kWriteAutomaticFlushTimeout),
      UpperBits(hci_spec::kWriteAutomaticFlushTimeout),
      0x04,  // parameter_total_size (4 bytes)
      LowerBits(conn),
      UpperBits(conn),  // Little-Endian Connection_Handle
      LowerBits(flush_timeout),
      UpperBits(flush_timeout)  // Little-Endian Flush_Timeout
      ));
}

DynamicByteBuffer WritePageTimeoutPacket(uint16_t page_timeout) {
  return DynamicByteBuffer(StaticByteBuffer(
      LowerBits(hci_spec::kWritePageTimeout),
      UpperBits(hci_spec::kWritePageTimeout),
      0x02,  // parameter_total_size (2 bytes)
      LowerBits(page_timeout),
      UpperBits(page_timeout)  // Little-Endian Page_Timeout
      ));
}

DynamicByteBuffer ScoDataPacket(
    hci_spec::ConnectionHandle conn,
    hci_spec::SynchronousDataPacketStatusFlag flag,
    const BufferView& payload,
    std::optional<uint8_t> payload_length_override) {
  // Flag is bits 4-5 in the higher octet of |handle_and_flags|, i.e.
  // 0b00xx000000000000.
  conn |= static_cast<uint8_t>(flag) << 12;
  StaticByteBuffer header(
      LowerBits(conn),
      UpperBits(conn),
      payload_length_override ? *payload_length_override : payload.size());
  DynamicByteBuffer out(header.size() + payload.size());
  header.Copy(&out);
  MutableBufferView payload_view = out.mutable_view(header.size());
  payload.Copy(&payload_view);
  return out;
}

DynamicByteBuffer StartA2dpOffloadRequest(
    const l2cap::A2dpOffloadManager::Configuration& config,
    hci_spec::ConnectionHandle connection_handle,
    l2cap::ChannelId l2cap_channel_id,
    uint16_t l2cap_mtu_size) {
  uint8_t
      codec_information_bytes[sizeof(hci_android::A2dpOffloadCodecInformation)];
  memset(codec_information_bytes, 0, sizeof(codec_information_bytes));

  switch (config.codec) {
    case hci_android::A2dpCodecType::kSbc:
      codec_information_bytes[0] =
          config.codec_information.sbc.blocklen_subbands_alloc_method;
      codec_information_bytes[1] =
          config.codec_information.sbc.min_bitpool_value;
      codec_information_bytes[2] =
          config.codec_information.sbc.max_bitpool_value;
      codec_information_bytes[3] =
          config.codec_information.sbc.sampling_freq_channel_mode;
      break;
    case hci_android::A2dpCodecType::kAac:
      codec_information_bytes[0] = config.codec_information.aac.object_type;
      codec_information_bytes[1] =
          static_cast<uint8_t>(config.codec_information.aac.variable_bit_rate);
      break;
    case hci_android::A2dpCodecType::kLdac:
      codec_information_bytes[0] =
          static_cast<uint32_t>(config.codec_information.ldac.vendor_id),
      codec_information_bytes[1] =
          static_cast<uint32_t>(config.codec_information.ldac.vendor_id) >>
          CHAR_BIT,
      codec_information_bytes[2] =
          static_cast<uint32_t>(config.codec_information.ldac.vendor_id) >>
          2 * CHAR_BIT,
      codec_information_bytes[3] =
          static_cast<uint32_t>(config.codec_information.ldac.vendor_id) >>
          3 * CHAR_BIT,
      codec_information_bytes[4] =
          LowerBits(config.codec_information.ldac.codec_id);
      codec_information_bytes[5] =
          UpperBits(config.codec_information.ldac.codec_id);
      codec_information_bytes[6] =
          static_cast<uint8_t>(config.codec_information.ldac.bitrate_index);
      codec_information_bytes[7] =
          static_cast<uint8_t>(config.codec_information.ldac.ldac_channel_mode);
      break;
    default:
      break;
  }

  return DynamicByteBuffer(StaticByteBuffer(
      // clang-format off
      LowerBits(hci_android::kA2dpOffloadCommand), UpperBits(hci_android::kA2dpOffloadCommand),
      0x39,  // parameter_total_size (57 bytes)
      hci_android::kStartA2dpOffloadCommandSubopcode,
      UINT32_TO_LE(config.codec),
      LowerBits(config.max_latency), UpperBits(config.max_latency),
      config.scms_t_enable.enabled, config.scms_t_enable.header,
      UINT32_TO_LE(config.sampling_frequency),
      config.bits_per_sample,
      config.channel_mode,
      UINT32_TO_LE(config.encoded_audio_bit_rate),
      LowerBits(connection_handle), UpperBits(connection_handle),
      LowerBits(l2cap_channel_id), UpperBits(l2cap_channel_id),
      LowerBits(l2cap_mtu_size), UpperBits(l2cap_mtu_size),
      codec_information_bytes[0], codec_information_bytes[1], codec_information_bytes[2],
      codec_information_bytes[3], codec_information_bytes[4], codec_information_bytes[5],
      codec_information_bytes[6], codec_information_bytes[7], codec_information_bytes[8],
      codec_information_bytes[9], codec_information_bytes[10], codec_information_bytes[11],
      codec_information_bytes[12], codec_information_bytes[13], codec_information_bytes[14],
      codec_information_bytes[15], codec_information_bytes[16], codec_information_bytes[17],
      codec_information_bytes[18], codec_information_bytes[19], codec_information_bytes[20],
      codec_information_bytes[21], codec_information_bytes[22], codec_information_bytes[23],
      codec_information_bytes[24], codec_information_bytes[25], codec_information_bytes[26],
      codec_information_bytes[27], codec_information_bytes[28], codec_information_bytes[29],
      codec_information_bytes[30], codec_information_bytes[31]));
  // clang-format on
}

DynamicByteBuffer StopA2dpOffloadRequest() {
  return DynamicByteBuffer(StaticByteBuffer(
      // clang-format off
      LowerBits(hci_android::kA2dpOffloadCommand), UpperBits(hci_android::kA2dpOffloadCommand),
      0x01,  // parameter_total_size (1 byte)
      hci_android::kStopA2dpOffloadCommandSubopcode));
  // clang-format on
}

}  // namespace bt::testing
