// Copyright 2022 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 "src/ui/testing/util/test_view.h"

#include <fuchsia/ui/app/cpp/fidl.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/ui/scenic/cpp/view_creation_tokens.h>
#include <lib/ui/scenic/cpp/view_identity.h>
#include <zircon/status.h>

#include "sdk/lib/syslog/cpp/macros.h"
#include "src/lib/fsl/handles/object_info.h"

namespace ui_testing {

using fuchsia::ui::composition::ContentId;
using fuchsia::ui::composition::TransformId;

void TestViewAccess::SetTestView(const fxl::WeakPtr<TestView>& view) { test_view_ = view; }

void TestView::OnStart() {
  FX_CHECK(outgoing()->AddPublicService(
               fidl::InterfaceRequestHandler<fuchsia::ui::app::ViewProvider>([this](auto request) {
                 view_provider_bindings_.AddBinding(this, std::move(request), dispatcher_);
               })) == ZX_OK);
}

std::optional<zx_koid_t> TestView::GetViewRefKoid() {
  if (!view_ref_)
    return std::nullopt;

  return fsl::GetKoid(view_ref_->reference.get());
}

void TestView::DrawContent() {
  FX_CHECK(width() > 0);
  FX_CHECK(height() > 0);

  if (content_type_ == ContentType::COORDINATE_GRID) {
    DrawCoordinateGrid();
  } else {
    DrawSimpleBackground();
  }

  PresentChanges();
}

void TestView::DrawCoordinateGrid() {
  const uint32_t view_width = width();
  const uint32_t view_height = height();

  FX_LOGS(INFO) << "Test view width " << view_width;
  FX_LOGS(INFO) << "Test view height " << view_height;

  const uint32_t pane_width =
      static_cast<uint32_t>(std::ceil(static_cast<float>(view_width) / 2.f));

  const uint32_t pane_height =
      static_cast<uint32_t>(std::ceil(static_cast<float>(view_height) / 2.f));

  for (uint8_t i = 0; i < 2; i++) {
    for (uint8_t j = 0; j < 2; j++) {
      // Compute width and height as integers.
      DrawRectangle(/* x = */ i * pane_width,
                    /* y = */ j * pane_height,
                    /* z = */ -20,
                    /* width = */ pane_width,
                    /* height = */ pane_height,
                    /* red = */ i * 255,
                    /* green = */ 0,
                    /* blue = */ j * 255,
                    /* alpha = */ 255);
    }
  }

  DrawRectangle(/* x = */ 3 * view_width / 8,
                /* y = */ 3 * view_height / 8,
                /* z = */ -40,
                /* width = */ view_width / 4,
                /* height = */ view_height / 4,
                /* red = */ 0,
                /* green = */ 255,
                /* blue = */ 0,
                /* alpha = */ 255);
}

void TestView::DrawSimpleBackground() {
  DrawRectangle(/* x = */ 0,
                /* y = */ 0,
                /* z = */ 0,
                /* width = */ width(),
                /* height = */ height(),
                /* red = */ 0,
                /* green = */ 255,
                /* blue = */ 0,
                /* alpha = */ 255);
}

void TestView::DrawRectangle(int32_t x, int32_t y, int32_t z, uint32_t width, uint32_t height,
                             uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) {
  const ContentId kFilledRectId = {next_resource_id_++};
  const TransformId kTransformId = {next_resource_id_++};

  float red_f = static_cast<float>(red) / 255.f;
  float green_f = static_cast<float>(green) / 255.f;
  float blue_f = static_cast<float>(blue) / 255.f;
  float alpha_f = static_cast<float>(alpha) / 255.f;

  flatland_->CreateFilledRect(kFilledRectId);
  flatland_->SetSolidFill(kFilledRectId, {red_f, green_f, blue_f, alpha_f}, {width, height});

  // Associate the rect with a transform.
  flatland_->CreateTransform(kTransformId);
  flatland_->SetContent(kTransformId, kFilledRectId);
  flatland_->SetTranslation(kTransformId, {x, y});

  // Attach the transform to the view.
  flatland_->AddChild(TransformId{kRectangleHolderTransform}, kTransformId);
}

void TestView::PresentChanges() { flatland_->Present(fuchsia::ui::composition::PresentArgs{}); }

void TestView::ResizeChildViewport() {
  if (!child_view_is_nested) {
    return;
  }

  fuchsia::ui::composition::ViewportProperties viewport_properties;
  viewport_properties.set_logical_size({std::max(1u, width() / 4), std::max(1u, height() / 4)});
  flatland_->SetViewportProperties(ContentId{.value = kChildViewportContentId},
                                   fidl::Clone(viewport_properties));

  flatland_->SetTranslation(
      TransformId{.value = kChildViewportTransformId},
      {static_cast<int32_t>(width() * 3 / 8), static_cast<int32_t>(height() * 3 / 8)});
  PresentChanges();
}

void TestView::CreateView2(fuchsia::ui::app::CreateView2Args args) {
  flatland_ = svc().Connect<fuchsia::ui::composition::Flatland>();
  flatland_.set_error_handler([](zx_status_t status) {
    FX_LOGS(ERROR) << "Error from fuchsia::ui::composition::Flatland: "
                   << zx_status_get_string(status);
  });
  flatland_->SetDebugName("TestView");

  // Set up parent watcher to retrieve layout info.
  parent_watcher_.set_error_handler([](zx_status_t status) {
    FX_LOGS(ERROR) << "Error from fuchsia::ui::composition::ParentViewportWatcher: "
                   << zx_status_get_string(status);
  });
  // Create a11y view's ViewRef.
  auto view_identity = scenic::NewViewIdentityOnCreation();
  view_ref_ = fidl::Clone(view_identity.view_ref);

  flatland_->CreateView2(std::move(*args.mutable_view_creation_token()), std::move(view_identity),
                         /* view_bound_protocols = */ {}, parent_watcher_.NewRequest());

  flatland_->CreateTransform(TransformId({.value = kRootTransformId}));
  flatland_->SetRootTransform(TransformId({.value = kRootTransformId}));

  flatland_->CreateTransform(TransformId({.value = kRectangleHolderTransform}));
  flatland_->AddChild(TransformId({.value = kRootTransformId}),
                      TransformId({.value = kRectangleHolderTransform}));

  parent_watcher_->GetLayout([this](fuchsia::ui::composition::LayoutInfo layout_info) {
    layout_info_ = std::move(layout_info);

    DrawContent();
    ResizeChildViewport();
  });
}

void TestView::NestChildView() {
  FX_CHECK(!child_view_is_nested);

  child_view_is_nested = true;

  auto child_view_provider = svc().Connect<fuchsia::ui::app::ViewProvider>();

  auto [child_view_token, child_viewport_token] = scenic::ViewCreationTokenPair::New();

  fuchsia::ui::app::CreateView2Args args;
  args.set_view_creation_token(std::move(child_view_token));
  child_view_provider->CreateView2(std::move(args));

  fuchsia::ui::composition::ViewportProperties viewport_properties;
  viewport_properties.set_logical_size({std::max(1u, width() / 4), std::max(1u, height() / 4)});
  {
    fuchsia::ui::composition::ChildViewWatcherPtr unused_watcher;
    flatland_->CreateViewport(ContentId{.value = kChildViewportContentId},
                              std::move(child_viewport_token), fidl::Clone(viewport_properties),
                              unused_watcher.NewRequest());
  }

  flatland_->CreateTransform(TransformId{.value = kChildViewportTransformId});
  flatland_->SetContent(TransformId{.value = kChildViewportTransformId},
                        ContentId{.value = kChildViewportContentId});
  flatland_->AddChild(TransformId{.value = kRootTransformId},
                      TransformId{.value = kChildViewportTransformId});
  flatland_->SetTranslation(
      TransformId{.value = kChildViewportTransformId},
      {static_cast<int32_t>(width() * 3 / 8), static_cast<int32_t>(height() * 3 / 8)});

  PresentChanges();
}

uint32_t TestView::width() {
  FX_CHECK(layout_info_);
  return layout_info_->logical_size().width;
}

uint32_t TestView::height() {
  FX_CHECK(layout_info_);
  return layout_info_->logical_size().height;
}

}  // namespace ui_testing
