// Copyright 2020 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 <fuchsia/sysmem/cpp/fidl.h>
#include <lib/fzl/vmo-mapper.h>
#include <lib/sys/cpp/component_context.h>
#include <zircon/status.h>
#include <zircon/types.h>

#include "src/camera/lib/virtual_camera/virtual_camera.h"
#include "src/lib/testing/loop_fixture/real_loop_fixture.h"

class VirtualCameraTest : public gtest::RealLoopFixture {
 public:
  VirtualCameraTest() { context_ = sys::ComponentContext::Create(); }

 protected:
  virtual void SetUp() override {
    context_->svc()->Connect(allocator_.NewRequest());
    SetFailOnError(allocator_);
    fidl::InterfaceHandle<fuchsia::sysmem::Allocator> allocator;
    context_->svc()->Connect(allocator.NewRequest());
    auto result = camera::VirtualCamera::Create(std::move(allocator));
    ASSERT_TRUE(result.is_ok());
    virtual_camera_ = result.take_value();
  }

  virtual void TearDown() override {
    virtual_camera_ = nullptr;
    allocator_ = nullptr;
  }

  template <class T>
  static void SetFailOnError(fidl::InterfacePtr<T>& ptr, std::string name = T::Name_) {
    ptr.set_error_handler([=](zx_status_t status) {
      ADD_FAILURE() << name << " server disconnected: " << zx_status_get_string(status);
    });
  }

  void RunLoopUntilFailureOr(bool& condition) {
    RunLoopUntil([&]() { return HasFailure() || condition; });
  }

  std::unique_ptr<sys::ComponentContext> context_;
  fuchsia::sysmem::AllocatorPtr allocator_;
  std::unique_ptr<camera::VirtualCamera> virtual_camera_;
};

TEST_F(VirtualCameraTest, FramesReceived) {
  fuchsia::camera3::DevicePtr camera;
  SetFailOnError(camera, "Camera");
  virtual_camera_->GetHandler()(camera.NewRequest());

  bool configurations_received = false;
  camera->GetConfigurations([&](std::vector<fuchsia::camera3::Configuration> configurations) {
    ASSERT_FALSE(configurations.empty());
    ASSERT_FALSE(configurations[0].streams.empty());
    configurations_received = true;
  });
  RunLoopUntilFailureOr(configurations_received);
  ASSERT_FALSE(HasFailure());

  fuchsia::camera3::StreamPtr stream;
  SetFailOnError(stream, "Stream");
  camera->ConnectToStream(0, stream.NewRequest());

  fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> token;
  allocator_->AllocateSharedCollection(token.NewRequest());
  stream->SetBufferCollection(std::move(token));
  fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> client_token;
  bool token_received = false;
  stream->WatchBufferCollection(
      [&](fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> token) {
        client_token = std::move(token);
        token_received = true;
      });
  RunLoopUntilFailureOr(token_received);

  fuchsia::sysmem::BufferCollectionPtr collection;
  SetFailOnError(collection);
  allocator_->BindSharedCollection(std::move(client_token), collection.NewRequest());

  fuchsia::sysmem::BufferCollectionConstraints constraints{
      .usage{.cpu = fuchsia::sysmem::cpuUsageRead}, .min_buffer_count_for_camping = 2};
  collection->SetConstraints(true, constraints);
  fuchsia::sysmem::BufferCollectionInfo_2 buffers_received;
  bool buffers_allocated = false;
  collection->WaitForBuffersAllocated(
      [&](zx_status_t status, fuchsia::sysmem::BufferCollectionInfo_2 buffers) {
        ASSERT_EQ(status, ZX_OK);
        buffers_received = std::move(buffers);
        buffers_allocated = true;
      });
  RunLoopUntilFailureOr(buffers_allocated);
  ASSERT_FALSE(HasFailure());
  collection->Close();

  constexpr uint32_t kTargetFrameCount = 11;
  uint32_t frames_received = 0;
  bool all_frames_received = false;
  fit::function<void(fuchsia::camera3::FrameInfo)> check_frame;
  check_frame = [&](fuchsia::camera3::FrameInfo info) {
    fzl::VmoMapper mapper;
    ASSERT_EQ(mapper.Map(buffers_received.buffers[info.buffer_index].vmo, 0,
                         buffers_received.settings.buffer_settings.size_bytes, ZX_VM_PERM_READ),
              ZX_OK);
    auto result = virtual_camera_->CheckFrame(mapper.start(), mapper.size(), info);
    EXPECT_TRUE(result.is_ok()) << result.error();
    result = virtual_camera_->CheckFrame(mapper.start(), 0, info);
    EXPECT_TRUE(result.is_error());
    mapper.Unmap();
    std::vector<char> zeros(0, mapper.size());
    result = virtual_camera_->CheckFrame(zeros.data(), zeros.size(), info);
    EXPECT_TRUE(result.is_error());
    if (++frames_received < kTargetFrameCount) {
      stream->GetNextFrame(check_frame.share());
    } else {
      all_frames_received = true;
    }
  };
  stream->GetNextFrame(check_frame.share());
  RunLoopUntilFailureOr(all_frames_received);
  ASSERT_FALSE(HasFailure());
}
