// Copyright 2022 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.

// [START imports]
#include <fidl/examples.routing.echo/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/inspect/component/cpp/component.h>
#include <lib/sys/component/cpp/outgoing_directory.h>
#include <lib/syslog/global.h>
// [END imports]

// [START handler]
struct EchoConnectionStats {
  inspect::UintProperty bytes_processed;
  inspect::UintProperty total_requests;
};

// Handler for incoming FIDL protocol requests
class EchoImplementation : public fidl::Server<examples_routing_echo::Echo> {
 public:
  // The handler for `examples.routing.echo/Echo.EchoString` requests.
  //
  // Replies back to the caller with the original request value.
  void EchoString(EchoStringRequest& request, EchoStringCompleter::Sync& completer) override {
    // Increment connection stats on each request
    stats_->total_requests.Add(1);
    stats_->bytes_processed.Add(request.value()->size());
    completer.Reply({{request.value()}});
  }

  // Called when the FIDL connection is torn down.
  void OnUnbound(fidl::UnbindInfo info, fidl::ServerEnd<examples_routing_echo::Echo> server_end) {
    if (info.is_user_initiated()) {
      return;
    }
    if (info.is_peer_closed()) {
      // The peer (the client) closed their endpoint.
      FX_LOG(DEBUG, "echo_server", "Client disconnected.");
    } else {
      // Treat other unbind causes as errors.
      FX_LOGF(ERROR, "echo_server", "Server error: %s", info.status_string());
    }
  }

  std::unique_ptr<EchoConnectionStats> stats_;
};
// [END handler]

int main(int argc, const char** argv) {
  async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
  component::OutgoingDirectory outgoing = component::OutgoingDirectory::Create(loop.dispatcher());

  // Initialize inspect
  inspect::ComponentInspector inspector(outgoing, loop.dispatcher());
  inspector.Health().StartingUp();

  // [START echo_instance]
  // Serve the Echo protocol
  std::unique_ptr<EchoImplementation> echo_instance = std::make_unique<EchoImplementation>();
  // [END echo_instance]
  zx::result result = outgoing.AddProtocol<examples_routing_echo::Echo>(echo_instance.get());
  if (result.is_error()) {
    FX_LOGF(ERROR, "echo_server", "Failed to add Echo protocol: %s", result.status_string());
    return -1;
  }

  result = outgoing.ServeFromStartupInfo();
  if (result.is_error()) {
    FX_LOGF(ERROR, "echo_server", "Failed to serve outgoing directory: %s", result.status_string());
    return -1;
  }

  // [START add_properties]
  // Create request tracking properties
  inspect::Node& root_node = inspector.root();
  auto total_requests = root_node.CreateUint("total_requests", 0);
  auto bytes_processed = root_node.CreateUint("bytes_processed", 0);
  echo_instance->stats_ = std::make_unique<EchoConnectionStats>(EchoConnectionStats{
    std::move(bytes_processed),
    std::move(total_requests),
  });
  // [END add_properties]

  // Component is serving and ready to handle incoming requests
  inspector.Health().Ok();

  return loop.Run();
}
