// Copyright 2021 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 "gatt2_remote_service_server.h"

#include <measure_tape/hlcpp/hlcpp_measure_tape_for_read_by_type_result.h>

#include "src/connectivity/bluetooth/core/bt-host/att/att.h"
#include "src/connectivity/bluetooth/core/bt-host/common/identifier.h"
#include "src/connectivity/bluetooth/core/bt-host/fidl/helpers.h"

namespace fbg = fuchsia::bluetooth::gatt2;
namespace measure_fbg = measure_tape::fuchsia::bluetooth::gatt2;

namespace bthost {
namespace {

bt::att::ResultFunction<> MakeStatusCallback(
    bt::PeerId peer_id, const char* request_name, fbg::Handle fidl_handle,
    fit::function<void(fpromise::result<void, fbg::Error>)> callback) {
  return [peer_id, fidl_handle, callback = std::move(callback),
          request_name](bt::att::Result<> status) {
    if (bt_is_error(status, INFO, "fidl", "%s: error (peer: %s, handle: 0x%lX)", request_name,
                    bt_str(peer_id), fidl_handle.value)) {
      callback(fpromise::error(fidl_helpers::AttErrorToGattFidlError(status.error_value())));
      return;
    }

    callback(fpromise::ok());
  };
}

fbg::Characteristic CharacteristicToFidl(
    const bt::gatt::CharacteristicData& characteristic,
    const std::map<bt::gatt::DescriptorHandle, bt::gatt::DescriptorData>& descriptors) {
  fbg::Characteristic fidl_char;
  fidl_char.set_handle(fbg::Handle{characteristic.value_handle});
  fidl_char.set_type(fuchsia::bluetooth::Uuid{characteristic.type.value()});

  // The FIDL property bitfield combines the properties and extended properties bits.
  // We mask away the kExtendedProperties property.
  constexpr uint8_t kRemoveExtendedPropertiesMask = 0x7F;
  uint16_t fidl_properties =
      static_cast<uint16_t>(characteristic.properties & kRemoveExtendedPropertiesMask);
  if (characteristic.extended_properties) {
    if (*characteristic.extended_properties & bt::gatt::ExtendedProperty::kReliableWrite) {
      fidl_properties |= static_cast<uint16_t>(fbg::CharacteristicPropertyBits::RELIABLE_WRITE);
    }
    if (*characteristic.extended_properties & bt::gatt::ExtendedProperty::kWritableAuxiliaries) {
      fidl_properties |=
          static_cast<uint16_t>(fbg::CharacteristicPropertyBits::WRITABLE_AUXILIARIES);
    }
  }
  fidl_char.set_properties(static_cast<uint32_t>(fidl_properties));

  if (!descriptors.empty()) {
    std::vector<fbg::Descriptor> fidl_descriptors;
    for (const auto& [handle, data] : descriptors) {
      fbg::Descriptor fidl_descriptor;
      fidl_descriptor.set_handle(fbg::Handle{handle.value});
      fidl_descriptor.set_type(fuchsia::bluetooth::Uuid{data.type.value()});
      fidl_descriptors.push_back(std::move(fidl_descriptor));
    }
    fidl_char.set_descriptors(std::move(fidl_descriptors));
  }

  return fidl_char;
}

// Returned result is supposed to match Read{Characteristic, Descriptor}Callback (result type is
// converted by FIDL move constructor).
[[nodiscard]] fpromise::result<::fuchsia::bluetooth::gatt2::ReadValue,
                               ::fuchsia::bluetooth::gatt2::Error>
ReadResultToFidl(bt::PeerId peer_id, fbg::Handle handle, bt::att::Result<> status,
                 const bt::ByteBuffer& value, bool maybe_truncated, const char* request) {
  if (bt_is_error(status, INFO, "fidl", "%s: error (peer: %s, handle: 0x%lX)", request,
                  bt_str(peer_id), handle.value)) {
    return fpromise::error(fidl_helpers::AttErrorToGattFidlError(status.error_value()));
  }

  fbg::ReadValue fidl_value;
  fidl_value.set_handle(handle);
  fidl_value.set_value(value.ToVector());
  fidl_value.set_maybe_truncated(maybe_truncated);
  return fpromise::ok(std::move(fidl_value));
}

void FillInReadOptionsDefaults(fbg::ReadOptions& options) {
  if (options.is_short_read()) {
    return;
  }
  if (!options.long_read().has_offset()) {
    options.long_read().set_offset(0);
  }
  if (!options.long_read().has_max_bytes()) {
    options.long_read().set_max_bytes(fbg::MAX_VALUE_LENGTH);
  }
}

void FillInDefaultWriteOptions(fbg::WriteOptions& options) {
  if (!options.has_write_mode()) {
    *options.mutable_write_mode() = fbg::WriteMode::DEFAULT;
  }
  if (!options.has_offset()) {
    *options.mutable_offset() = 0;
  }
}

bt::gatt::ReliableMode ReliableModeFromFidl(const fbg::WriteMode& mode) {
  return mode == fbg::WriteMode::RELIABLE ? bt::gatt::ReliableMode::kEnabled
                                          : bt::gatt::ReliableMode::kDisabled;
}

}  // namespace

Gatt2RemoteServiceServer::Gatt2RemoteServiceServer(
    fbl::RefPtr<bt::gatt::RemoteService> service, fxl::WeakPtr<bt::gatt::GATT> gatt,
    bt::PeerId peer_id, fidl::InterfaceRequest<fuchsia::bluetooth::gatt2::RemoteService> request)
    : GattServerBase(gatt, this, std::move(request)),
      service_(std::move(service)),
      peer_id_(peer_id),
      weak_ptr_factory_(this) {}

Gatt2RemoteServiceServer::~Gatt2RemoteServiceServer() {
  // Disable all notifications to prevent leaks.
  for (auto& [_, notifier] : characteristic_notifiers_) {
    service_->DisableNotifications(notifier.characteristic_handle, notifier.handler_id,
                                   /*status_callback=*/[](auto /*status*/) {});
  }
  characteristic_notifiers_.clear();
}

void Gatt2RemoteServiceServer::Close(zx_status_t status) { binding()->Close(status); }

void Gatt2RemoteServiceServer::DiscoverCharacteristics(DiscoverCharacteristicsCallback callback) {
  auto res_cb = [callback = std::move(callback)](
                    bt::att::Result<> status, const bt::gatt::CharacteristicMap& characteristics) {
    if (status.is_error()) {
      callback({});
      return;
    }

    std::vector<fbg::Characteristic> fidl_characteristics;
    for (const auto& [_, characteristic] : characteristics) {
      const auto& [data, descriptors] = characteristic;
      fidl_characteristics.push_back(CharacteristicToFidl(data, descriptors));
    }
    callback(std::move(fidl_characteristics));
  };

  service_->DiscoverCharacteristics(std::move(res_cb));
}

void Gatt2RemoteServiceServer::ReadByType(::fuchsia::bluetooth::Uuid uuid,
                                          ReadByTypeCallback callback) {
  service_->ReadByType(
      fidl_helpers::UuidFromFidl(uuid),
      [self = weak_ptr_factory_.GetWeakPtr(), cb = std::move(callback), func = __FUNCTION__](
          bt::att::Result<> status,
          std::vector<bt::gatt::RemoteService::ReadByTypeResult> results) {
        if (!self) {
          return;
        }

        if (status == ToResult(bt::HostError::kInvalidParameters)) {
          bt_log(WARN, "fidl", "%s: called with invalid parameters (peer: %s)", func,
                 bt_str(self->peer_id_));
          cb(fpromise::error(fbg::Error::INVALID_PARAMETERS));
          return;
        } else if (status.is_error()) {
          cb(fpromise::error(fbg::Error::UNLIKELY_ERROR));
          return;
        }

        const size_t kVectorOverhead = sizeof(fidl_message_header_t) + sizeof(fidl_vector_t);
        const size_t kMaxBytes = ZX_CHANNEL_MAX_MSG_BYTES - kVectorOverhead;
        size_t bytes_used = 0;

        std::vector<fuchsia::bluetooth::gatt2::ReadByTypeResult> fidl_results;
        fidl_results.reserve(results.size());

        for (const bt::gatt::RemoteService::ReadByTypeResult& result : results) {
          fuchsia::bluetooth::gatt2::ReadByTypeResult fidl_result;
          fidl_result.set_handle(fbg::Handle{result.handle.value});
          if (result.result.is_ok()) {
            fbg::ReadValue read_value;
            read_value.set_handle(fbg::Handle{result.handle.value});
            read_value.set_value(result.result.value()->ToVector());
            read_value.set_maybe_truncated(result.maybe_truncated);
            fidl_result.set_value(std::move(read_value));
          } else {
            fidl_result.set_error(
                fidl_helpers::AttErrorToGattFidlError(bt::att::Error(result.result.error_value())));
          }

          measure_fbg::Size result_size = measure_fbg::Measure(fidl_result);
          ZX_ASSERT(result_size.num_handles == 0);
          bytes_used += result_size.num_bytes;

          if (bytes_used > kMaxBytes) {
            cb(fpromise::error(fuchsia::bluetooth::gatt2::Error::TOO_MANY_RESULTS));
            return;
          }

          fidl_results.push_back(std::move(fidl_result));
        }

        cb(fpromise::ok(std::move(fidl_results)));
      });
}

void Gatt2RemoteServiceServer::ReadCharacteristic(fbg::Handle fidl_handle, fbg::ReadOptions options,
                                                  ReadCharacteristicCallback callback) {
  if (!fidl_helpers::IsFidlGattHandleValid(fidl_handle)) {
    callback(fpromise::error(fbg::Error::INVALID_HANDLE));
    return;
  }
  bt::gatt::CharacteristicHandle handle(static_cast<bt::att::Handle>(fidl_handle.value));

  FillInReadOptionsDefaults(options);

  const char* kRequestName = __FUNCTION__;
  bt::gatt::RemoteService::ReadValueCallback read_cb =
      [peer_id = peer_id_, fidl_handle, kRequestName, callback = std::move(callback)](
          bt::att::Result<> status, const bt::ByteBuffer& value, bool maybe_truncated) {
        callback(
            ReadResultToFidl(peer_id, fidl_handle, status, value, maybe_truncated, kRequestName));
      };

  if (options.is_short_read()) {
    service_->ReadCharacteristic(handle, std::move(read_cb));
    return;
  }

  service_->ReadLongCharacteristic(handle, options.long_read().offset(),
                                   options.long_read().max_bytes(), std::move(read_cb));
}

void Gatt2RemoteServiceServer::WriteCharacteristic(fbg::Handle fidl_handle,
                                                   std::vector<uint8_t> value,
                                                   fbg::WriteOptions options,
                                                   WriteCharacteristicCallback callback) {
  if (!fidl_helpers::IsFidlGattHandleValid(fidl_handle)) {
    callback(fpromise::error(fbg::Error::INVALID_HANDLE));
    return;
  }
  bt::gatt::CharacteristicHandle handle(static_cast<bt::att::Handle>(fidl_handle.value));

  FillInDefaultWriteOptions(options);

  bt::att::ResultFunction<> write_cb =
      MakeStatusCallback(peer_id_, __FUNCTION__, fidl_handle, std::move(callback));

  if (options.write_mode() == fbg::WriteMode::WITHOUT_RESPONSE) {
    if (options.offset() != 0) {
      write_cb(bt::ToResult(bt::HostError::kInvalidParameters));
      return;
    }
    service_->WriteCharacteristicWithoutResponse(handle, std::move(value), std::move(write_cb));
    return;
  }

  const uint16_t kMaxShortWriteValueLength =
      service_->att_mtu() - sizeof(bt::att::OpCode) - sizeof(bt::att::WriteRequestParams);
  if (options.offset() == 0 && options.write_mode() == fbg::WriteMode::DEFAULT &&
      value.size() <= kMaxShortWriteValueLength) {
    service_->WriteCharacteristic(handle, std::move(value), std::move(write_cb));
    return;
  }

  service_->WriteLongCharacteristic(handle, options.offset(), std::move(value),
                                    ReliableModeFromFidl(options.write_mode()),
                                    std::move(write_cb));
}

void Gatt2RemoteServiceServer::ReadDescriptor(::fuchsia::bluetooth::gatt2::Handle fidl_handle,
                                              ::fuchsia::bluetooth::gatt2::ReadOptions options,
                                              ReadDescriptorCallback callback) {
  if (!fidl_helpers::IsFidlGattHandleValid(fidl_handle)) {
    callback(fpromise::error(fbg::Error::INVALID_HANDLE));
    return;
  }
  bt::gatt::DescriptorHandle handle(static_cast<bt::att::Handle>(fidl_handle.value));

  FillInReadOptionsDefaults(options);

  const char* kRequestName = __FUNCTION__;
  bt::gatt::RemoteService::ReadValueCallback read_cb =
      [peer_id = peer_id_, fidl_handle, kRequestName, callback = std::move(callback)](
          bt::att::Result<> status, const bt::ByteBuffer& value, bool maybe_truncated) {
        callback(
            ReadResultToFidl(peer_id, fidl_handle, status, value, maybe_truncated, kRequestName));
      };

  if (options.is_short_read()) {
    service_->ReadDescriptor(handle, std::move(read_cb));
    return;
  }

  service_->ReadLongDescriptor(handle, options.long_read().offset(),
                               options.long_read().max_bytes(), std::move(read_cb));
}

void Gatt2RemoteServiceServer::WriteDescriptor(fbg::Handle fidl_handle, std::vector<uint8_t> value,
                                               fbg::WriteOptions options,
                                               WriteDescriptorCallback callback) {
  if (!fidl_helpers::IsFidlGattHandleValid(fidl_handle)) {
    callback(fpromise::error(fbg::Error::INVALID_HANDLE));
    return;
  }
  bt::gatt::DescriptorHandle handle(static_cast<bt::att::Handle>(fidl_handle.value));

  FillInDefaultWriteOptions(options);

  bt::att::ResultFunction<> write_cb =
      MakeStatusCallback(peer_id_, __FUNCTION__, fidl_handle, std::move(callback));

  // WITHOUT_RESPONSE and RELIABLE write modes are not supported for descriptors.
  if (options.write_mode() == fbg::WriteMode::WITHOUT_RESPONSE ||
      options.write_mode() == fbg::WriteMode::RELIABLE) {
    write_cb(bt::ToResult(bt::HostError::kInvalidParameters));
    return;
  }

  const uint16_t kMaxShortWriteValueLength =
      service_->att_mtu() - sizeof(bt::att::OpCode) - sizeof(bt::att::WriteRequestParams);
  if (options.offset() == 0 && value.size() <= kMaxShortWriteValueLength) {
    service_->WriteDescriptor(handle, std::move(value), std::move(write_cb));
    return;
  }

  service_->WriteLongDescriptor(handle, options.offset(), std::move(value), std::move(write_cb));
}

void Gatt2RemoteServiceServer::RegisterCharacteristicNotifier(
    fbg::Handle fidl_handle, fidl::InterfaceHandle<fbg::CharacteristicNotifier> notifier_handle,
    RegisterCharacteristicNotifierCallback callback) {
  bt::gatt::CharacteristicHandle char_handle(static_cast<bt::att::Handle>(fidl_handle.value));
  NotifierId notifier_id = next_notifier_id_++;
  auto self = weak_ptr_factory_.GetWeakPtr();

  auto value_cb = [self, notifier_id, fidl_handle](const bt::ByteBuffer& value,
                                                   bool maybe_truncated) {
    if (!self) {
      return;
    }

    auto notifier_iter = self->characteristic_notifiers_.find(notifier_id);
    // The lower layers guarantee that the status callback is always invoked before sending
    // notifications. Notifiers are only removed during destruction (addressed by previous `self`
    // check) and in the `DisableNotifications` completion callback in
    // `OnCharacteristicNotifierError`, so no notifications should be received after removing a
    // notifier.
    ZX_ASSERT_MSG(notifier_iter != self->characteristic_notifiers_.end(),
                  "characteristic notification value received after notifier unregistered"
                  "(peer: %s, characteristic: 0x%lX) ",
                  bt_str(self->peer_id_), fidl_handle.value);
    CharacteristicNotifier& notifier = notifier_iter->second;

    // The `- 1` is needed because there is one unacked notification that we've already sent to the
    // client aside from the values in the queue.
    if (notifier.queued_values.size() == kMaxPendingNotifierValues - 1) {
      bt_log(WARN, "fidl",
             "GATT CharacteristicNotifier pending values limit reached, closing protocol (peer: "
             "%s, characteristic: %#.2x)",
             bt_str(self->peer_id_), notifier.characteristic_handle.value);
      self->OnCharacteristicNotifierError(notifier_id, notifier.characteristic_handle,
                                          notifier.handler_id);
      return;
    }

    fbg::ReadValue fidl_value;
    fidl_value.set_handle(fidl_handle);
    fidl_value.set_value(value.ToVector());
    fidl_value.set_maybe_truncated(maybe_truncated);

    bt_log(TRACE, "fidl", "Queueing GATT notification value (characteristic: %#.2x)",
           notifier.characteristic_handle.value);
    notifier.queued_values.push(std::move(fidl_value));

    self->MaybeNotifyNextValue(notifier_id);
  };

  auto status_cb = [self, service = service_, char_handle, notifier_id,
                    notifier_handle = std::move(notifier_handle), callback = std::move(callback)](
                       bt::att::Result<> status, bt::gatt::IdType handler_id) mutable {
    if (!self) {
      if (status.is_ok()) {
        // Disable this handler so it doesn't leak.
        service->DisableNotifications(char_handle, handler_id, [](auto /*status*/) {
          // There is no notifier to clean up because the server has been destroyed.
        });
      }
      return;
    }

    if (status.is_error()) {
      callback(fpromise::error(fidl_helpers::AttErrorToGattFidlError(status.error_value())));
      return;
    }

    CharacteristicNotifier notifier{.handler_id = handler_id,
                                    .characteristic_handle = char_handle,
                                    .notifier = notifier_handle.Bind()};
    auto [notifier_iter, emplaced] =
        self->characteristic_notifiers_.emplace(notifier_id, std::move(notifier));
    ZX_ASSERT(emplaced);

    // When the client closes the protocol, unregister the notifier.
    notifier_iter->second.notifier.set_error_handler(
        [self, char_handle, handler_id, notifier_id](auto /*status*/) {
          self->OnCharacteristicNotifierError(notifier_id, char_handle, handler_id);
        });

    callback(fpromise::ok());
  };

  service_->EnableNotifications(char_handle, std::move(value_cb), std::move(status_cb));
}

void Gatt2RemoteServiceServer::MaybeNotifyNextValue(NotifierId notifier_id) {
  auto notifier_iter = characteristic_notifiers_.find(notifier_id);
  if (notifier_iter == characteristic_notifiers_.end()) {
    return;
  }
  CharacteristicNotifier& notifier = notifier_iter->second;

  if (notifier.queued_values.empty()) {
    return;
  }

  if (!notifier.last_value_ack) {
    return;
  }
  notifier.last_value_ack = false;

  fbg::ReadValue value = std::move(notifier.queued_values.front());
  notifier.queued_values.pop();

  bt_log(DEBUG, "fidl", "Sending GATT notification value (handle: 0x%lX)", value.handle().value);
  auto self = weak_ptr_factory_.GetWeakPtr();
  notifier.notifier->OnNotification(std::move(value), [self, notifier_id]() {
    if (!self) {
      return;
    }

    auto notifier_iter = self->characteristic_notifiers_.find(notifier_id);
    if (notifier_iter == self->characteristic_notifiers_.end()) {
      return;
    }
    notifier_iter->second.last_value_ack = true;
    self->MaybeNotifyNextValue(notifier_id);
  });
}

void Gatt2RemoteServiceServer::OnCharacteristicNotifierError(
    NotifierId notifier_id, bt::gatt::CharacteristicHandle char_handle,
    bt::gatt::IdType handler_id) {
  auto self = weak_ptr_factory_.GetWeakPtr();
  service_->DisableNotifications(char_handle, handler_id, [self, notifier_id](auto /*status*/) {
    if (!self) {
      return;
    }
    // Clear the notifier regardless of status. Wait until this callback is called in order to
    // prevent the value callback from being called for an erased notifier.
    self->characteristic_notifiers_.erase(notifier_id);
  });
}

}  // namespace bthost
