// Copyright 2016 The Chromium 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 "third_party/blink/renderer/modules/notifications/notification_manager.h"

#include <utility>

#include "base/metrics/histogram_functions.h"
#include "base/numerics/safe_conversions.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/public/mojom/notifications/notification.mojom-blink.h"
#include "third_party/blink/public/mojom/permissions/permission.mojom-blink.h"
#include "third_party/blink/public/mojom/permissions/permission_status.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_notification_permission.h"
#include "third_party/blink/renderer/core/frame/frame.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/modules/notifications/notification.h"
#include "third_party/blink/renderer/modules/notifications/notification_metrics.h"
#include "third_party/blink/renderer/modules/permissions/permission_utils.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"

namespace blink {

// static
NotificationManager* NotificationManager::From(ExecutionContext* context) {
  DCHECK(context);
  DCHECK(context->IsContextThread());

  NotificationManager* manager =
      Supplement<ExecutionContext>::From<NotificationManager>(context);
  if (!manager) {
    manager = MakeGarbageCollected<NotificationManager>(*context);
    Supplement<ExecutionContext>::ProvideTo(*context, manager);
  }

  return manager;
}

// static
const char NotificationManager::kSupplementName[] = "NotificationManager";

NotificationManager::NotificationManager(ExecutionContext& context)
    : Supplement<ExecutionContext>(context),
      notification_service_(&context),
      permission_service_(&context) {}

NotificationManager::~NotificationManager() = default;

mojom::blink::PermissionStatus NotificationManager::GetPermissionStatus() {
  if (GetSupplementable()->IsContextDestroyed())
    return mojom::blink::PermissionStatus::DENIED;

  mojom::blink::PermissionStatus permission_status;
  if (!GetNotificationService()->GetPermissionStatus(&permission_status)) {
    NOTREACHED();
    return mojom::blink::PermissionStatus::DENIED;
  }

  return permission_status;
}

ScriptPromise NotificationManager::RequestPermission(
    ScriptState* script_state,
    V8NotificationPermissionCallback* deprecated_callback) {
  ExecutionContext* context = ExecutionContext::From(script_state);

  if (!permission_service_.is_bound()) {
    // See https://bit.ly/2S0zRAS for task types
    scoped_refptr<base::SingleThreadTaskRunner> task_runner =
        context->GetTaskRunner(TaskType::kMiscPlatformAPI);
    ConnectToPermissionService(
        context,
        permission_service_.BindNewPipeAndPassReceiver(std::move(task_runner)));
    permission_service_.set_disconnect_handler(
        WTF::Bind(&NotificationManager::OnPermissionServiceConnectionError,
                  WrapWeakPersistent(this)));
  }

  auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
  ScriptPromise promise = resolver->Promise();

  LocalDOMWindow* win = To<LocalDOMWindow>(context);
  permission_service_->RequestPermission(
      CreatePermissionDescriptor(mojom::blink::PermissionName::NOTIFICATIONS),
      LocalFrame::HasTransientUserActivation(win ? win->GetFrame() : nullptr),
      WTF::Bind(&NotificationManager::OnPermissionRequestComplete,
                WrapPersistent(this), WrapPersistent(resolver),
                WrapPersistent(deprecated_callback)));

  return promise;
}

void NotificationManager::OnPermissionRequestComplete(
    ScriptPromiseResolver* resolver,
    V8NotificationPermissionCallback* deprecated_callback,
    mojom::blink::PermissionStatus status) {
  String status_string = Notification::PermissionString(status);
  if (deprecated_callback) {
#if defined(USE_BLINK_V8_BINDING_NEW_IDL_CALLBACK_FUNCTION)
    deprecated_callback->InvokeAndReportException(
        nullptr, V8NotificationPermission::Create(status_string).value());
#else
    deprecated_callback->InvokeAndReportException(nullptr, status_string);
#endif
  }

  resolver->Resolve(status_string);
}

void NotificationManager::OnNotificationServiceConnectionError() {
  notification_service_.reset();
}

void NotificationManager::OnPermissionServiceConnectionError() {
  permission_service_.reset();
}

void NotificationManager::DisplayNonPersistentNotification(
    const String& token,
    mojom::blink::NotificationDataPtr notification_data,
    mojom::blink::NotificationResourcesPtr notification_resources,
    mojo::PendingRemote<mojom::blink::NonPersistentNotificationListener>
        event_listener) {
  DCHECK(!token.IsEmpty());
  DCHECK(notification_resources);
  GetNotificationService()->DisplayNonPersistentNotification(
      token, std::move(notification_data), std::move(notification_resources),
      std::move(event_listener));
}

void NotificationManager::CloseNonPersistentNotification(const String& token) {
  DCHECK(!token.IsEmpty());
  GetNotificationService()->CloseNonPersistentNotification(token);
}

void NotificationManager::DisplayPersistentNotification(
    int64_t service_worker_registration_id,
    mojom::blink::NotificationDataPtr notification_data,
    mojom::blink::NotificationResourcesPtr notification_resources,
    ScriptPromiseResolver* resolver) {
  DCHECK(notification_data);
  DCHECK(notification_resources);
  DCHECK_EQ(notification_data->actions.has_value()
                ? notification_data->actions->size()
                : 0,
            notification_resources->action_icons.has_value()
                ? notification_resources->action_icons->size()
                : 0);

  // Verify that the author-provided payload size does not exceed our limit.
  // This is an implementation-defined limit to prevent abuse of notification
  // data as a storage mechanism. A UMA histogram records the requested sizes,
  // which enables us to track how much data authors are attempting to store.
  //
  // If the size exceeds this limit, reject the showNotification() promise. This
  // is outside of the boundaries set by the specification, but it gives authors
  // an indication that something has gone wrong.
  size_t author_data_size =
      notification_data->data.has_value() ? notification_data->data->size() : 0;

  base::UmaHistogramCounts1000(
      "Notifications.AuthorDataSize",
      base::saturated_cast<base::HistogramBase::Sample>(author_data_size));

  if (author_data_size >
      mojom::blink::NotificationData::kMaximumDeveloperDataSize) {
    RecordPersistentNotificationDisplayResult(
        PersistentNotificationDisplayResult::kTooMuchData);
    resolver->Reject();
    return;
  }

  GetNotificationService()->DisplayPersistentNotification(
      service_worker_registration_id, std::move(notification_data),
      std::move(notification_resources),
      WTF::Bind(&NotificationManager::DidDisplayPersistentNotification,
                WrapPersistent(this), WrapPersistent(resolver)));
}

void NotificationManager::DidDisplayPersistentNotification(
    ScriptPromiseResolver* resolver,
    mojom::blink::PersistentNotificationError error) {
  switch (error) {
    case mojom::blink::PersistentNotificationError::NONE:
      RecordPersistentNotificationDisplayResult(
          PersistentNotificationDisplayResult::kOk);
      resolver->Resolve();
      return;
    case mojom::blink::PersistentNotificationError::INTERNAL_ERROR:
      RecordPersistentNotificationDisplayResult(
          PersistentNotificationDisplayResult::kInternalError);
      resolver->Reject();
      return;
    case mojom::blink::PersistentNotificationError::PERMISSION_DENIED:
      RecordPersistentNotificationDisplayResult(
          PersistentNotificationDisplayResult::kPermissionDenied);
      // TODO(https://crbug.com/832944): Throw a TypeError if permission denied.
      resolver->Reject();
      return;
  }
  NOTREACHED();
}

void NotificationManager::ClosePersistentNotification(
    const WebString& notification_id) {
  GetNotificationService()->ClosePersistentNotification(notification_id);
}

void NotificationManager::GetNotifications(
    int64_t service_worker_registration_id,
    const WebString& filter_tag,
    bool include_triggered,
    ScriptPromiseResolver* resolver) {
  GetNotificationService()->GetNotifications(
      service_worker_registration_id, filter_tag, include_triggered,
      WTF::Bind(&NotificationManager::DidGetNotifications, WrapPersistent(this),
                WrapPersistent(resolver)));
}

void NotificationManager::DidGetNotifications(
    ScriptPromiseResolver* resolver,
    const Vector<String>& notification_ids,
    Vector<mojom::blink::NotificationDataPtr> notification_datas) {
  DCHECK_EQ(notification_ids.size(), notification_datas.size());
  ExecutionContext* context = resolver->GetExecutionContext();
  if (!context)
    return;

  HeapVector<Member<Notification>> notifications;
  notifications.ReserveInitialCapacity(notification_ids.size());

  for (wtf_size_t i = 0; i < notification_ids.size(); ++i) {
    notifications.push_back(Notification::Create(
        context, notification_ids[i], std::move(notification_datas[i]),
        true /* showing */));
  }

  resolver->Resolve(notifications);
}

mojom::blink::NotificationService*
NotificationManager::GetNotificationService() {
  if (!notification_service_.is_bound()) {
    // See https://bit.ly/2S0zRAS for task types
    scoped_refptr<base::SingleThreadTaskRunner> task_runner =
        GetSupplementable()->GetTaskRunner(TaskType::kMiscPlatformAPI);
    GetSupplementable()->GetBrowserInterfaceBroker().GetInterface(
        notification_service_.BindNewPipeAndPassReceiver(task_runner));

    notification_service_.set_disconnect_handler(
        WTF::Bind(&NotificationManager::OnNotificationServiceConnectionError,
                  WrapWeakPersistent(this)));
  }

  return notification_service_.get();
}

void NotificationManager::Trace(Visitor* visitor) const {
  visitor->Trace(notification_service_);
  visitor->Trace(permission_service_);
  Supplement<ExecutionContext>::Trace(visitor);
}

}  // namespace blink
