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

#include <zircon/errors.h>

#include <algorithm>

#include "helpers.h"
#include "src/connectivity/bluetooth/core/bt-host/common/log.h"

using fuchsia::bluetooth::ErrorCode;
using fuchsia::bluetooth::Status;
using fuchsia::bluetooth::gatt::Characteristic;
using fuchsia::bluetooth::gatt::CharacteristicPtr;
using fuchsia::bluetooth::gatt::Descriptor;
using fuchsia::bluetooth::gatt::WriteOptions;

using bt::ByteBuffer;
using bt::MutableBufferView;
using bt::gatt::CharacteristicData;
using bt::gatt::CharacteristicHandle;
using bt::gatt::DescriptorData;
using bt::gatt::DescriptorHandle;

namespace bthost {
namespace {

// We mask away the "extended properties" property. We expose extended
// properties in the same bitfield.
constexpr uint8_t kPropertyMask = 0x7F;

Characteristic CharacteristicToFidl(const CharacteristicData& characteristic,
                                    const std::map<DescriptorHandle, DescriptorData>& descriptors) {
  Characteristic fidl_char;
  fidl_char.id = static_cast<uint64_t>(characteristic.value_handle);
  fidl_char.type = characteristic.type.ToString();
  fidl_char.properties = static_cast<uint16_t>(characteristic.properties & kPropertyMask);
  fidl_char.descriptors.emplace();  // initialize an empty vector

  // TODO(armansito): Add extended properties.

  for (const auto& [id, descr] : descriptors) {
    Descriptor fidl_descr;
    fidl_descr.id = static_cast<uint64_t>(id.value);
    fidl_descr.type = descr.type.ToString();
    fidl_char.descriptors->push_back(std::move(fidl_descr));
  }

  return fidl_char;
}

void NopStatusCallback(bt::att::Status) {}

}  // namespace

GattRemoteServiceServer::GattRemoteServiceServer(
    fbl::RefPtr<bt::gatt::RemoteService> service, fbl::RefPtr<bt::gatt::GATT> gatt,
    fidl::InterfaceRequest<fuchsia::bluetooth::gatt::RemoteService> request)
    : GattServerBase(gatt, this, std::move(request)),
      service_(std::move(service)),
      weak_ptr_factory_(this) {
  ZX_DEBUG_ASSERT(service_);
}

GattRemoteServiceServer::~GattRemoteServiceServer() {
  for (const auto& iter : notify_handlers_) {
    if (iter.second != bt::gatt::kInvalidId) {
      service_->DisableNotifications(iter.first, iter.second, NopStatusCallback);
    }
  }
}

void GattRemoteServiceServer::DiscoverCharacteristics(DiscoverCharacteristicsCallback callback) {
  auto res_cb = [callback = std::move(callback)](bt::att::Status status, const auto& chrcs) {
    std::vector<Characteristic> fidl_chrcs;
    if (status) {
      for (const auto& [id, chrc] : chrcs) {
        auto& [chr, descs] = chrc;
        fidl_chrcs.push_back(CharacteristicToFidl(chr, descs));
      }
    }

    callback(fidl_helpers::StatusToFidlDeprecated(status, ""), std::move(fidl_chrcs));
  };

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

void GattRemoteServiceServer::ReadCharacteristic(uint64_t id, ReadCharacteristicCallback callback) {
  auto cb = [callback = std::move(callback)](bt::att::Status status, const bt::ByteBuffer& value) {
    // We always reply with a non-null value.
    std::vector<uint8_t> vec;

    if (status && value.size()) {
      vec.resize(value.size());

      MutableBufferView vec_view(vec.data(), vec.size());
      value.Copy(&vec_view);
    }

    callback(fidl_helpers::StatusToFidlDeprecated(status), std::move(vec));
  };

  service_->ReadCharacteristic(CharacteristicHandle(id), std::move(cb));
}

void GattRemoteServiceServer::ReadLongCharacteristic(uint64_t id, uint16_t offset,
                                                     uint16_t max_bytes,
                                                     ReadLongCharacteristicCallback callback) {
  auto cb = [callback = std::move(callback)](bt::att::Status status, const bt::ByteBuffer& value) {
    // We always reply with a non-null value.
    std::vector<uint8_t> vec;

    if (status && value.size()) {
      vec.resize(value.size());

      MutableBufferView vec_view(vec.data(), vec.size());
      value.Copy(&vec_view);
    }

    callback(fidl_helpers::StatusToFidlDeprecated(status), std::move(vec));
  };

  service_->ReadLongCharacteristic(CharacteristicHandle(id), offset, max_bytes, std::move(cb));
}

void GattRemoteServiceServer::WriteCharacteristic(uint64_t id, ::std::vector<uint8_t> value,
                                                  WriteCharacteristicCallback callback) {
  auto cb = [callback = std::move(callback)](bt::att::Status status) {
    callback(fidl_helpers::StatusToFidlDeprecated(status, ""));
  };

  service_->WriteCharacteristic(CharacteristicHandle(id), std::move(value), std::move(cb));
}

void GattRemoteServiceServer::WriteLongCharacteristic(uint64_t id, uint16_t offset,
                                                      ::std::vector<uint8_t> value,
                                                      WriteOptions write_options,
                                                      WriteLongCharacteristicCallback callback) {
  auto cb = [callback = std::move(callback)](bt::att::Status status) {
    callback(fidl_helpers::StatusToFidlDeprecated(status, ""));
  };

  auto reliable_mode = fidl_helpers::ReliableModeFromFidl(write_options);
  service_->WriteLongCharacteristic(CharacteristicHandle(id), offset, std::move(value),
                                    std::move(reliable_mode), std::move(cb));
}

void GattRemoteServiceServer::WriteCharacteristicWithoutResponse(uint64_t id,
                                                                 ::std::vector<uint8_t> value) {
  service_->WriteCharacteristicWithoutResponse(CharacteristicHandle(id), std::move(value));
}

void GattRemoteServiceServer::ReadDescriptor(uint64_t id, ReadDescriptorCallback callback) {
  auto cb = [callback = std::move(callback)](bt::att::Status status, const bt::ByteBuffer& value) {
    // We always reply with a non-null value.
    std::vector<uint8_t> vec;

    if (status && value.size()) {
      vec.resize(value.size());

      MutableBufferView vec_view(vec.data(), vec.size());
      value.Copy(&vec_view);
    }

    callback(fidl_helpers::StatusToFidlDeprecated(status), std::move(vec));
  };

  service_->ReadDescriptor(DescriptorHandle(id), std::move(cb));
}

void GattRemoteServiceServer::ReadLongDescriptor(uint64_t id, uint16_t offset, uint16_t max_bytes,
                                                 ReadLongDescriptorCallback callback) {
  auto cb = [callback = std::move(callback)](bt::att::Status status, const bt::ByteBuffer& value) {
    // We always reply with a non-null value.
    std::vector<uint8_t> vec;

    if (status && value.size()) {
      vec.resize(value.size());

      MutableBufferView vec_view(vec.data(), vec.size());
      value.Copy(&vec_view);
    }

    callback(fidl_helpers::StatusToFidlDeprecated(status), std::move(vec));
  };

  service_->ReadLongDescriptor(DescriptorHandle(id), offset, max_bytes, std::move(cb));
}

void GattRemoteServiceServer::WriteDescriptor(uint64_t id, ::std::vector<uint8_t> value,
                                              WriteDescriptorCallback callback) {
  service_->WriteDescriptor(DescriptorHandle(id), std::move(value),
                            [callback = std::move(callback)](bt::att::Status status) {
                              callback(fidl_helpers::StatusToFidlDeprecated(status, ""));
                            });
}

void GattRemoteServiceServer::WriteLongDescriptor(uint64_t id, uint16_t offset,
                                                  ::std::vector<uint8_t> value,
                                                  WriteLongDescriptorCallback callback) {
  service_->WriteLongDescriptor(DescriptorHandle(id), offset, std::move(value),
                                [callback = std::move(callback)](bt::att::Status status) {
                                  callback(fidl_helpers::StatusToFidlDeprecated(status, ""));
                                });
}

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

        switch (status.error()) {
          case bt::HostError::kNoError:
            break;
          case bt::HostError::kInvalidParameters:
            bt_log(TRACE, "bt-host",
                   "ReadByType called with invalid parameters, closing FIDL channel");
            self->binding()->Close(ZX_ERR_INVALID_ARGS);
            return;
          default:
            cb(fit::error(fidl_helpers::GattStatusToFidl(status)));
            return;
        }

        if (results.size() > fuchsia::bluetooth::gatt::MAX_READ_BY_TYPE_RESULTS) {
          cb(fit::error(fuchsia::bluetooth::gatt::Error::TOO_MANY_RESULTS));
          return;
        }

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

        for (const auto& result : results) {
          fuchsia::bluetooth::gatt::ReadByTypeResult fidl_result;
          fidl_result.set_id(static_cast<uint64_t>(result.handle.value));
          if (result.result.is_ok()) {
            fidl_result.set_value(result.result.value()->ToVector());
          } else {
            fidl_result.set_error(
                fidl_helpers::GattStatusToFidl(bt::att::Status(result.result.error())));
          }
          fidl_results.push_back(std::move(fidl_result));
        }

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

void GattRemoteServiceServer::NotifyCharacteristic(uint64_t id, bool enable,
                                                   NotifyCharacteristicCallback callback) {
  auto handle = CharacteristicHandle(id);
  if (!enable) {
    auto iter = notify_handlers_.find(handle);
    if (iter == notify_handlers_.end()) {
      callback(fidl_helpers::NewFidlError(ErrorCode::NOT_FOUND, "characteristic not notifying"));
      return;
    }

    if (iter->second == bt::gatt::kInvalidId) {
      callback(fidl_helpers::NewFidlError(ErrorCode::IN_PROGRESS,
                                          "characteristic notification registration pending"));
      return;
    }

    service_->DisableNotifications(handle, iter->second,
                                   [callback = std::move(callback)](bt::att::Status status) {
                                     callback(fidl_helpers::StatusToFidlDeprecated(status, ""));
                                   });
    notify_handlers_.erase(iter);

    return;
  }

  if (notify_handlers_.count(handle) != 0) {
    callback(fidl_helpers::NewFidlError(ErrorCode::ALREADY, "characteristic already notifying"));
    return;
  }

  // Prevent any races and leaks by marking a notification is in progress
  notify_handlers_[handle] = bt::gatt::kInvalidId;

  auto self = weak_ptr_factory_.GetWeakPtr();
  auto value_cb = [self, id](const ByteBuffer& value) {
    if (!self)
      return;

    self->binding()->events().OnCharacteristicValueUpdated(id, value.ToVector());
  };

  auto status_cb = [self, svc = service_, handle, callback = std::move(callback)](
                       bt::att::Status status, HandlerId handler_id) {
    if (!self) {
      if (status) {
        // Disable this handler so it doesn't leak.
        svc->DisableNotifications(handle, handler_id, NopStatusCallback);
      }

      callback(fidl_helpers::NewFidlError(ErrorCode::FAILED, "canceled"));
      return;
    }

    if (status) {
      ZX_DEBUG_ASSERT(handler_id != bt::gatt::kInvalidId);
      ZX_DEBUG_ASSERT(self->notify_handlers_.count(handle) == 1u);
      ZX_DEBUG_ASSERT(self->notify_handlers_[handle] == bt::gatt::kInvalidId);
      self->notify_handlers_[handle] = handler_id;
    } else {
      // Remove our handle holder.
      self->notify_handlers_.erase(handle);
    }

    callback(fidl_helpers::StatusToFidlDeprecated(status, ""));
  };

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

}  // namespace bthost
