// 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 <gtest/gtest.h>
#include <lib/async-loop/default.h>
#include <lib/zx/event.h>
#include <zircon/syscalls.h>

#include <array>

#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/fml/time/time_delta.h"
#include "flutter/fml/time/time_point.h"
#include "flutter/shell/common/thread_host.h"
#include "flutter/shell/common/vsync_waiter.h"
#include "flutter/shell/platform/fuchsia/flutter/flutter_runner_product_configuration.h"
#include "flutter/shell/platform/fuchsia/flutter/task_runner_adapter.h"
#include "flutter/shell/platform/fuchsia/flutter/thread.h"
#include "flutter/shell/platform/fuchsia/flutter/vsync_waiter.h"

namespace flutter_runner_test {

class VsyncWaiterTest : public testing::Test {
 public:
  VsyncWaiterTest() {}

  ~VsyncWaiterTest() = default;

  std::unique_ptr<flutter::VsyncWaiter> CreateVsyncWaiter(
      flutter::TaskRunners task_runners) {
    return std::make_unique<flutter_runner::VsyncWaiter>(
        "VsyncWaiterTest", vsync_event_.get(), task_runners,
        fml::TimeDelta::Zero());
  }

  void SignalVsyncEvent() {
    auto status =
        zx_object_signal(vsync_event_.get(), 0,
                         flutter_runner::VsyncWaiter::SessionPresentSignal);
    EXPECT_EQ(status, ZX_OK);
  }

 protected:
  void SetUp() override {
    auto status = zx::event::create(0, &vsync_event_);
    EXPECT_EQ(status, ZX_OK);
  }

 private:
  zx::event vsync_event_;
};

TEST_F(VsyncWaiterTest, AwaitVsync) {
  std::array<std::unique_ptr<flutter_runner::Thread>, 3> threads;

  for (auto& thread : threads) {
    thread.reset(new flutter_runner::Thread());
  }

  async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);

  const flutter::TaskRunners task_runners(
      "VsyncWaiterTests",  // Dart thread labels
      flutter_runner::CreateFMLTaskRunner(
          async_get_default_dispatcher()),  // platform
      flutter_runner::CreateFMLTaskRunner(threads[0]->dispatcher()),  // raster
      flutter_runner::CreateFMLTaskRunner(threads[1]->dispatcher()),  // ui
      flutter_runner::CreateFMLTaskRunner(threads[2]->dispatcher())   // io
  );

  auto vsync_waiter = CreateVsyncWaiter(std::move(task_runners));

  fml::AutoResetWaitableEvent latch;
  vsync_waiter->AsyncWaitForVsync(
      [&latch](fml::TimePoint frame_start_time,
               fml::TimePoint frame_target_time) { latch.Signal(); });
  SignalVsyncEvent();

  bool did_timeout =
      latch.WaitWithTimeout(fml::TimeDelta::FromMilliseconds(5000));

  // False indicates we were signalled rather than timed out
  EXPECT_FALSE(did_timeout);

  vsync_waiter.reset();
  for (const auto& thread : threads) {
    thread->Quit();
  }
}

TEST_F(VsyncWaiterTest, SnapToNextPhaseOverlapsWithNow) {
  const auto now = fml::TimePoint::Now();
  const auto last_presentation_time = now - fml::TimeDelta::FromNanoseconds(10);
  const auto delta = fml::TimeDelta::FromNanoseconds(10);
  const auto next_vsync = flutter_runner::VsyncWaiter::SnapToNextPhase(
      now, last_presentation_time, delta);

  EXPECT_EQ(now + delta, next_vsync);
}

TEST_F(VsyncWaiterTest, SnapToNextPhaseAfterNow) {
  const auto now = fml::TimePoint::Now();
  const auto last_presentation_time = now - fml::TimeDelta::FromNanoseconds(9);
  const auto delta = fml::TimeDelta::FromNanoseconds(10);
  const auto next_vsync = flutter_runner::VsyncWaiter::SnapToNextPhase(
      now, last_presentation_time, delta);

  // math here: 10 - 9 = 1
  EXPECT_EQ(now + fml::TimeDelta::FromNanoseconds(1), next_vsync);
}

TEST_F(VsyncWaiterTest, SnapToNextPhaseAfterNowMultiJump) {
  const auto now = fml::TimePoint::Now();
  const auto last_presentation_time = now - fml::TimeDelta::FromNanoseconds(34);
  const auto delta = fml::TimeDelta::FromNanoseconds(10);
  const auto next_vsync = flutter_runner::VsyncWaiter::SnapToNextPhase(
      now, last_presentation_time, delta);

  // zeroes: -34, -24, -14, -4, 6, ...
  EXPECT_EQ(now + fml::TimeDelta::FromNanoseconds(6), next_vsync);
}

TEST_F(VsyncWaiterTest, SnapToNextPhaseAfterNowMultiJumpAccountForCeils) {
  const auto now = fml::TimePoint::Now();
  const auto last_presentation_time = now - fml::TimeDelta::FromNanoseconds(20);
  const auto delta = fml::TimeDelta::FromNanoseconds(16);
  const auto next_vsync = flutter_runner::VsyncWaiter::SnapToNextPhase(
      now, last_presentation_time, delta);

  // zeroes: -20, -4, 12, 28, ...
  EXPECT_EQ(now + fml::TimeDelta::FromNanoseconds(12), next_vsync);
}

}  // namespace flutter_runner_test
