// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/capture/video/chromeos/camera_app_device_impl.h"

#include <algorithm>
#include <cmath>

#include "base/task/bind_post_task.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "chromeos/ash/components/mojo_service_manager/connection.h"
#include "gpu/ipc/common/gpu_memory_buffer_impl.h"
#include "media/capture/video/chromeos/camera_app_device_bridge_impl.h"
#include "media/capture/video/chromeos/camera_device_context.h"
#include "media/capture/video/chromeos/camera_metadata_utils.h"
#include "media/capture/video/chromeos/mojom/document_scanner.mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/cros_system_api/mojo/service_constants.h"
#include "third_party/libyuv/include/libyuv.h"

namespace media {

namespace {

constexpr int kDetectionWidth = 256;
constexpr int kDetectionHeight = 256;

}  // namespace

class CameraAppDeviceImpl::DocumentScanner {
 public:
  using DetectCornersFromNV12ImageCallback =
      base::OnceCallback<void(bool success,
                              const std::vector<gfx::PointF>& results)>;

  DocumentScanner() {
    if (!ash::mojo_service_manager::IsServiceManagerBound()) {
      return;
    }
    ash::mojo_service_manager::GetServiceManagerProxy()->Request(
        chromeos::mojo_services::kCrosDocumentScanner, std::nullopt,
        document_scanner_remote_.BindNewPipeAndPassReceiver().PassPipe());
  }

  DocumentScanner(const DocumentScanner&) = delete;
  DocumentScanner& operator=(const DocumentScanner&) = delete;

  ~DocumentScanner() = default;

  void DetectCornersFromNV12Image(base::ReadOnlySharedMemoryRegion nv12_image,
                                  DetectCornersFromNV12ImageCallback callback) {
    document_scanner_remote_->DetectCornersFromNV12Image(
        std::move(nv12_image),
        base::BindOnce(
            [](DetectCornersFromNV12ImageCallback callback,
               cros::mojom::DetectCornersResultPtr detect_result) {
              std::move(callback).Run(detect_result->success,
                                      std::move(detect_result->corners));
            },
            std::move(callback)));
  }

 private:
  mojo::Remote<cros::mojom::CrosDocumentScanner> document_scanner_remote_;
};

// static
int CameraAppDeviceImpl::GetPortraitSegResultCode(
    const cros::mojom::CameraMetadataPtr* metadata) {
  auto portrait_mode_segmentation_result = GetMetadataEntryAsSpan<uint8_t>(
      *metadata, static_cast<cros::mojom::CameraMetadataTag>(
                     kPortraitModeSegmentationResultVendorKey));
  CHECK(!portrait_mode_segmentation_result.empty());
  return static_cast<int>(portrait_mode_segmentation_result[0]);
}

CameraAppDeviceImpl::CameraAppDeviceImpl(
    const std::string& device_id,
    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
    : device_id_(device_id),
      allow_new_ipc_weak_ptrs_(true),
      capture_intent_(cros::mojom::CaptureIntent::kDefault),
      camera_device_context_(nullptr),
      document_scanner_(ui_task_runner) {}

CameraAppDeviceImpl::~CameraAppDeviceImpl() {
  // If the instance is bound, then this instance should only be destroyed when
  // the mojo connection is dropped, which also happens on the mojo thread.
  DCHECK(!mojo_task_runner_ || mojo_task_runner_->BelongsToCurrentThread());

  // All the weak pointers of |weak_ptr_factory_| should be invalidated on
  // camera device IPC thread before destroying CameraAppDeviceImpl.
  DCHECK(!weak_ptr_factory_.HasWeakPtrs());
}

void CameraAppDeviceImpl::BindReceiver(
    mojo::PendingReceiver<cros::mojom::CameraAppDevice> receiver) {
  mojo_task_runner_ = base::SingleThreadTaskRunner::GetCurrentDefault();
  receivers_.Add(this, std::move(receiver));
  receivers_.set_disconnect_handler(
      base::BindRepeating(&CameraAppDeviceImpl::OnMojoConnectionError,
                          weak_ptr_factory_for_mojo_.GetWeakPtr()));
}

base::WeakPtr<CameraAppDeviceImpl> CameraAppDeviceImpl::GetWeakPtr() {
  return allow_new_ipc_weak_ptrs_ ? weak_ptr_factory_.GetWeakPtr() : nullptr;
}

void CameraAppDeviceImpl::ResetOnDeviceIpcThread(base::OnceClosure callback,
                                                 bool should_disable_new_ptrs) {
  if (should_disable_new_ptrs) {
    allow_new_ipc_weak_ptrs_ = false;
  }
  weak_ptr_factory_.InvalidateWeakPtrs();
  std::move(callback).Run();
}

std::optional<gfx::Range> CameraAppDeviceImpl::GetFpsRange() {
  base::AutoLock lock(fps_ranges_lock_);

  return specified_fps_range_;
}

gfx::Size CameraAppDeviceImpl::GetStillCaptureResolution() {
  base::AutoLock lock(still_capture_resolution_lock_);

  return still_capture_resolution_;
}

cros::mojom::CaptureIntent CameraAppDeviceImpl::GetCaptureIntent() {
  base::AutoLock lock(capture_intent_lock_);
  return capture_intent_;
}

void CameraAppDeviceImpl::OnResultMetadataAvailable(
    const cros::mojom::CameraMetadataPtr& metadata,
    cros::mojom::StreamType streamType) {
  mojo_task_runner_->PostTask(
      FROM_HERE,
      base::BindOnce(&CameraAppDeviceImpl::NotifyResultMetadataOnMojoThread,
                     weak_ptr_factory_for_mojo_.GetWeakPtr(), metadata.Clone(),
                     streamType));
}

void CameraAppDeviceImpl::OnShutterDone() {
  mojo_task_runner_->PostTask(
      FROM_HERE,
      base::BindOnce(&CameraAppDeviceImpl::NotifyShutterDoneOnMojoThread,
                     weak_ptr_factory_for_mojo_.GetWeakPtr()));
}

void CameraAppDeviceImpl::OnCameraInfoUpdated(
    cros::mojom::CameraInfoPtr camera_info) {
  base::AutoLock lock(camera_info_lock_);
  camera_info_ = std::move(camera_info);

  if (!mojo_task_runner_) {
    return;
  }
  mojo_task_runner_->PostTask(
      FROM_HERE,
      base::BindOnce(&CameraAppDeviceImpl::NotifyCameraInfoUpdatedOnMojoThread,
                     weak_ptr_factory_for_mojo_.GetWeakPtr()));
}

void CameraAppDeviceImpl::SetCameraDeviceContext(
    CameraDeviceContext* camera_device_context) {
  base::AutoLock lock(camera_device_context_lock_);
  camera_device_context_ = camera_device_context;
}

void CameraAppDeviceImpl::MaybeDetectDocumentCorners(
    std::unique_ptr<gpu::GpuMemoryBufferImpl> gmb,
    VideoRotation rotation) {
  {
    base::AutoLock lock(document_corners_observers_lock_);
    if (document_corners_observers_.empty()) {
      return;
    }
  }
  mojo_task_runner_->PostTask(
      FROM_HERE,
      base::BindOnce(&CameraAppDeviceImpl::DetectDocumentCornersOnMojoThread,
                     weak_ptr_factory_for_mojo_.GetWeakPtr(), std::move(gmb),
                     rotation));
}

bool CameraAppDeviceImpl::IsMultipleStreamsEnabled() {
  base::AutoLock lock(multi_stream_lock_);
  return multi_stream_enabled_;
}

void CameraAppDeviceImpl::TakePortraitModePhoto(
    mojo::PendingRemote<cros::mojom::StillCaptureResultObserver> observer,
    TakePortraitModePhotoCallback callback) {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  base::AutoLock lock(portrait_mode_callbacks_lock_);
  portrait_mode_observers_.reset();
  portrait_mode_observers_.Bind(std::move(observer));
  take_portrait_photo_callbacks_.reset();

  // Create two callbacks that will notify the client when the result is
  // returned. The `normal_photo_callback` is for the normal photo, and
  // `portrait_photo_callback` is for the portrait photo.
  PortraitModeCallbacks take_portrait_photo_callbacks;
  take_portrait_photo_callbacks.normal_photo_callback =
      base::BindPostTaskToCurrentDefault(
          base::BindOnce(&CameraAppDeviceImpl::NotifyPortraitResultOnMojoThread,
                         weak_ptr_factory_for_mojo_.GetWeakPtr(),
                         cros::mojom::Effect::kNoEffect));
  take_portrait_photo_callbacks.portrait_photo_callback =
      base::BindPostTaskToCurrentDefault(
          base::BindOnce(&CameraAppDeviceImpl::NotifyPortraitResultOnMojoThread,
                         weak_ptr_factory_for_mojo_.GetWeakPtr(),
                         cros::mojom::Effect::kPortraitMode));
  take_portrait_photo_callbacks_ = std::move(take_portrait_photo_callbacks);

  std::move(callback).Run();
}

void CameraAppDeviceImpl::SetFpsRange(const gfx::Range& fps_range,
                                      SetFpsRangeCallback callback) {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  const int entry_length = 2;

  base::AutoLock camera_info_lock(camera_info_lock_);
  if (!camera_info_) {
    LOG(ERROR) << "Camera info is still not available at this moment";
    std::move(callback).Run(false);
    return;
  }
  auto& static_metadata = camera_info_->static_camera_characteristics;
  auto available_fps_range_entries = GetMetadataEntryAsSpan<int32_t>(
      static_metadata, cros::mojom::CameraMetadataTag::
                           ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
  DCHECK(available_fps_range_entries.size() % entry_length == 0);

  bool is_valid = false;
  int min_fps = static_cast<int>(fps_range.GetMin());
  int max_fps = static_cast<int>(fps_range.GetMax());
  for (size_t i = 0; i < available_fps_range_entries.size();
       i += entry_length) {
    if (available_fps_range_entries[i] == min_fps &&
        available_fps_range_entries[i + 1] == max_fps) {
      is_valid = true;
      break;
    }
  }

  base::AutoLock lock(fps_ranges_lock_);

  if (is_valid) {
    specified_fps_range_ = fps_range;
  } else {
    specified_fps_range_ = {};
  }
  std::move(callback).Run(is_valid);
}

void CameraAppDeviceImpl::SetStillCaptureResolution(
    const gfx::Size& resolution,
    SetStillCaptureResolutionCallback callback) {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  base::AutoLock lock(still_capture_resolution_lock_);
  still_capture_resolution_ = resolution;
  std::move(callback).Run();
}

void CameraAppDeviceImpl::SetCaptureIntent(
    cros::mojom::CaptureIntent capture_intent,
    SetCaptureIntentCallback callback) {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  {
    base::AutoLock lock(capture_intent_lock_);
    capture_intent_ = capture_intent;
  }
  // Reset fps range for VCD to determine it if not explicitly set by app.
  {
    base::AutoLock lock(fps_ranges_lock_);
    specified_fps_range_ = {};
  }
  std::move(callback).Run();
}

void CameraAppDeviceImpl::AddResultMetadataObserver(
    mojo::PendingRemote<cros::mojom::ResultMetadataObserver> observer,
    cros::mojom::StreamType stream_type,
    AddResultMetadataObserverCallback callback) {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  stream_to_metadata_observers_map_[stream_type].Add(std::move(observer));
  std::move(callback).Run();
}

void CameraAppDeviceImpl::AddCameraEventObserver(
    mojo::PendingRemote<cros::mojom::CameraEventObserver> observer,
    AddCameraEventObserverCallback callback) {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  camera_event_observers_.Add(std::move(observer));
  std::move(callback).Run();
}

void CameraAppDeviceImpl::SetCameraFrameRotationEnabledAtSource(
    bool is_enabled,
    SetCameraFrameRotationEnabledAtSourceCallback callback) {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  bool is_success = false;
  {
    base::AutoLock lock(camera_device_context_lock_);
    if (camera_device_context_) {
      camera_device_context_->SetCameraFrameRotationEnabledAtSource(is_enabled);
      is_success = true;
    }
  }
  std::move(callback).Run(is_success);
}

void CameraAppDeviceImpl::GetCameraFrameRotation(
    GetCameraFrameRotationCallback callback) {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  uint32_t rotation = 0;
  {
    base::AutoLock lock(camera_device_context_lock_);
    if (camera_device_context_ &&
        !camera_device_context_->IsCameraFrameRotationEnabledAtSource()) {
      // The camera rotation value can only be [0, 90, 180, 270].
      rotation = static_cast<uint32_t>(
          camera_device_context_->GetCameraFrameRotation());
    }
  }
  std::move(callback).Run(rotation);
}

void CameraAppDeviceImpl::RegisterDocumentCornersObserver(
    mojo::PendingRemote<cros::mojom::DocumentCornersObserver> observer,
    RegisterDocumentCornersObserverCallback callback) {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  base::AutoLock lock(document_corners_observers_lock_);
  document_corners_observers_.Add(std::move(observer));
  std::move(callback).Run();
}

void CameraAppDeviceImpl::SetMultipleStreamsEnabled(
    bool enabled,
    SetMultipleStreamsEnabledCallback callback) {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  base::AutoLock lock(multi_stream_lock_);
  multi_stream_enabled_ = enabled;
  std::move(callback).Run();
}

void CameraAppDeviceImpl::RegisterCameraInfoObserver(
    mojo::PendingRemote<cros::mojom::CameraInfoObserver> observer,
    RegisterCameraInfoObserverCallback callback) {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  camera_info_observers_.Add(std::move(observer));
  std::move(callback).Run();

  NotifyCameraInfoUpdatedOnMojoThread();
}

void CameraAppDeviceImpl::OnMojoConnectionError() {
  CameraAppDeviceBridgeImpl::GetInstance()->OnDeviceMojoDisconnected(
      device_id_);
}

bool CameraAppDeviceImpl::IsCloseToPreviousDetectionRequest() {
  return document_detection_timer_ &&
         document_detection_timer_->Elapsed().InMilliseconds() < 300;
}

void CameraAppDeviceImpl::DetectDocumentCornersOnMojoThread(
    std::unique_ptr<gpu::GpuMemoryBufferImpl> image,
    VideoRotation rotation) {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  if (IsCloseToPreviousDetectionRequest() ||
      has_ongoing_document_detection_task_) {
    return;
  }

  DCHECK(image);
  if (!image->Map()) {
    LOG(ERROR) << "Failed to map frame buffer";
    return;
  }
  auto frame_size = image->GetSize();
  int width = frame_size.width();
  int height = frame_size.height();

  base::MappedReadOnlyRegion memory = base::ReadOnlySharedMemoryRegion::Create(
      kDetectionWidth * kDetectionHeight * 3 / 2);
  if (!memory.IsValid()) {
    LOG(ERROR) << "Failed to allocate shared memory";
    return;
  }
  auto* y_data = memory.mapping.GetMemoryAs<uint8_t>();
  auto* uv_data = y_data + kDetectionWidth * kDetectionHeight;

  int status = libyuv::NV12Scale(
      static_cast<uint8_t*>(image->memory(0)), image->stride(0),
      static_cast<uint8_t*>(image->memory(1)), image->stride(1), width, height,
      y_data, kDetectionWidth, uv_data, kDetectionWidth, kDetectionWidth,
      kDetectionHeight, libyuv::FilterMode::kFilterNone);
  image->Unmap();
  if (status != 0) {
    LOG(ERROR) << "Failed to scale buffer";
    return;
  }

  has_ongoing_document_detection_task_ = true;
  document_detection_timer_ = std::make_unique<base::ElapsedTimer>();

  document_scanner_.AsyncCall(&DocumentScanner::DetectCornersFromNV12Image)
      .WithArgs(std::move(memory.region),
                base::BindPostTaskToCurrentDefault(base::BindOnce(
                    &CameraAppDeviceImpl::OnDetectedDocumentCornersOnMojoThread,
                    weak_ptr_factory_for_mojo_.GetWeakPtr(), rotation)));
}

void CameraAppDeviceImpl::OnDetectedDocumentCornersOnMojoThread(
    VideoRotation rotation,
    bool success,
    const std::vector<gfx::PointF>& corners) {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  has_ongoing_document_detection_task_ = false;
  if (!success) {
    LOG(ERROR) << "Failed to detect document corners";
    return;
  }

  // Rotate a point in coordination space {x: [0.0, 1.0], y: [0.0, 1.0]} with
  // anchor point {x: 0.5, y: 0.5}.
  auto rotate_corner = [&](const gfx::PointF& corner) -> gfx::PointF {
    float x = std::clamp(corner.x(), 0.0f, 1.0f);
    float y = std::clamp(corner.y(), 0.0f, 1.0f);

    switch (rotation) {
      case VIDEO_ROTATION_0:
        return {x, y};
      case VIDEO_ROTATION_90:
        return {1.0f - y, x};
      case VIDEO_ROTATION_180:
        return {1.0f - x, 1.0f - y};
      case VIDEO_ROTATION_270:
        return {y, 1.0f - x};
      default:
        NOTREACHED_IN_MIGRATION();
    }
  };

  std::vector<gfx::PointF> rotated_corners;
  for (auto& corner : corners) {
    rotated_corners.push_back(rotate_corner(corner));
  }

  base::AutoLock lock(document_corners_observers_lock_);
  for (auto& observer : document_corners_observers_) {
    observer->OnDocumentCornersUpdated(rotated_corners);
  }
}

void CameraAppDeviceImpl::NotifyPortraitResultOnMojoThread(
    cros::mojom::Effect effect,
    const int32_t status,
    media::mojom::BlobPtr blob) {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  portrait_mode_observers_->OnStillCaptureDone(effect, status, std::move(blob));
}

void CameraAppDeviceImpl::NotifyShutterDoneOnMojoThread() {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  for (auto& observer : camera_event_observers_) {
    observer->OnShutterDone();
  }
}

void CameraAppDeviceImpl::NotifyResultMetadataOnMojoThread(
    cros::mojom::CameraMetadataPtr metadata,
    cros::mojom::StreamType streamType) {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  auto& metadata_observers = stream_to_metadata_observers_map_[streamType];
  for (auto& observer : metadata_observers) {
    observer->OnMetadataAvailable(metadata.Clone());
  }
}

void CameraAppDeviceImpl::NotifyCameraInfoUpdatedOnMojoThread() {
  DCHECK(mojo_task_runner_->BelongsToCurrentThread());

  base::AutoLock lock(camera_info_lock_);
  if (!camera_info_) {
    return;
  }
  for (auto& observer : camera_info_observers_) {
    observer->OnCameraInfoUpdated(camera_info_.Clone());
  }
}

std::optional<PortraitModeCallbacks>
CameraAppDeviceImpl::ConsumePortraitModeCallbacks() {
  base::AutoLock lock(portrait_mode_callbacks_lock_);
  std::optional<PortraitModeCallbacks> callbacks;
  if (take_portrait_photo_callbacks_.has_value()) {
    callbacks = std::move(take_portrait_photo_callbacks_);
    take_portrait_photo_callbacks_.reset();
  }
  return callbacks;
}

void CameraAppDeviceImpl::SetCropRegion(const gfx::Rect& crop_region,
                                        SetCropRegionCallback callback) {
  CHECK(mojo_task_runner_->BelongsToCurrentThread());

  base::AutoLock lock(crop_region_lock_);
  crop_region_ = {
      crop_region.x(),
      crop_region.y(),
      crop_region.width(),
      crop_region.height(),
  };

  std::move(callback).Run();
}

void CameraAppDeviceImpl::ResetCropRegion(ResetCropRegionCallback callback) {
  CHECK(mojo_task_runner_->BelongsToCurrentThread());

  base::AutoLock lock(crop_region_lock_);
  crop_region_.reset();

  std::move(callback).Run();
}

std::optional<std::vector<int32_t>> CameraAppDeviceImpl::GetCropRegion() {
  base::AutoLock lock(crop_region_lock_);
  return crop_region_;
}

}  // namespace media
