// 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 <fuchsia/cobalt/llcpp/fidl.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fd.h>
#include <lib/fdio/fdio.h>
#include <lib/fidl/llcpp/string_view.h>
#include <lib/fidl/llcpp/vector_view.h>
#include <lib/zx/channel.h>
#include <zircon/errors.h>
#include <zircon/status.h>
#include <zircon/types.h>

#include <utility>

#include <cobalt-client/cpp/collector_internal.h>
#include <cobalt-client/cpp/histogram_internal.h>
#include <cobalt-client/cpp/types_internal.h>

namespace cobalt_client {
namespace internal {
namespace {

fuchsia_cobalt::wire::CobaltEvent MetricIntoToCobaltEvent(const MetricOptions& metric_info) {
  fuchsia_cobalt::wire::CobaltEvent event;
  event.metric_id = metric_info.metric_id;
  event.component = fidl::StringView::FromExternal(metric_info.component);
  // Safe to do so, since the request is read only.
  event.event_codes = fidl::VectorView<uint32_t>::FromExternal(
      const_cast<uint32_t*>(metric_info.event_codes.data()), metric_info.metric_dimensions);
  return event;
}

}  // namespace

std::string_view CobaltLogger::GetServiceName() {
  return fidl::DiscoverableProtocolName<fuchsia_cobalt::LoggerFactory>;
}

bool CobaltLogger::TryObtainLogger() {
  if (logger_.client_end().is_valid()) {
    return true;
  }

  auto factory_endpoints = fidl::CreateEndpoints<fuchsia_cobalt::LoggerFactory>();
  if (factory_endpoints.is_error()) {
    return false;
  }
  auto [logger_factory_client, logger_factory_srv] = *std::move(factory_endpoints);

  if (options_.service_connect(options_.service_path.c_str(), logger_factory_srv.TakeChannel()) !=
      ZX_OK) {
    return false;
  }

  // Obtain a logger service for the project ID.
  auto logger_endpoints = fidl::CreateEndpoints<fuchsia_cobalt::Logger>();
  if (logger_endpoints.is_error()) {
    return false;
  }
  auto [logger_client, logger_server] = *std::move(logger_endpoints);
  auto create_logger_result =
      fidl::WireCall(logger_factory_client)
          .CreateLoggerFromProjectId(options_.project_id, std::move(logger_server));
  if (create_logger_result.status() == ZX_OK &&
      create_logger_result->status == fuchsia_cobalt::wire::Status::OK) {
    logger_ = fidl::BindSyncClient(std::move(logger_client));
    return true;
  }
  return false;
}

bool CobaltLogger::Log(const MetricOptions& metric_info, const HistogramBucket* buckets,
                       size_t bucket_count) {
  if (!TryObtainLogger()) {
    return false;
  }
  auto event = MetricIntoToCobaltEvent(metric_info);
  // Safe because is read only.
  auto int_histogram = fidl::VectorView<HistogramBucket>::FromExternal(
      const_cast<HistogramBucket*>(buckets), bucket_count);
  event.payload.set_int_histogram(
      fidl::ObjectView<fidl::VectorView<HistogramBucket>>::FromExternal(&int_histogram));

  auto log_result = logger_.LogCobaltEvent(std::move(event));
  if (log_result.status() == ZX_ERR_PEER_CLOSED) {
    Reset();
  }
  return log_result.status() == ZX_OK && log_result->status == fuchsia_cobalt::wire::Status::OK;
}

bool CobaltLogger::Log(const MetricOptions& metric_info, RemoteCounter::Type count) {
  if (!TryObtainLogger()) {
    return false;
  }
  auto event = MetricIntoToCobaltEvent(metric_info);
  fuchsia_cobalt::wire::CountEvent event_count{.period_duration_micros = 0, .count = count};
  event.payload.set_event_count(
      fidl::ObjectView<fuchsia_cobalt::wire::CountEvent>::FromExternal(&event_count));

  auto log_result = logger_.LogCobaltEvent(std::move(event));
  if (log_result.status() == ZX_ERR_PEER_CLOSED) {
    Reset();
  }
  return log_result.status() == ZX_OK && log_result->status == fuchsia_cobalt::wire::Status::OK;
}

bool CobaltLogger::LogInteger(const MetricOptions& metric_info, RemoteCounter::Type value) {
  if (!TryObtainLogger()) {
    return false;
  }

  auto event = MetricIntoToCobaltEvent(metric_info);
  event.payload.set_memory_bytes_used(fidl::ObjectView<RemoteCounter::Type>::FromExternal(&value));

  // Cobalt 1.0 does not support integer. The closest to integer is memory
  // usage. So, we use MemoryUsage until we have a better support for integer(in
  // version 1.1).
  auto log_result =
      logger_.LogMemoryUsage(event.metric_id, event.event_codes[0], event.component, value);
  if (log_result.status() == ZX_ERR_PEER_CLOSED) {
    Reset();
  }
  return log_result.status() == ZX_OK && log_result->status == fuchsia_cobalt::wire::Status::OK;
}

}  // namespace internal
}  // namespace cobalt_client
