// Copyright 2019 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/cpp/fidl.h>
#include <fuchsia/devicesettings/cpp/fidl.h>
#include <fuchsia/process/lifecycle/cpp/fidl.h>
#include <fuchsia/settings/cpp/fidl.h>
#include <fuchsia/sys/cpp/fidl.h>
#include <fuchsia/ui/lifecycle/cpp/fidl.h>
#include <fuchsia/ui/policy/cpp/fidl.h>
#include <lib/async/default.h>
#include <lib/fdio/directory.h>
#include <lib/sys/cpp/file_descriptor.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/vfs/cpp/pseudo_file.h>

#include "lib/sys/cpp/testing/test_with_environment.h"
#include "src/lib/files/directory.h"
#include "src/lib/files/file.h"
#include "src/modular/lib/modular_config/modular_config.h"
#include "src/modular/lib/modular_config/modular_config_constants.h"
#include "src/modular/lib/modular_test_harness/cpp/fake_settings_intl.h"

constexpr char kBasemgrUrl[] = "fuchsia-pkg://fuchsia.com/basemgr#meta/basemgr.cmx";

class BasemgrImplTest : public sys::testing::TestWithEnvironment,
                        fuchsia::ui::lifecycle::LifecycleController {
 public:
  BasemgrImplTest() {}

  void SetUp() override {
    // Setup an enclosing environment that provides basemgr with a mock of the cobalt logger
    // factory.
    auto env_services = CreateServices();
    env_services->AddServiceWithLaunchInfo(
        fuchsia::sys::LaunchInfo{.url =
                                     "fuchsia-pkg://fuchsia.com/mock_cobalt#meta/mock_cobalt.cmx"},
        fuchsia::cobalt::LoggerFactory::Name_);

    env_services->AddServiceWithLaunchInfo(
        fuchsia::sys::LaunchInfo{.url = "fuchsia-pkg://fuchsia.com/device_settings_manager#meta/"
                                        "device_settings_manager.cmx"},
        fuchsia::devicesettings::DeviceSettingsManager::Name_);

    env_services->AddService(scenic_lifecycle_controller_bindings_.GetHandler(this));
    env_services->AddService(std::make_unique<vfs::Service>(
                                 [presenter_channels = std::vector<zx::channel>()](
                                     zx::channel channel, async_dispatcher_t* dispatcher) mutable {
                                   presenter_channels.push_back(std::move(channel));
                                 }),
                             fuchsia::ui::policy::Presenter::Name_);

    settings_ = modular_testing::FakeSettingsIntl::CreateWithDefaultOptions();
    env_services->AddService(settings_->GetHandler(), fuchsia::settings::Intl::Name_);

    env_ = CreateNewEnclosingEnvironment("basemgr_impl_unittest_env", std::move(env_services),
                                         {.inherit_parent_services = true});
    WaitForEnclosingEnvToStart(env_.get());
  }

  std::unique_ptr<vfs::PseudoDir> CreateConfigPseudoDir(std::string config_str) {
    auto dir = std::make_unique<vfs::PseudoDir>();
    dir->AddEntry(modular_config::kStartupConfigFilePath,
                  std::make_unique<vfs::PseudoFile>(
                      config_str.length(), [config_str = std::move(config_str)](
                                               std::vector<uint8_t>* out, size_t /*unused*/) {
                        std::copy(config_str.begin(), config_str.end(), std::back_inserter(*out));
                        return ZX_OK;
                      }));
    return dir;
  }

  std::string GetTestConfig() {
    return R"config(
      {
      "basemgr": {
        "enable_cobalt": false,
        "use_session_shell_for_story_shell_factory": false,
        "base_shell": {
          "url": "fuchsia-pkg://fuchsia.com/auto_login_base_shell#meta/auto_login_base_shell.cmx",
          "keep_alive_after_login": false,
          "args": []
        },
        "session_shells": [
          {
            "name": "fuchsia-pkg://fuchsia.com/modular_test_harness#meta/test_session_shell.cmx",
            "url": "fuchsia-pkg://fuchsia.com/modular_test_harness#meta/test_session_shell.cmx",
            "args": []
          }
        ]
      },
      "sessionmgr": {
        "enable_cobalt": false,
        "startup_agents": [],
        "session_agents": [],
        "restart_session_on_agent_crash": [],
        "component_args": [],
        "agent_service_index": []
      }
    }
    )config";
  }

  std::shared_ptr<sys::ServiceDirectory> LaunchBasemgrWithConfigJson(std::string config_str) {
    // Create the pseudo directory with our config "file"
    auto config_dir = CreateConfigPseudoDir(config_str);
    fidl::InterfaceHandle<fuchsia::io::Directory> config_dir_handle;
    config_dir->Serve(fuchsia::io::OPEN_RIGHT_READABLE,
                      config_dir_handle.NewRequest().TakeChannel());

    zx::channel svc_request;
    auto svc_dir = sys::ServiceDirectory::CreateWithRequest(&svc_request);
    FX_CHECK(svc_request.is_valid());

    fuchsia::sys::LaunchInfo launch_info;
    launch_info.url = kBasemgrUrl;
    launch_info.flat_namespace = fuchsia::sys::FlatNamespace::New();
    launch_info.flat_namespace->paths.push_back(modular_config::kOverriddenConfigDir);
    launch_info.flat_namespace->directories.push_back(config_dir_handle.TakeChannel());
    launch_info.directory_request = std::move(svc_request);

    bool on_directory_ready = false;
    controller_.events().OnDirectoryReady = [&] { on_directory_ready = true; };
    env_->CreateComponent(std::move(launch_info), controller_.NewRequest());

    RunLoopUntil([&] { return on_directory_ready; });
    return svc_dir;
  }

  int ui_lifecycle_terminate_calls() const { return ui_lifecycle_terminate_calls_; }

 protected:
  // |fuchsia.ui.lifecycle.Controller|
  void Terminate() override {
    ++ui_lifecycle_terminate_calls_;
    scenic_lifecycle_controller_bindings_.CloseAll(ZX_ERR_PEER_CLOSED);
  }

  int ui_lifecycle_terminate_calls_ = 0;

  std::unique_ptr<sys::testing::EnclosingEnvironment> env_;
  std::unique_ptr<modular_testing::FakeSettingsIntl> settings_;
  fuchsia::sys::ComponentControllerPtr controller_;
  fidl::BindingSet<fuchsia::ui::lifecycle::LifecycleController>
      scenic_lifecycle_controller_bindings_;
};

TEST_F(BasemgrImplTest, BasemgrImplGracefulShutdown) {
  auto svc_dir = LaunchBasemgrWithConfigJson(GetTestConfig());

  bool is_terminated = false;
  controller_.events().OnTerminated = [&](int64_t return_code,
                                          fuchsia::sys::TerminationReason reason) {
    EXPECT_EQ(EXIT_SUCCESS, return_code);
    EXPECT_EQ(fuchsia::sys::TerminationReason::EXITED, reason);
    is_terminated = true;
  };

  fuchsia::process::lifecycle::LifecyclePtr process_lifecycle;
  zx_status_t status = svc_dir->Connect("fuchsia.process.lifecycle.Lifecycle",
                                        process_lifecycle.NewRequest().TakeChannel());
  FX_CHECK(ZX_OK == status);
  process_lifecycle->Stop();
  RunLoopUntil([&]() { return is_terminated; });
}

TEST_F(BasemgrImplTest, BasemgrImplGracefulShutdownAlsoShutsDownScenic) {
  auto svc_dir = LaunchBasemgrWithConfigJson(GetTestConfig());

  fuchsia::process::lifecycle::LifecyclePtr process_lifecycle;
  zx_status_t status = svc_dir->Connect("fuchsia.process.lifecycle.Lifecycle",
                                        process_lifecycle.NewRequest().TakeChannel());
  FX_CHECK(ZX_OK == status);

  bool is_terminated = false;
  controller_.events().OnTerminated =
      [&](int64_t return_code, fuchsia::sys::TerminationReason reason) { is_terminated = true; };

  process_lifecycle->Stop();
  RunLoopUntil([&]() { return ui_lifecycle_terminate_calls() > 0; });

  // Ensure basemgr has shut down completely before tearing down the test environment to avoid
  // error logs from the cobalt client in basemgr.
  RunLoopUntil([&]() { return is_terminated; });
}
