// 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_handler_registry_impl.h"

#include "base/feature_list.h"
#include "build/build_config.h"
#include "chrome/browser/glic/public/glic_keyed_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sharing/browser_actuator/browser_actuator_message_handler.h"
#include "chrome/browser/sharing/glic_experimental_triggering/glic_experimental_triggering_message_handler.h"
#include "chrome/browser/sharing/one_time_tokens/one_time_token_sharing_handler.h"
#include "chrome/browser/sharing/optimization_guide/optimization_guide_message_handler.h"
#include "chrome/common/chrome_features.h"
#include "components/browser_actuator/public/features.h"
#include "components/one_time_tokens/core/browser/gmail_otp_backend.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
#include "components/sharing_message/ack_message_handler.h"
#include "components/sharing_message/ping_message_handler.h"
#include "components/sharing_message/sharing_device_registration.h"
#include "components/sharing_message/sharing_message_handler.h"
#include "components/sharing_message/sharing_message_sender.h"

#if BUILDFLAG(IS_ANDROID)
#include "chrome/browser/sharing/sms/sms_fetch_request_handler.h"
#endif  // BUILDFLAG(IS_ANDROID)

#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
    BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/sharing/shared_clipboard/remote_copy_message_handler.h"
#endif

SharingHandlerRegistryImpl::SharingHandlerRegistryImpl(
    Profile* profile,
    SharingDeviceRegistration* sharing_device_registration,
    SharingMessageSender* message_sender,
    SharingDeviceSource* device_source,
    content::SmsFetcher* sms_fetcher,
    one_time_tokens::GmailOtpBackend* gmail_otp_backend) {
  AddSharingHandler(std::make_unique<PingMessageHandler>(),
                    {components_sharing_message::SharingMessage::kPingMessage});

  AddSharingHandler(std::make_unique<AckMessageHandler>(message_sender),
                    {components_sharing_message::SharingMessage::kAckMessage});

#if BUILDFLAG(IS_ANDROID)
  if (sharing_device_registration->IsSmsFetcherSupported()) {
    AddSharingHandler(
        std::make_unique<SmsFetchRequestHandler>(device_source, sms_fetcher),
        {components_sharing_message::SharingMessage::kSmsFetchRequest});
  }

#endif  // BUILDFLAG(IS_ANDROID)

  // Profile can be null in tests.
  if (optimization_guide::features::IsPushNotificationsEnabled() &&
      optimization_guide::features::IsOptimizationHintsEnabled() && profile) {
    AddSharingHandler(OptimizationGuideMessageHandler::Create(profile),
                      {components_sharing_message::SharingMessage::
                           kOptimizationGuidePushNotification});
  }

#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
    BUILDFLAG(IS_CHROMEOS)
  if (sharing_device_registration->IsRemoteCopySupported()) {
    AddSharingHandler(
        std::make_unique<RemoteCopyMessageHandler>(profile),
        {components_sharing_message::SharingMessage::kRemoteCopyMessage});
  }
#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
        // BUILDFLAG(IS_CHROMEOS)
#if !BUILDFLAG(IS_ANDROID)
  if (sharing_device_registration
          ->IsOneTimeTokenBackendNotificationSupported()) {
    AddSharingHandler(
        std::make_unique<OneTimeTokenSharingHandler>(gmail_otp_backend),
        {components_sharing_message::SharingMessage::
             kOneTimeTokenBackendNotification});
  }
#endif  // !BUILDFLAG(IS_ANDROID)

  bool browser_actuator_enabled =
      base::FeatureList::IsEnabled(browser_actuator::kBrowserActuator);
  bool browser_actuator_for_glic_enabled =
      browser_actuator_enabled &&
      base::FeatureList::IsEnabled(
          browser_actuator::
              kEnableBrowserActuatorForGlicExperimentalTriggering);
  bool glic_experimental_triggering_enabled =
      base::FeatureList::IsEnabled(features::kGlicExperimentalTriggering);

  if ((browser_actuator_for_glic_enabled ||
       glic_experimental_triggering_enabled) &&
      glic::GlicKeyedServiceFactory::GetGlicKeyedService(profile,
                                                         /*create=*/true)) {
    if (browser_actuator_for_glic_enabled) {
      AddSharingHandler(
          std::make_unique<BrowserActuatorMessageHandler>(profile),
          {components_sharing_message::SharingMessage::
               kGlicExperimentalTriggering});
    } else {
      AddSharingHandler(
          std::make_unique<GlicExperimentalTriggeringMessageHandler>(
              profile, message_sender),
          {components_sharing_message::SharingMessage::
               kGlicExperimentalTriggering});
    }
  }
}

SharingHandlerRegistryImpl::~SharingHandlerRegistryImpl() = default;

SharingMessageHandler* SharingHandlerRegistryImpl::GetSharingHandler(
    components_sharing_message::SharingMessage::PayloadCase payload_case) {
  auto it = handler_map_.find(payload_case);
  if (it != handler_map_.end()) {
    return it->second;
  }

  auto extra_it = extra_handler_map_.find(payload_case);
  if (extra_it != extra_handler_map_.end()) {
    return extra_it->second.get();
  }

  return nullptr;
}

void SharingHandlerRegistryImpl::AddSharingHandler(
    std::unique_ptr<SharingMessageHandler> handler,
    std::set<components_sharing_message::SharingMessage::PayloadCase>
        payload_cases) {
  DCHECK(handler) << "Received request to add null handler";

  for (const auto& payload_case : payload_cases) {
    DCHECK(payload_case !=
           components_sharing_message::SharingMessage::PAYLOAD_NOT_SET)
        << "Incorrect payload type specified for handler";
    DCHECK(!handler_map_.count(payload_case)) << "Handler already exists";
    handler_map_[payload_case] = handler.get();
  }

  handlers_.push_back(std::move(handler));
}

void SharingHandlerRegistryImpl::RegisterSharingHandler(
    std::unique_ptr<SharingMessageHandler> handler,
    components_sharing_message::SharingMessage::PayloadCase payload_case) {
  DCHECK(handler) << "Received request to add null handler";
  DCHECK(!GetSharingHandler(payload_case));
  DCHECK(payload_case !=
         components_sharing_message::SharingMessage::PAYLOAD_NOT_SET)
      << "Incorrect payload type specified for handler";

  extra_handler_map_[payload_case] = std::move(handler);
}

void SharingHandlerRegistryImpl::UnregisterSharingHandler(
    components_sharing_message::SharingMessage::PayloadCase payload_case) {
  extra_handler_map_.erase(payload_case);
}
