// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// The generated C++ bindings for the Echo FIDL protocol
#include <flutter/shell/platform/fuchsia/dart_runner/tests/fidl/flutter.example.echo/flutter/example/echo/cpp/fidl.h>

#include <fuchsia/tracing/provider/cpp/fidl.h>

#include <lib/async-loop/testing/cpp/real_loop.h>
#include <lib/sys/component/cpp/testing/realm_builder.h>
#include <lib/sys/component/cpp/testing/realm_builder_types.h>

#include "flutter/fml/logging.h"
#include "gtest/gtest.h"

namespace dart_aot_runner_testing::testing {
namespace {

// Types imported for the realm_builder library
using component_testing::ChildOptions;
using component_testing::ChildRef;
using component_testing::Directory;
using component_testing::ParentRef;
using component_testing::Protocol;
using component_testing::RealmBuilder;
using component_testing::RealmRoot;
using component_testing::Route;

constexpr auto kDartRunnerEnvironment = "dart_runner_env";

constexpr auto kDartAotRunner = "dart_aot_runner";
constexpr auto kDartAotRunnerRef = ChildRef{kDartAotRunner};
constexpr auto kDartAotRunnerUrl =
    "fuchsia-pkg://fuchsia.com/oot_dart_aot_runner#meta/"
    "dart_aot_runner.cm";

constexpr auto kDartAotEchoServer = "dart_aot_echo_server";
constexpr auto kDartAotEchoServerRef = ChildRef{kDartAotEchoServer};
constexpr auto kDartAotEchoServerUrl =
    "fuchsia-pkg://fuchsia.com/dart_aot_echo_server#meta/"
    "dart_aot_echo_server.cm";

class RealmBuilderTest : public ::loop_fixture::RealLoop,
                         public ::testing::Test {
 public:
  RealmBuilderTest() = default;
};

TEST_F(RealmBuilderTest, DartRunnerStartsUp) {
  auto realm_builder = RealmBuilder::Create();
  // Add Dart AOT runner as a child of RealmBuilder
  realm_builder.AddChild(kDartAotRunner, kDartAotRunnerUrl);

  // Add environment providing the Dart AOT runner
  fuchsia::component::decl::Environment dart_runner_environment;
  dart_runner_environment.set_name(kDartRunnerEnvironment);
  dart_runner_environment.set_extends(
      fuchsia::component::decl::EnvironmentExtends::REALM);
  dart_runner_environment.set_runners({});
  auto environment_runners = dart_runner_environment.mutable_runners();

  fuchsia::component::decl::RunnerRegistration dart_aot_runner_reg;
  dart_aot_runner_reg.set_source(fuchsia::component::decl::Ref::WithChild(
      fuchsia::component::decl::ChildRef{.name = kDartAotRunner}));
  dart_aot_runner_reg.set_source_name(kDartAotRunner);
  dart_aot_runner_reg.set_target_name(kDartAotRunner);
  environment_runners->push_back(std::move(dart_aot_runner_reg));

  auto realm_decl = realm_builder.GetRealmDecl();
  if (!realm_decl.has_environments()) {
    realm_decl.set_environments({});
  }
  auto realm_environments = realm_decl.mutable_environments();
  realm_environments->push_back(std::move(dart_runner_environment));
  realm_builder.ReplaceRealmDecl(std::move(realm_decl));

  // Add Dart server component as a child of Realm Builder
  realm_builder.AddChild(kDartAotEchoServer, kDartAotEchoServerUrl,
                         ChildOptions{.environment = kDartRunnerEnvironment});

  // Route base capabilities to the Dart AOT runner
  realm_builder.AddRoute(
      Route{.capabilities = {Protocol{"fuchsia.logger.LogSink"},
                             Protocol{"fuchsia.tracing.provider.Registry"},
                             Protocol{"fuchsia.posix.socket.Provider"},
                             Protocol{"fuchsia.intl.PropertyProvider"},
                             Protocol{"fuchsia.vulkan.loader.Loader"},
                             Directory{"config-data"}},
            .source = ParentRef(),
            .targets = {kDartAotRunnerRef, kDartAotEchoServerRef}});

  // Route the Echo FIDL protocol, this allows the Dart echo server to
  // communicate with the Realm Builder
  realm_builder.AddRoute(
      Route{.capabilities = {Protocol{"flutter.example.echo.Echo"}},
            .source = kDartAotEchoServerRef,
            .targets = {ParentRef()}});

  // Build the Realm with the provided child and protocols
  auto realm = realm_builder.Build(dispatcher());
  FML_LOG(INFO) << "Realm built: " << realm.component().GetChildName();
  // Connect to the Dart echo server
  auto echo = realm.component().ConnectSync<flutter::example::echo::Echo>();
  fidl::StringPtr response;
  // Attempt to ping the Dart echo server for a response
  echo->EchoString("hello", &response);
  ASSERT_EQ(response, "hello");
}

}  // namespace
}  // namespace dart_aot_runner_testing::testing
