// Copyright 2018 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 <fstream>
#include <map>
#include <ostream>
#include <string>
#include <vector>

#include <fuchsia/ui/policy/cpp/fidl.h>
#include <fuchsia/ui/scenic/cpp/fidl.h>

#include <gtest/gtest.h>
#include <lib/async/cpp/task.h>
#include <lib/component/cpp/testing/test_with_environment.h>
#include <lib/fsl/vmo/vector.h>
#include <lib/fxl/logging.h>
#include <lib/fxl/strings/string_printf.h>
#include <lib/ui/gfx/cpp/math.h>
#include <lib/ui/scenic/cpp/resources.h>
#include <lib/ui/scenic/cpp/session.h>

namespace {

constexpr char kEnvironment[] = "ScenicPixelTest";

// These tests need Scenic and RootPresenter at minimum, which expand to the
// dependencies below. Using |TestWithEnvironment|, we use
// |fuchsia.sys.Environment| and |fuchsia.sys.Loader| from the system (declared
// in our *.cmx sandbox) and launch these other services in the environment we
// create in our test fixture.
//
// Another way to do this would be to whitelist these services in our sandbox
// and inject/start them via the |fuchsia.test| facet. However that has the
// disadvantage that it uses one instance of those services across all tests in
// the binary, making each test not hermetic wrt. the others. A trade-off is
// that the |TestWithEnvironment| method is more verbose.
const std::map<std::string, std::string> kServices = {
    {"fuchsia.tracelink.Registry",
     "fuchsia-pkg://fuchsia.com/trace_manager#meta/trace_manager.cmx"},
    {"fuchsia.ui.policy.Presenter2",
     "fuchsia-pkg://fuchsia.com/root_presenter#meta/root_presenter.cmx"},
    {"fuchsia.ui.scenic.Scenic",
     "fuchsia-pkg://fuchsia.com/scenic#meta/scenic.cmx"},
    {"fuchsia.vulkan.loader.Loader",
     "fuchsia-pkg://fuchsia.com/vulkan_loader#meta/vulkan_loader.cmx"}};

struct ViewContext {
  scenic::SessionPtrAndListenerRequest session_and_listener_request;
  zx::eventpair view_token;
};

// Represents a view that allows a callback to be set for its |Present|.
class TestView {
 public:
  virtual ~TestView() = default;
  virtual void set_present_callback(
      scenic::Session::PresentCallback present_callback) = 0;
};

// Test fixture that sets up an environment suitable for Scenic pixel tests
// and provides related utilities. The environment includes Scenic and
// RootPresenter, and their dependencies.
class ScenicPixelTest : public component::testing::TestWithEnvironment {
 protected:
  ScenicPixelTest() {
    std::unique_ptr<component::testing::EnvironmentServices> services =
        CreateServices();

    for (const auto& entry : kServices) {
      fuchsia::sys::LaunchInfo launch_info;
      launch_info.url = entry.second;
      services->AddServiceWithLaunchInfo(std::move(launch_info), entry.first);
    }

    environment_ =
        CreateNewEnclosingEnvironment(kEnvironment, std::move(services));

    environment_->ConnectToService(scenic_.NewRequest());
    scenic_.set_error_handler([this](zx_status_t status) {
      FAIL() << "Lost connection to Scenic: " << status;
    });
  }

  // Blocking wrapper around |Scenic::TakeScreenshot|. This should not be called
  // from within a loop |Run|, as it spins up its own to block and nested loops
  // are undefined behavior.
  fuchsia::ui::scenic::ScreenshotData TakeScreenshot() {
    fuchsia::ui::scenic::ScreenshotData screenshot_out;
    scenic_->TakeScreenshot(
        [this, &screenshot_out](fuchsia::ui::scenic::ScreenshotData screenshot,
                                bool status) {
          EXPECT_TRUE(status) << "Failed to take screenshot";
          screenshot_out = std::move(screenshot);
          QuitLoop();
        });
    RunLoop();
    return screenshot_out;
  }

  // Dumps the screenshot to a shared temporary file and returns the filename.
  std::string DumpScreenshot(fuchsia::ui::scenic::ScreenshotData screenshot) {
    std::vector<uint8_t> data;
    EXPECT_TRUE(fsl::VectorFromVmo(screenshot.data, &data))
        << "Failed to read screenshot";
    const auto* test_info =
        testing::UnitTest::GetInstance()->current_test_info();
    std::ostringstream filename;
    filename << "/tmp/screenshot-" << test_info->test_case_name()
             << "::" << test_info->name() << "-" << screenshot_index_;

    std::ofstream fout(filename.str());
    EXPECT_TRUE(fout.good())
        << "Failed to open " << filename.str() << " for writing";

    // Convert to PPM. We'll probably need PNG instead for Skia Gold.
    fout << "P6\n"
         << screenshot.info.width << "\n"
         << screenshot.info.height << "\n"
         << 255 << "\n";

    const uint8_t* pchannel = data.data();
    for (uint32_t pixel = 0;
         pixel < screenshot.info.width * screenshot.info.height; pixel++) {
      uint8_t rgb[] = {pchannel[2], pchannel[1], pchannel[0]};
      fout.write(reinterpret_cast<const char*>(rgb), 3);
      pchannel += 4;
    }

    fout.flush();

    EXPECT_TRUE(fout.good())
        << "Failed to write screenshot to " << filename.str();

    ++screenshot_index_;
    return filename.str();
  }

  // Create a |ViewContext| that allows us to present a view via
  // |RootPresenter|. See also examples/ui/hello_base_view
  ViewContext CreatePresentationContext() {
    zx::eventpair view_holder_token, view_token;
    FXL_CHECK(zx::eventpair::create(0u, &view_holder_token, &view_token) ==
              ZX_OK);

    ViewContext view_context = {
        .session_and_listener_request =
            scenic::CreateScenicSessionPtrAndListenerRequest(scenic_.get()),
        .view_token = std::move(view_token),
    };

    fuchsia::ui::policy::Presenter2Ptr presenter;
    environment_->ConnectToService(presenter.NewRequest());
    presenter->PresentView(std::move(view_holder_token), nullptr);

    return view_context;
  }

  // Runs until the view renders its next frame. Technically, waits until the
  // |Present| callback is invoked with an expected presentation timestamp, and
  // then waits until that time.
  void RunUntilPresent(TestView* view) {
    view->set_present_callback([this](fuchsia::images::PresentationInfo info) {
      async::PostTaskForTime(dispatcher(), QuitLoopClosure(),
                             static_cast<zx::time>(info.presentation_time));
    });

    RunLoop();
  }

  fuchsia::ui::scenic::ScenicPtr scenic_;

 private:
  std::unique_ptr<component::testing::EnclosingEnvironment> environment_;
  uint screenshot_index_ = 0;
};

struct Color {
  uint8_t r;
  uint8_t g;
  uint8_t b;
  uint8_t a;
};

inline bool operator==(const Color& a, const Color& b) {
  return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
}

inline bool operator<(const Color& a, const Color& b) {
  return std::tie(a.r, a.g, a.b, a.a) < std::tie(b.r, b.g, b.b, b.a);
}

// RGBA hex dump
std::ostream& operator<<(std::ostream& os, const Color& c) {
  return os << fxl::StringPrintf("%02X%02X%02X%02X", c.r, c.g, c.b, c.a);
}

// Base view with a solid background.
// See also lib/ui/base_view
class BackgroundView : public TestView,
                       private fuchsia::ui::scenic::SessionListener {
 public:
  static constexpr float kBackgroundElevation = 0.f;
  static constexpr Color kBackgroundColor = {0x67, 0x3a, 0xb7,
                                             0xff};  // Deep Purple 500

  BackgroundView(ViewContext context,
                 const std::string& debug_name = "BackgroundView")
      : binding_(this, std::move(context.session_and_listener_request.second)),
        session_(std::move(context.session_and_listener_request.first)),
        view_(&session_, std::move(context.view_token), debug_name),
        background_node_(&session_) {
    binding_.set_error_handler([](zx_status_t status) { FAIL() << status; });
    session_.Present(0, [](auto) {});

    scenic::Material background_material(&session_);
    background_material.SetColor(kBackgroundColor.r, kBackgroundColor.g,
                                 kBackgroundColor.b, kBackgroundColor.a);
    background_node_.SetMaterial(background_material);
    view_.AddChild(background_node_);
  }

  void set_present_callback(
      scenic::Session::PresentCallback present_callback) override {
    present_callback_ = std::move(present_callback);
  }

 protected:
  scenic::Session* session() { return &session_; }

  scenic::View* view() { return &view_; }

  virtual void Draw(float cx, float cy, float sx, float sy) {
    scenic::Rectangle background_shape(&session_, sx, sy);
    background_node_.SetShape(background_shape);
    background_node_.SetTranslation((float[]){cx, cy, kBackgroundElevation});
  }

 private:
  void OnScenicEvent(std::vector<fuchsia::ui::scenic::Event> events) override {
    for (const auto& event : events) {
      if (event.Which() == fuchsia::ui::scenic::Event::Tag::kGfx &&
          event.gfx().Which() ==
              fuchsia::ui::gfx::Event::Tag::kViewPropertiesChanged) {
        const auto& evt = event.gfx().view_properties_changed();
        fuchsia::ui::gfx::BoundingBox layout_box =
            scenic::ViewPropertiesLayoutBox(evt.properties);

        const auto sz = scenic::Max(layout_box.max - layout_box.min, 0.f);
        OnViewPropertiesChanged(sz);
      }
    }
  }

  void OnScenicError(std::string error) override { FAIL() << error; }

  void OnViewPropertiesChanged(const fuchsia::ui::gfx::vec3& sz) {
    if (!sz.x || !sz.y || !sz.z)
      return;

    Draw(sz.x * .5f, sz.y * .5f, sz.x, sz.y);

    session_.Present(0, std::move(present_callback_));
  }

  fidl::Binding<fuchsia::ui::scenic::SessionListener> binding_;
  scenic::Session session_;
  scenic::View view_;

  scenic::ShapeNode background_node_;
  scenic::Session::PresentCallback present_callback_;
};

// Displays a static frame of the Spinning Square example.
// See also examples/ui/spinning_square
class RotatedSquareView : public BackgroundView {
 public:
  static constexpr float kSquareElevation = 8.f;
  static constexpr float kAngle = M_PI / 4;

  RotatedSquareView(ViewContext context,
                    const std::string& debug_name = "RotatedSquareView")
      : BackgroundView(std::move(context), debug_name),
        square_node_(session()) {
    scenic::Material square_material(session());
    square_material.SetColor(0xf5, 0x00, 0x57, 0xff);  // Pink A400
    square_node_.SetMaterial(square_material);
    view()->AddChild(square_node_);
  }

 private:
  void Draw(float cx, float cy, float sx, float sy) override {
    BackgroundView::Draw(cx, cy, sx, sy);

    const float square_size = std::min(sx, sy) * .6f;

    scenic::Rectangle square_shape(session(), square_size, square_size);
    square_node_.SetShape(square_shape);
    square_node_.SetTranslation((float[]){cx, cy, kSquareElevation});
    square_node_.SetRotation(
        (float[]){0.f, 0.f, sinf(kAngle * .5f), cosf(kAngle * .5f)});
  }

  scenic::ShapeNode square_node_;
};

TEST_F(ScenicPixelTest, SolidColor) {
  BackgroundView view(CreatePresentationContext());
  RunUntilPresent(&view);

  fuchsia::ui::scenic::ScreenshotData screenshot = TakeScreenshot();
  std::vector<uint8_t> data;
  EXPECT_TRUE(fsl::VectorFromVmo(screenshot.data, &data))
      << "Failed to read screenshot";

  EXPECT_GT(screenshot.info.width, 0u);
  EXPECT_GT(screenshot.info.height, 0u);

  // We could assert on each pixel individually, but a histogram might give us a
  // more meaningful failure.
  std::map<Color, size_t> histogram;

  // https://en.wikipedia.org/wiki/Sword_Art_Online_Alternative_Gun_Gale_Online#Characters
  const uint8_t* pchan = data.data();
  const size_t llenn = screenshot.info.width * screenshot.info.height;
  for (uint32_t pixel = 0; pixel < llenn; pixel++) {
    Color color = {pchan[2], pchan[1], pchan[0], pchan[3]};
    ++histogram[color];
    pchan += 4;
  }

  EXPECT_GT(histogram[BackgroundView::kBackgroundColor], 0u);
  histogram.erase(BackgroundView::kBackgroundColor);
  EXPECT_EQ((std::map<Color, size_t>){}, histogram) << "Unexpected colors";
}

// Renders a rotated square to the screen and saves a screenshot for later
// screendiff validation.
TEST_F(ScenicPixelTest, RotatedSquare) {
  RotatedSquareView view(CreatePresentationContext());
  RunUntilPresent(&view);

  const std::string filename = DumpScreenshot(TakeScreenshot());
  FXL_LOG(INFO) << "Wrote screenshot to " << filename;
}

}  // namespace