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

#include <lib/fit/defer.h>

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

using fuchsia::bluetooth::ErrorCode;
using fuchsia::bluetooth::Status;

using fuchsia::bluetooth::gatt::Client;
using fuchsia::bluetooth::gatt::RemoteService;
using fuchsia::bluetooth::gatt::ServiceInfo;
using fuchsia::bluetooth::gatt::ServiceInfoPtr;

namespace bthost {

GattClientServer::GattClientServer(bt::gatt::PeerId peer_id, fxl::WeakPtr<bt::gatt::GATT> gatt,
                                   fidl::InterfaceRequest<Client> request)
    : GattServerBase(gatt, this, std::move(request)), peer_id_(peer_id), weak_ptr_factory_(this) {}

void GattClientServer::ListServices(::fidl::VectorPtr<::std::string> fidl_uuids,
                                    ListServicesCallback callback) {
  // Parse the UUID list.
  std::vector<bt::UUID> uuids;
  if (fidl_uuids.has_value()) {
    // Allocate all at once and convert in-place.
    uuids.resize(fidl_uuids->size());
    for (size_t i = 0; i < uuids.size(); ++i) {
      if (!StringToUuid(fidl_uuids.value()[i], &uuids[i])) {
        bt_log(WARN, "fidl", "%s: Invalid UUID: %s (peer: %s)", __FUNCTION__,
               fidl_uuids.value()[i].c_str(), bt_str(peer_id_));
        callback(fidl_helpers::NewFidlError(ErrorCode::INVALID_ARGUMENTS,
                                            "Invalid UUID: " + fidl_uuids.value()[i]),
                 std::vector<ServiceInfo>((size_t)0u));
        return;
      }
    }
  }

  auto cb = [callback = std::move(callback), peer_id = peer_id_, func = __FUNCTION__](
                bt::att::Status status, auto services) {
    std::vector<ServiceInfo> out;
    if (!status) {
      bt_log(WARN, "fidl", "%s: Failed to discover services (peer: %s)", func, bt_str(peer_id));
      auto fidl_status =
          fidl_helpers::StatusToFidlDeprecated(status, "Failed to discover services");
      callback(std::move(fidl_status), std::move(out));
      return;
    }

    out.resize(services.size());

    size_t i = 0;
    for (const auto& svc : services) {
      ServiceInfo service_info;
      service_info.id = svc->handle();
      service_info.primary = svc->info().kind == bt::gatt::ServiceKind::PRIMARY;
      service_info.type = svc->uuid().ToString();
      out[i++] = std::move(service_info);
    }
    callback(Status(), std::move(out));
  };

  gatt()->ListServices(peer_id_, std::move(uuids), std::move(cb));
}

void GattClientServer::ConnectToService(uint64_t id,
                                        ::fidl::InterfaceRequest<RemoteService> service) {
  if (connected_services_.count(id)) {
    bt_log(WARN, "fidl", "%s: service already requested (service: %lu, peer: %s)", __FUNCTION__, id,
           bt_str(peer_id_));
    return;
  }

  // Initialize an entry so that we remember when this request is in progress.
  connected_services_[id] = nullptr;

  auto self = weak_ptr_factory_.GetWeakPtr();
  auto callback = [self, id, request = std::move(service),
                   func = __FUNCTION__](auto service) mutable {
    if (!self)
      return;

    // The operation must be in progress.
    ZX_DEBUG_ASSERT(self->connected_services_.count(id));

    // Automatically called on failure.
    auto fail_cleanup = fit::defer([self, id] { self->connected_services_.erase(id); });

    if (!service) {
      bt_log(WARN, "fidl", "%s: failed (service: %lu, peer: %s)", func, id, bt_str(self->peer_id_));
      return;
    }

    // Clean up the server if either the peer device or the FIDL client
    // disconnects.
    auto error_cb = [self, id, peer_id = self->peer_id_, func] {
      bt_log(DEBUG, "fidl", "%s: service disconnected (service: %lu, peer: %s)", func, id,
             bt_str(peer_id));
      if (self) {
        self->connected_services_.erase(id);
      }
    };

    if (!service->AddRemovedHandler(error_cb)) {
      bt_log(WARN, "fidl", "%s: failed to assign closed handler (service: %lu, peer: %s)", func, id,
             bt_str(self->peer_id_));
      return;
    }

    fail_cleanup.cancel();

    auto server = std::make_unique<GattRemoteServiceServer>(std::move(service), self->gatt(),
                                                            self->peer_id_, std::move(request));
    server->set_error_handler([cb = std::move(error_cb)](zx_status_t status) { cb(); });

    self->connected_services_[id] = std::move(server);
  };

  gatt()->FindService(peer_id_, id, std::move(callback));
}

}  // namespace bthost
