// 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/flow/frame_timings.h"
#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](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {
        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
