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

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

namespace fb = fuchsia::bluetooth;
namespace fbg = fuchsia::bluetooth::gatt2;

namespace bthost {

namespace {

fbg::ServiceInfo RemoteServiceToFidlServiceInfo(const fbl::RefPtr<bt::gatt::RemoteService>& svc) {
  fbg::ServiceInfo out;
  out.set_handle(fbg::Handle{svc->handle()});
  out.set_primary(svc->info().kind == bt::gatt::ServiceKind::PRIMARY);
  out.set_type(fb::Uuid{svc->uuid().value()});
  return out;
}

}  // namespace

Gatt2ClientServer::Gatt2ClientServer(bt::gatt::PeerId peer_id,
                                     fxl::WeakPtr<bt::gatt::GATT> weak_gatt,
                                     fidl::InterfaceRequest<fbg::Client> request,
                                     fit::callback<void()> error_cb)
    : GattServerBase(std::move(weak_gatt), /*impl=*/this, std::move(request)),
      peer_id_(peer_id),
      server_error_cb_(std::move(error_cb)),
      weak_ptr_factory_(this) {
  set_error_handler([this](zx_status_t) {
    if (server_error_cb_) {
      server_error_cb_();
    }
  });

  // It is safe to bind |this| to the callback because the service watcher is unregistered in the
  // destructor.
  service_watcher_id_ = gatt()->RegisterRemoteServiceWatcherForPeer(
      peer_id_, [this](auto removed, auto added, auto modified) {
        // Ignore results before the initial call to ListServices() completes to avoid redundant
        // notifications.
        if (!list_services_complete_) {
          bt_log(TRACE, "fidl",
                 "ignoring service watcher update before ListServices() result received");
          return;
        }
        OnWatchServicesResult(removed, added, modified);
      });
}

Gatt2ClientServer::~Gatt2ClientServer() {
  ZX_ASSERT(gatt()->UnregisterRemoteServiceWatcher(service_watcher_id_));
}

void Gatt2ClientServer::OnWatchServicesResult(const std::vector<bt::att::Handle>& removed,
                                              const bt::gatt::ServiceList& added,
                                              const bt::gatt::ServiceList& modified) {
  // Accumulate all removed services and send in next result.
  if (!next_watch_services_result_.has_value()) {
    next_watch_services_result_.emplace();
  }
  next_watch_services_result_->removed.insert(removed.begin(), removed.end());

  // Remove any stale updated services (to avoid sending an invalid one to the client).
  for (bt::att::Handle handle : removed) {
    next_watch_services_result_->updated.erase(handle);
  }

  // Replace any existing updated services with same handle and add new updates.
  for (const fbl::RefPtr<bt::gatt::RemoteService>& svc : added) {
    next_watch_services_result_->updated[svc->handle()] = svc;
  }
  for (const fbl::RefPtr<bt::gatt::RemoteService>& svc : modified) {
    next_watch_services_result_->updated[svc->handle()] = svc;
  }

  bt_log(TRACE, "fidl", "next watch services result: (removed: %zu, updated: %zu) (peer: %s)",
         next_watch_services_result_->removed.size(), next_watch_services_result_->updated.size(),
         bt_str(peer_id_));

  TrySendNextWatchServicesResult();
}

void Gatt2ClientServer::TrySendNextWatchServicesResult() {
  if (!watch_services_request_ || !next_watch_services_result_) {
    return;
  }

  std::vector<fbg::Handle> fidl_removed;
  std::transform(next_watch_services_result_->removed.begin(),
                 next_watch_services_result_->removed.end(), std::back_inserter(fidl_removed),
                 [](const bt::att::Handle& handle) { return fbg::Handle{handle}; });

  // Don't filter removed services by UUID because we don't know the UUIDs of these services
  // currently.
  // TODO(fxbug.dev/36374): Filter removed services by UUID.

  std::vector<fbg::ServiceInfo> fidl_updated;
  for (const ServiceMap::value_type& svc_pair : next_watch_services_result_->updated) {
    // Filter updated services by UUID.
    // NOTE: If clients change UUIDs they are requesting across requests, they won't receive
    // existing service with the new UUIDs, only new ones
    if (prev_watch_services_uuids_.empty() ||
        prev_watch_services_uuids_.count(svc_pair.second->uuid()) == 1) {
      fidl_updated.push_back(RemoteServiceToFidlServiceInfo(svc_pair.second));
    }
  }

  next_watch_services_result_.reset();

  // Skip sending results that are empty after filtering services by UUID.
  if (fidl_removed.empty() && fidl_updated.empty()) {
    bt_log(TRACE, "fidl", "skipping service watcher update without matching UUIDs (peer: %s)",
           bt_str(peer_id_));
    return;
  }

  // TODO(fxbug.dev/84988): Use measure-tape to verify response fits in FIDL channel before sending.
  // This is only an issue for peers with very large databases.
  bt_log(TRACE, "fidl", "notifying WatchServices() callback (removed: %zu, updated: %zu, peer: %s)",
         fidl_removed.size(), fidl_updated.size(), bt_str(peer_id_));
  watch_services_request_.value()(std::move(fidl_updated), std::move(fidl_removed));
  watch_services_request_.reset();
}

// TODO(fxbug.dev/84971): Do not send privileged services (e.g. Generic Attribute Profile Service)
// to clients.
void Gatt2ClientServer::WatchServices(std::vector<fb::Uuid> fidl_uuids,
                                      WatchServicesCallback callback) {
  std::unordered_set<bt::UUID> uuids;
  std::transform(fidl_uuids.begin(), fidl_uuids.end(), std::inserter(uuids, uuids.begin()),
                 [](const fb::Uuid& uuid) { return bt::UUID(uuid.value); });

  // Only allow 1 callback at a time. Close the server if this is violated.
  if (watch_services_request_) {
    bt_log(WARN, "fidl", "%s: call received while previous call is still pending", __FUNCTION__);
    binding()->Close(ZX_ERR_ALREADY_BOUND);
    server_error_cb_();
    return;
  }

  // If the UUID filter list is changed between requests, perform a fresh ListServices() call to
  // ensure existing services that match the new UUIDs are reported to the client.
  if (uuids != prev_watch_services_uuids_) {
    bt_log(DEBUG, "fidl", "WatchServices: UUIDs changed from previous call (peer: %s)",
           bt_str(peer_id_));
    list_services_complete_ = false;
    // Clear old watch service results as we're about to get a fresh list of services.
    next_watch_services_result_.reset();
    prev_watch_services_uuids_ = uuids;
  }

  watch_services_request_.emplace(std::move(callback));

  auto self = weak_ptr_factory_.GetWeakPtr();

  // Return a complete service snapshot on the first call, or on calls that use a new UUID filter
  // list.
  if (!list_services_complete_) {
    std::vector<bt::UUID> uuids_vector(uuids.begin(), uuids.end());
    gatt()->ListServices(
        peer_id_, std::move(uuids_vector),
        [self](bt::att::Result<> status, const bt::gatt::ServiceList& services) {
          if (!self) {
            return;
          }
          if (bt_is_error(status, INFO, "fidl", "WatchServices: ListServices failed (peer: %s)",
                          bt_str(self->peer_id_))) {
            self->binding()->Close(ZX_ERR_CONNECTION_RESET);
            self->server_error_cb_();
            return;
          }

          bt_log(DEBUG, "fidl", "WatchServices: ListServices complete (peer: %s)",
                 bt_str(self->peer_id_));

          ZX_ASSERT(self->watch_services_request_);
          self->list_services_complete_ = true;
          self->OnWatchServicesResult(/*removed=*/{}, /*added=*/services, /*modified=*/{});
        });
    return;
  }

  TrySendNextWatchServicesResult();
}

void Gatt2ClientServer::ConnectToService(fbg::Handle handle,
                                         fidl::InterfaceRequest<fbg::RemoteService> request) {
  bt_log(DEBUG, "fidl", "%s: (handle: 0x%lX)", __FUNCTION__, handle.value);

  if (!fidl_helpers::IsFidlGattHandleValid(handle)) {
    request.Close(ZX_ERR_INVALID_ARGS);
    return;
  }
  bt::att::Handle service_handle = static_cast<bt::att::Handle>(handle.value);

  // Only allow clients to have 1 RemoteService per service at a time to prevent race conditions
  // between multiple RemoteService clients modifying a service, and to simplify implementation.
  // A client shouldn't need more than 1 RemoteService per service at a time, but if they really
  // need to, they can create multiple Client instances.
  if (services_.count(service_handle) == 1) {
    request.Close(ZX_ERR_ALREADY_EXISTS);
    return;
  }

  // Mark this connection as in progress.
  services_.try_emplace(service_handle, nullptr);

  fbl::RefPtr<bt::gatt::RemoteService> service = gatt()->FindService(peer_id_, service_handle);
  if (!service) {
    bt_log(INFO, "fidl", "service not found (peer: %s, handle: %#.4x)", bt_str(peer_id_),
           service_handle);
    services_.erase(service_handle);
    request.Close(ZX_ERR_NOT_FOUND);
    return;
  }
  ZX_ASSERT(service_handle == service->handle());

  // This removed handler may be called long after the service is removed from the service map or
  // this server is destroyed, since removed handlers are not unregistered. If the FIDL client
  // connects->disconnects->connects, it is possible for this handler to be called twice (the
  // second call should then do nothing).
  auto self = weak_ptr_factory_.GetWeakPtr();
  fit::closure removed_handler = [self, service_handle] {
    if (!self) {
      return;
    }
    bt_log(DEBUG, "fidl", "service removed (peer: %s, handle: %#.4x)", bt_str(self->peer_id_),
           service_handle);
    auto svc_iter = self->services_.find(service_handle);
    if (svc_iter == self->services_.end()) {
      bt_log(TRACE, "fidl",
             "ignoring service removed callback for already removed service (peer: %s, handle: "
             "%#.4x)",
             bt_str(self->peer_id_), service_handle);
      return;
    }
    svc_iter->second->Close(ZX_ERR_CONNECTION_RESET);
    self->services_.erase(svc_iter);
  };

  // The only reason RemoteService::AddRemovedHandler() can fail is if the service is already
  // shut down, but that should not be possible in this synchronous callback (the service
  // would not have been returned in the first place).
  ZX_ASSERT_MSG(service->AddRemovedHandler(std::move(removed_handler)),
                "adding service removed handler failed (service may be shut down) (peer: %s, "
                "handle: %#.4x)",
                bt_str(peer_id_), service_handle);

  std::unique_ptr<Gatt2RemoteServiceServer> remote_service_server =
      std::make_unique<Gatt2RemoteServiceServer>(std::move(service), gatt(), peer_id_,
                                                 std::move(request));

  // Even if there is already an error, this handler won't be called until the next yield to
  // the event loop.
  remote_service_server->set_error_handler([self, service_handle](zx_status_t status) {
    bt_log(TRACE, "fidl", "FIDL channel error (peer: %s, handle: %#.4x)", bt_str(self->peer_id_),
           service_handle);
    self->services_.erase(service_handle);
  });

  // Error handler should not have been called yet.
  ZX_ASSERT(services_.count(service_handle) == 1);
  services_[service_handle] = std::move(remote_service_server);
}

}  // namespace bthost
