// 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 "chrome/browser/sharing/sharing_fcm_sender.h"

#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/trace_event/trace_event.h"
#include "base/uuid.h"
#include "base/version.h"
#include "chrome/browser/sharing/sharing_constants.h"
#include "chrome/browser/sharing/sharing_message_bridge.h"
#include "chrome/browser/sharing/sharing_sync_preference.h"
#include "chrome/browser/sharing/sharing_utils.h"
#include "chrome/browser/sharing/vapid_key_manager.h"
#include "chrome/browser/sharing/web_push/web_push_sender.h"
#include "components/gcm_driver/crypto/gcm_encryption_result.h"
#include "components/gcm_driver/gcm_driver.h"
#include "components/sync/driver/sync_service.h"
#include "components/sync_device_info/local_device_info_provider.h"

SharingFCMSender::SharingFCMSender(
    std::unique_ptr<WebPushSender> web_push_sender,
    SharingMessageBridge* sharing_message_bridge,
    SharingSyncPreference* sync_preference,
    VapidKeyManager* vapid_key_manager,
    gcm::GCMDriver* gcm_driver,
    syncer::LocalDeviceInfoProvider* local_device_info_provider,
    syncer::SyncService* sync_service)
    : web_push_sender_(std::move(web_push_sender)),
      sharing_message_bridge_(sharing_message_bridge),
      sync_preference_(sync_preference),
      vapid_key_manager_(vapid_key_manager),
      gcm_driver_(gcm_driver),
      local_device_info_provider_(local_device_info_provider),
      sync_service_(sync_service) {}

SharingFCMSender::~SharingFCMSender() = default;

void SharingFCMSender::DoSendMessageToDevice(const syncer::DeviceInfo& device,
                                             base::TimeDelta time_to_live,
                                             SharingMessage message,
                                             SendMessageCallback callback) {
  TRACE_EVENT0("sharing", "SharingFCMSender::DoSendMessageToDevice");

  auto fcm_configuration = GetFCMChannel(device);
  if (!fcm_configuration) {
    std::move(callback).Run(SharingSendMessageResult::kDeviceNotFound,
                            /*message_id=*/absl::nullopt,
                            SharingChannelType::kUnknown);
    return;
  }

  if (!SetMessageSenderInfo(&message)) {
    std::move(callback).Run(SharingSendMessageResult::kInternalError,
                            /*message_id=*/absl::nullopt,
                            SharingChannelType::kUnknown);
    return;
  }

  SendMessageToFcmTarget(*fcm_configuration, time_to_live, std::move(message),
                         std::move(callback));
}

void SharingFCMSender::SendMessageToFcmTarget(
    const chrome_browser_sharing::FCMChannelConfiguration& fcm_configuration,
    base::TimeDelta time_to_live,
    SharingMessage message,
    SendMessageCallback callback) {
  TRACE_EVENT0("sharing", "SharingFCMSender::SendMessageToFcmTarget");

  bool canSendViaSync =
      sync_service_->GetActiveDataTypes().Has(syncer::SHARING_MESSAGE) &&
      !fcm_configuration.sender_id_fcm_token().empty() &&
      !fcm_configuration.sender_id_p256dh().empty() &&
      !fcm_configuration.sender_id_auth_secret().empty();
  bool canSendViaVapid = !fcm_configuration.vapid_fcm_token().empty() &&
                         !fcm_configuration.vapid_p256dh().empty() &&
                         !fcm_configuration.vapid_auth_secret().empty();

  if (canSendViaSync) {
    message.set_message_id(base::Uuid::GenerateRandomV4().AsLowercaseString());
    EncryptMessage(
        kSharingSenderID, fcm_configuration.sender_id_p256dh(),
        fcm_configuration.sender_id_auth_secret(), message,
        SharingChannelType::kFcmSenderId, std::move(callback),
        base::BindOnce(&SharingFCMSender::DoSendMessageToSenderIdTarget,
                       weak_ptr_factory_.GetWeakPtr(),
                       fcm_configuration.sender_id_fcm_token(), time_to_live,
                       message.message_id()));
    return;
  }

  // TODO(crbug.com/1408456): This can probably go away.
  if (canSendViaVapid) {
    absl::optional<SharingSyncPreference::FCMRegistration> fcm_registration =
        sync_preference_->GetFCMRegistration();
    if (!fcm_registration || !fcm_registration->authorized_entity) {
      LOG(ERROR) << "Unable to retrieve FCM registration";
      std::move(callback).Run(SharingSendMessageResult::kInternalError,
                              /*message_id=*/absl::nullopt,
                              SharingChannelType::kUnknown);
      return;
    }

    EncryptMessage(
        *fcm_registration->authorized_entity, fcm_configuration.vapid_p256dh(),
        fcm_configuration.vapid_auth_secret(), message,
        SharingChannelType::kFcmVapid, std::move(callback),
        base::BindOnce(&SharingFCMSender::DoSendMessageToVapidTarget,
                       weak_ptr_factory_.GetWeakPtr(),
                       fcm_configuration.vapid_fcm_token(), time_to_live));
    return;
  }

  std::move(callback).Run(SharingSendMessageResult::kDeviceNotFound,
                          /*message_id=*/absl::nullopt,
                          SharingChannelType::kUnknown);
}

void SharingFCMSender::SendMessageToServerTarget(
    const chrome_browser_sharing::ServerChannelConfiguration& server_channel,
    SharingMessage message,
    SendMessageCallback callback) {
  TRACE_EVENT0("sharing", "SharingFCMSender::SendMessageToServerTarget");

  if (!sync_service_->GetActiveDataTypes().Has(syncer::SHARING_MESSAGE)) {
    std::move(callback).Run(SharingSendMessageResult::kInternalError,
                            /*message_id=*/absl::nullopt,
                            SharingChannelType::kServer);
    return;
  }

  message.set_message_id(base::Uuid::GenerateRandomV4().AsLowercaseString());
  EncryptMessage(
      kSharingSenderID, server_channel.p256dh(), server_channel.auth_secret(),
      message, SharingChannelType::kServer, std::move(callback),
      base::BindOnce(&SharingFCMSender::DoSendMessageToServerTarget,
                     weak_ptr_factory_.GetWeakPtr(),
                     server_channel.configuration(), message.message_id()));
}

void SharingFCMSender::EncryptMessage(const std::string& authorized_entity,
                                      const std::string& p256dh,
                                      const std::string& auth_secret,
                                      const SharingMessage& message,
                                      SharingChannelType channel_type,
                                      SendMessageCallback callback,
                                      MessageSender message_sender) {
  std::string payload;
  message.SerializeToString(&payload);
  gcm_driver_->EncryptMessage(
      kSharingFCMAppID, authorized_entity, p256dh, auth_secret, payload,
      base::BindOnce(&SharingFCMSender::OnMessageEncrypted,
                     weak_ptr_factory_.GetWeakPtr(), channel_type,
                     std::move(callback), std::move(message_sender)));
}

void SharingFCMSender::OnMessageEncrypted(SharingChannelType channel_type,
                                          SendMessageCallback callback,
                                          MessageSender message_sender,
                                          gcm::GCMEncryptionResult result,
                                          std::string message) {
  if (result != gcm::GCMEncryptionResult::ENCRYPTED_DRAFT_08) {
    LOG(ERROR) << "Unable to encrypt message";
    std::move(callback).Run(SharingSendMessageResult::kEncryptionError,
                            /*message_id=*/absl::nullopt, channel_type);
    return;
  }

  std::move(message_sender).Run(std::move(message), std::move(callback));
}

void SharingFCMSender::DoSendMessageToVapidTarget(
    const std::string& fcm_token,
    base::TimeDelta time_to_live,
    std::string message,
    SendMessageCallback callback) {
  TRACE_EVENT0("sharing", "SharingFCMSender::DoSendMessageToVapidTarget");

  auto* vapid_key = vapid_key_manager_->GetOrCreateKey();
  if (!vapid_key) {
    LOG(ERROR) << "Unable to retrieve VAPID key";
    std::move(callback).Run(SharingSendMessageResult::kInternalError,
                            /*message_id=*/absl::nullopt,
                            SharingChannelType::kFcmVapid);
    return;
  }

  WebPushMessage web_push_message;
  web_push_message.time_to_live = time_to_live.InSeconds();
  web_push_message.urgency = WebPushMessage::Urgency::kHigh;
  web_push_message.payload = std::move(message);

  web_push_sender_->SendMessage(
      fcm_token, vapid_key, std::move(web_push_message),
      base::BindOnce(&SharingFCMSender::OnMessageSentToVapidTarget,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}

void SharingFCMSender::OnMessageSentToVapidTarget(
    SendMessageCallback callback,
    SendWebPushMessageResult result,
    absl::optional<std::string> message_id) {
  TRACE_EVENT1("sharing", "SharingFCMSender::OnMessageSentToVapidTarget",
               "result", result);

  SharingSendMessageResult send_message_result;
  switch (result) {
    case SendWebPushMessageResult::kSuccessful:
      send_message_result = SharingSendMessageResult::kSuccessful;
      break;
    case SendWebPushMessageResult::kDeviceGone:
      send_message_result = SharingSendMessageResult::kDeviceNotFound;
      break;
    case SendWebPushMessageResult::kNetworkError:
      send_message_result = SharingSendMessageResult::kNetworkError;
      break;
    case SendWebPushMessageResult::kPayloadTooLarge:
      send_message_result = SharingSendMessageResult::kPayloadTooLarge;
      break;
    case SendWebPushMessageResult::kEncryptionFailed:
    case SendWebPushMessageResult::kCreateJWTFailed:
    case SendWebPushMessageResult::kServerError:
    case SendWebPushMessageResult::kParseResponseFailed:
    case SendWebPushMessageResult::kVapidKeyInvalid:
      send_message_result = SharingSendMessageResult::kInternalError;
      break;
  }

  std::move(callback).Run(send_message_result, message_id,
                          SharingChannelType::kFcmVapid);
}

void SharingFCMSender::DoSendMessageToSenderIdTarget(
    const std::string& fcm_token,
    base::TimeDelta time_to_live,
    const std::string& message_id,
    std::string message,
    SendMessageCallback callback) {
  TRACE_EVENT0("sharing", "SharingFCMSender::DoSendMessageToSenderIdTarget");

  // Double check that SHARING_MESSAGE is syncing.
  if (!sync_service_->GetActiveDataTypes().Has(syncer::SHARING_MESSAGE)) {
    std::move(callback).Run(SharingSendMessageResult::kInternalError,
                            /*message_id=*/absl::nullopt,
                            SharingChannelType::kFcmSenderId);
    return;
  }

  auto specifics = std::make_unique<sync_pb::SharingMessageSpecifics>();
  auto* fcm_configuration =
      specifics->mutable_channel_configuration()->mutable_fcm();
  fcm_configuration->set_token(fcm_token);
  fcm_configuration->set_ttl(time_to_live.InSeconds());
  fcm_configuration->set_priority(10);
  specifics->set_payload(message);

  sharing_message_bridge_->SendSharingMessage(
      std::move(specifics),
      base::BindOnce(&SharingFCMSender::OnMessageSentViaSync,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
                     message_id, SharingChannelType::kFcmSenderId));
}

void SharingFCMSender::DoSendMessageToServerTarget(
    const std::string& server_channel,
    const std::string& message_id,
    std::string message,
    SendMessageCallback callback) {
  TRACE_EVENT0("sharing", "SharingFCMSender::DoSendMessageToServerTarget");

  // Double check that SHARING_MESSAGE is syncing.
  if (!sync_service_->GetActiveDataTypes().Has(syncer::SHARING_MESSAGE)) {
    std::move(callback).Run(SharingSendMessageResult::kInternalError,
                            /*message_id=*/absl::nullopt,
                            SharingChannelType::kServer);
    return;
  }

  auto specifics = std::make_unique<sync_pb::SharingMessageSpecifics>();
  specifics->mutable_channel_configuration()->set_server(server_channel);
  specifics->set_payload(message);

  sharing_message_bridge_->SendSharingMessage(
      std::move(specifics),
      base::BindOnce(&SharingFCMSender::OnMessageSentViaSync,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
                     message_id, SharingChannelType::kServer));
}

void SharingFCMSender::OnMessageSentViaSync(
    SendMessageCallback callback,
    const std::string& message_id,
    SharingChannelType channel_type,
    const sync_pb::SharingMessageCommitError& error) {
  TRACE_EVENT1("sharing", "SharingFCMSender::OnMessageSentViaSync", "error",
               error.error_code());

  SharingSendMessageResult send_message_result;
  switch (error.error_code()) {
    case sync_pb::SharingMessageCommitError::NONE:
      send_message_result = SharingSendMessageResult::kSuccessful;
      break;
    case sync_pb::SharingMessageCommitError::NOT_FOUND:
      send_message_result = SharingSendMessageResult::kDeviceNotFound;
      break;
    case sync_pb::SharingMessageCommitError::INVALID_ARGUMENT:
      send_message_result = SharingSendMessageResult::kPayloadTooLarge;
      break;
    case sync_pb::SharingMessageCommitError::INTERNAL:
    case sync_pb::SharingMessageCommitError::UNAVAILABLE:
    case sync_pb::SharingMessageCommitError::RESOURCE_EXHAUSTED:
    case sync_pb::SharingMessageCommitError::UNAUTHENTICATED:
    case sync_pb::SharingMessageCommitError::PERMISSION_DENIED:
    case sync_pb::SharingMessageCommitError::SYNC_TURNED_OFF:
    case sync_pb::SharingMessageCommitError::
        DEPRECATED_SYNC_SERVER_OR_AUTH_ERROR:
    case sync_pb::SharingMessageCommitError::SYNC_SERVER_ERROR:
    case sync_pb::SharingMessageCommitError::SYNC_AUTH_ERROR:
      send_message_result = SharingSendMessageResult::kInternalError;
      break;
    case sync_pb::SharingMessageCommitError::SYNC_NETWORK_ERROR:
      send_message_result = SharingSendMessageResult::kNetworkError;
      break;
    case sync_pb::SharingMessageCommitError::SYNC_TIMEOUT:
      send_message_result = SharingSendMessageResult::kCommitTimeout;
      break;
  }

  std::move(callback).Run(send_message_result, message_id, channel_type);
}

bool SharingFCMSender::SetMessageSenderInfo(SharingMessage* message) {
  absl::optional<syncer::DeviceInfo::SharingInfo> sharing_info =
      local_device_info_provider_->GetLocalDeviceInfo()->sharing_info();
  if (!sharing_info)
    return false;

  auto* fcm_configuration = message->mutable_fcm_channel_configuration();
  fcm_configuration->set_vapid_fcm_token(
      sharing_info->vapid_target_info.fcm_token);
  fcm_configuration->set_vapid_p256dh(sharing_info->vapid_target_info.p256dh);
  fcm_configuration->set_vapid_auth_secret(
      sharing_info->vapid_target_info.auth_secret);
  fcm_configuration->set_sender_id_fcm_token(
      sharing_info->sender_id_target_info.fcm_token);
  fcm_configuration->set_sender_id_p256dh(
      sharing_info->sender_id_target_info.p256dh);
  fcm_configuration->set_sender_id_auth_secret(
      sharing_info->sender_id_target_info.auth_secret);
  return true;
}

void SharingFCMSender::SetWebPushSenderForTesting(
    std::unique_ptr<WebPushSender> web_push_sender) {
  web_push_sender_ = std::move(web_push_sender);
}

void SharingFCMSender::SetSharingMessageBridgeForTesting(
    SharingMessageBridge* sharing_message_bridge) {
  sharing_message_bridge_ = sharing_message_bridge;
}
