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

#include "flutter/fml/make_copyable.h"
#include "flutter/fml/mapping.h"
#include "flutter/fml/paths.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/fml/thread.h"
#include "flutter/runtime/dart_isolate.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/runtime/dart_vm_lifecycle.h"
#include "flutter/runtime/runtime_test.h"
#include "flutter/testing/testing.h"
#include "flutter/testing/thread_test.h"
#include "third_party/tonic/converter/dart_converter.h"
#include "third_party/tonic/scopes/dart_isolate_scope.h"

namespace flutter {
namespace testing {

using DartIsolateTest = RuntimeTest;

TEST_F(DartIsolateTest, RootIsolateCreationAndShutdown) {
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
  auto settings = CreateSettingsForFixture();
  auto vm_ref = DartVMRef::Create(settings);
  ASSERT_TRUE(vm_ref);
  auto vm_data = vm_ref.GetVMData();
  ASSERT_TRUE(vm_data);
  TaskRunners task_runners(::testing::GetCurrentTestName(),  //
                           GetCurrentTaskRunner(),           //
                           GetCurrentTaskRunner(),           //
                           GetCurrentTaskRunner(),           //
                           GetCurrentTaskRunner()            //
  );
  auto weak_isolate = DartIsolate::CreateRootIsolate(
      vm_data->GetSettings(),         // settings
      vm_data->GetIsolateSnapshot(),  // isolate snapshot
      vm_data->GetSharedSnapshot(),   // shared snapshot
      std::move(task_runners),        // task runners
      nullptr,                        // window
      {},                             // snapshot delegate
      {},                             // io manager
      "main.dart",                    // advisory uri
      "main"                          // advisory entrypoint
  );
  auto root_isolate = weak_isolate.lock();
  ASSERT_TRUE(root_isolate);
  ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::LibrariesSetup);
  ASSERT_TRUE(root_isolate->Shutdown());
}

TEST_F(DartIsolateTest, IsolateShutdownCallbackIsInIsolateScope) {
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
  auto settings = CreateSettingsForFixture();
  auto vm_ref = DartVMRef::Create(settings);
  ASSERT_TRUE(vm_ref);
  auto vm_data = vm_ref.GetVMData();
  ASSERT_TRUE(vm_data);
  TaskRunners task_runners(::testing::GetCurrentTestName(),  //
                           GetCurrentTaskRunner(),           //
                           GetCurrentTaskRunner(),           //
                           GetCurrentTaskRunner(),           //
                           GetCurrentTaskRunner()            //
  );
  auto weak_isolate = DartIsolate::CreateRootIsolate(
      vm_data->GetSettings(),         // settings
      vm_data->GetIsolateSnapshot(),  // isolate snapshot
      vm_data->GetSharedSnapshot(),   // shared snapshot
      std::move(task_runners),        // task runners
      nullptr,                        // window
      {},                             // snapshot delegate
      {},                             // io manager
      "main.dart",                    // advisory uri
      "main"                          // advisory entrypoint
  );
  auto root_isolate = weak_isolate.lock();
  ASSERT_TRUE(root_isolate);
  ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::LibrariesSetup);
  size_t destruction_callback_count = 0;
  root_isolate->AddIsolateShutdownCallback([&destruction_callback_count]() {
    ASSERT_NE(Dart_CurrentIsolate(), nullptr);
    destruction_callback_count++;
  });
  ASSERT_TRUE(root_isolate->Shutdown());
  ASSERT_EQ(destruction_callback_count, 1u);
}

class AutoIsolateShutdown {
 public:
  AutoIsolateShutdown() = default;

  AutoIsolateShutdown(std::shared_ptr<DartIsolate> isolate,
                      fml::RefPtr<fml::TaskRunner> runner)
      : isolate_(std::move(isolate)), runner_(std::move(runner)) {}

  ~AutoIsolateShutdown() {
    if (!IsValid()) {
      return;
    }
    fml::AutoResetWaitableEvent latch;
    fml::TaskRunner::RunNowOrPostTask(runner_, [isolate = isolate_, &latch]() {
      FML_LOG(INFO) << "Shutting down isolate.";
      if (!isolate->Shutdown()) {
        FML_LOG(ERROR) << "Could not shutdown isolate.";
        FML_CHECK(false);
      }
      latch.Signal();
    });
    latch.Wait();
  }

  bool IsValid() const { return isolate_ != nullptr && runner_; }

  FML_WARN_UNUSED_RESULT
  bool RunInIsolateScope(std::function<bool(void)> closure) {
    if (!IsValid()) {
      return false;
    }

    bool result = false;
    fml::AutoResetWaitableEvent latch;
    fml::TaskRunner::RunNowOrPostTask(
        runner_, [this, &result, &latch, closure]() {
          tonic::DartIsolateScope scope(isolate_->isolate());
          tonic::DartApiScope api_scope;
          if (closure) {
            result = closure();
          }
          latch.Signal();
        });
    latch.Wait();
    return true;
  }

  DartIsolate* get() {
    FML_CHECK(isolate_);
    return isolate_.get();
  }

 private:
  std::shared_ptr<DartIsolate> isolate_;
  fml::RefPtr<fml::TaskRunner> runner_;

  FML_DISALLOW_COPY_AND_ASSIGN(AutoIsolateShutdown);
};

static void RunDartCodeInIsolate(DartVMRef& vm_ref,
                                 std::unique_ptr<AutoIsolateShutdown>& result,
                                 const Settings& settings,
                                 fml::RefPtr<fml::TaskRunner> task_runner,
                                 std::string entrypoint) {
  FML_CHECK(task_runner->RunsTasksOnCurrentThread());

  if (!vm_ref) {
    return;
  }

  TaskRunners task_runners(::testing::GetCurrentTestName(),  //
                           task_runner,                      //
                           task_runner,                      //
                           task_runner,                      //
                           task_runner                       //
  );

  auto vm_data = vm_ref.GetVMData();

  if (!vm_data) {
    return;
  }

  auto weak_isolate = DartIsolate::CreateRootIsolate(
      vm_data->GetSettings(),         // settings
      vm_data->GetIsolateSnapshot(),  // isolate snapshot
      vm_data->GetSharedSnapshot(),   // shared snapshot
      std::move(task_runners),        // task runners
      nullptr,                        // window
      {},                             // snapshot delegate
      {},                             // io manager
      "main.dart",                    // advisory uri
      "main"                          // advisory entrypoint
  );

  auto root_isolate =
      std::make_unique<AutoIsolateShutdown>(weak_isolate.lock(), task_runner);

  if (!root_isolate->IsValid()) {
    FML_LOG(ERROR) << "Could not create isolate.";
    return;
  }

  if (root_isolate->get()->GetPhase() != DartIsolate::Phase::LibrariesSetup) {
    FML_LOG(ERROR) << "Created isolate is in unexpected phase.";
    return;
  }

  if (!DartVM::IsRunningPrecompiledCode()) {
    auto kernel_file_path = fml::paths::JoinPaths(
        {::testing::GetFixturesPath(), "kernel_blob.bin"});

    if (!fml::IsFile(kernel_file_path)) {
      FML_LOG(ERROR) << "Could not locate kernel file.";
      return;
    }

    auto kernel_file = fml::OpenFile(kernel_file_path.c_str(), false,
                                     fml::FilePermission::kRead);

    if (!kernel_file.is_valid()) {
      FML_LOG(ERROR) << "Kernel file descriptor was invalid.";
      return;
    }

    auto kernel_mapping = std::make_unique<fml::FileMapping>(kernel_file);

    if (kernel_mapping->GetMapping() == nullptr) {
      FML_LOG(ERROR) << "Could not setup kernel mapping.";
      return;
    }

    if (!root_isolate->get()->PrepareForRunningFromKernel(
            std::move(kernel_mapping))) {
      FML_LOG(ERROR)
          << "Could not prepare to run the isolate from the kernel file.";
      return;
    }
  } else {
    if (!root_isolate->get()->PrepareForRunningFromPrecompiledCode()) {
      FML_LOG(ERROR)
          << "Could not prepare to run the isolate from precompiled code.";
      return;
    }
  }

  if (root_isolate->get()->GetPhase() != DartIsolate::Phase::Ready) {
    FML_LOG(ERROR) << "Isolate is in unexpected phase.";
    return;
  }

  if (!root_isolate->get()->Run(entrypoint,
                                settings.root_isolate_create_callback)) {
    FML_LOG(ERROR) << "Could not run the method \"" << entrypoint
                   << "\" in the isolate.";
    return;
  }

  root_isolate->get()->AddIsolateShutdownCallback(
      settings.root_isolate_shutdown_callback);

  result = std::move(root_isolate);
}

static std::unique_ptr<AutoIsolateShutdown> RunDartCodeInIsolate(
    DartVMRef& vm_ref,
    const Settings& settings,
    fml::RefPtr<fml::TaskRunner> task_runner,
    std::string entrypoint) {
  std::unique_ptr<AutoIsolateShutdown> result;
  fml::AutoResetWaitableEvent latch;
  fml::TaskRunner::RunNowOrPostTask(
      task_runner, fml::MakeCopyable([&]() mutable {
        RunDartCodeInIsolate(vm_ref, result, settings, task_runner, entrypoint);
        latch.Signal();
      }));
  latch.Wait();
  return result;
}

TEST_F(DartIsolateTest, IsolateCanLoadAndRunDartCode) {
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
  const auto settings = CreateSettingsForFixture();
  auto vm_ref = DartVMRef::Create(settings);
  auto isolate =
      RunDartCodeInIsolate(vm_ref, settings, GetCurrentTaskRunner(), "main");
  ASSERT_TRUE(isolate);
  ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
}

TEST_F(DartIsolateTest, IsolateCannotLoadAndRunUnknownDartEntrypoint) {
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
  const auto settings = CreateSettingsForFixture();
  auto vm_ref = DartVMRef::Create(settings);
  auto isolate = RunDartCodeInIsolate(vm_ref, settings, GetCurrentTaskRunner(),
                                      "thisShouldNotExist");
  ASSERT_FALSE(isolate);
}

TEST_F(DartIsolateTest, CanRunDartCodeCodeSynchronously) {
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
  const auto settings = CreateSettingsForFixture();
  auto vm_ref = DartVMRef::Create(settings);
  auto isolate =
      RunDartCodeInIsolate(vm_ref, settings, GetCurrentTaskRunner(), "main");

  ASSERT_TRUE(isolate);
  ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
  ASSERT_TRUE(isolate->RunInIsolateScope([]() -> bool {
    if (tonic::LogIfError(::Dart_Invoke(Dart_RootLibrary(),
                                        tonic::ToDart("sayHi"), 0, nullptr))) {
      return false;
    }
    return true;
  }));
}

TEST_F(DartIsolateTest, CanRegisterNativeCallback) {
  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
  fml::AutoResetWaitableEvent latch;
  AddNativeCallback("NotifyNative",
                    CREATE_NATIVE_ENTRY(([&latch](Dart_NativeArguments args) {
                      FML_LOG(ERROR) << "Hello from Dart!";
                      latch.Signal();
                    })));
  const auto settings = CreateSettingsForFixture();
  auto vm_ref = DartVMRef::Create(settings);
  auto isolate = RunDartCodeInIsolate(vm_ref, settings, GetThreadTaskRunner(),
                                      "canRegisterNativeCallback");
  ASSERT_TRUE(isolate);
  ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
  latch.Wait();
}

TEST_F(DartIsolateTest, CanSaveCompilationTrace) {
  if (DartVM::IsRunningPrecompiledCode()) {
    // Can only save compilation traces in JIT modes.
    GTEST_SKIP();
    return;
  }
  fml::AutoResetWaitableEvent latch;
  AddNativeCallback("NotifyNative",
                    CREATE_NATIVE_ENTRY(([&latch](Dart_NativeArguments args) {
                      ASSERT_TRUE(tonic::DartConverter<bool>::FromDart(
                          Dart_GetNativeArgument(args, 0)));
                      latch.Signal();
                    })));

  const auto settings = CreateSettingsForFixture();
  auto vm_ref = DartVMRef::Create(settings);
  auto isolate = RunDartCodeInIsolate(vm_ref, settings, GetThreadTaskRunner(),
                                      "testCanSaveCompilationTrace");
  ASSERT_TRUE(isolate);
  ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);

  latch.Wait();
}

}  // namespace testing
}  // namespace flutter
