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

#import "components/autofill/ios/form_util/form_handlers_java_script_feature.h"

#import "base/feature_list.h"
#import "base/no_destructor.h"
#import "base/values.h"
#import "components/autofill/core/common/autofill_features.h"
#import "components/autofill/ios/common/autofill_optimization_features.h"
#import "components/autofill/ios/common/features.h"
#import "components/autofill/ios/common/javascript_feature_util.h"
#import "components/autofill/ios/form_util/autofill_form_features_java_script_feature.h"
#import "components/autofill/ios/form_util/form_activity_tab_helper.h"
#import "components/autofill/ios/form_util/remote_frame_registration_java_script_feature.h"
#import "ios/web/public/js_messaging/java_script_feature.h"
#import "ios/web/public/js_messaging/java_script_feature_util.h"
#import "ios/web/public/js_messaging/script_message.h"

namespace autofill {

namespace {

using FeatureScript = web::JavaScriptFeature::FeatureScript;

constexpr char kFormHandlerScriptName[] = "form_handlers";
constexpr char kRemoteTokenRegistrationScriptName[] =
    "register_remote_frame_token";
constexpr char kScriptMessageName[] = "FormHandlersMessage";

std::vector<web::JavaScriptFeature::FeatureScript> GetFeatureScripts() {
  std::vector<FeatureScript> feature_scripts;

  auto placeholder_replacements_callback = base::BindRepeating(
      []() -> web::JavaScriptFeature::FeatureScript::PlaceholderReplacements {
        // Override the placeholder for setting the capture mode of the form
        // submission listener.
        bool use_capture = base::FeatureList::IsEnabled(
            kAutofillFormSubmissionEventsInCaptureMode);
        return @{
          @"{{PlaceholderFormSubmissionListenerCapture}}" :
                  use_capture ? @"true" : @"false",
          @"window.gCrWebPlaceholderAutofillOptimizationFormSearch" :
                  base::FeatureList::IsEnabled(
                      features::kAutofillOptimizationFormSearchIos)
              ? @"true"
              : @"false",
          @"window.gCrWebPlaceholderTrackFormMutationsOptimization" :
                  base::FeatureList::IsEnabled(
                      features::kAutofillTrackFormMutationsOptimizationIos)
              ? @"true"
              : @"false",
        };
      });

  feature_scripts.push_back(FeatureScript::CreateWithFilename(
      kFormHandlerScriptName, FeatureScript::InjectionTime::kDocumentStart,
      FeatureScript::TargetFrames::kAllFrames,
      FeatureScript::ReinjectionBehavior::kReinjectOnDocumentRecreation,
      placeholder_replacements_callback));

  feature_scripts.push_back(FeatureScript::CreateWithFilename(
      kRemoteTokenRegistrationScriptName,
      FeatureScript::InjectionTime::kDocumentStart,
      FeatureScript::TargetFrames::kAllFrames,
      FeatureScript::ReinjectionBehavior::kReinjectOnDocumentRecreation));

  return feature_scripts;
}

}  // namespace

// static
FormHandlersJavaScriptFeature* FormHandlersJavaScriptFeature::GetInstance() {
  static base::NoDestructor<FormHandlersJavaScriptFeature> instance;
  return instance.get();
}

FormHandlersJavaScriptFeature::FormHandlersJavaScriptFeature()
    : web::JavaScriptFeature(
          ContentWorldForAutofillJavascriptFeatures(),
          GetFeatureScripts(),
          {
              AutofillFormFeaturesJavaScriptFeature::GetInstance(),
              RemoteFrameRegistrationJavaScriptFeature::GetInstance(),
          }) {}

FormHandlersJavaScriptFeature::~FormHandlersJavaScriptFeature() = default;

void FormHandlersJavaScriptFeature::TrackFormMutations(
    web::WebFrame* frame,
    int mutation_tracking_delay) {
  CallJavaScriptFunction(frame, "formHandlers.trackFormMutations",
                         base::ListValue().Append(mutation_tracking_delay));
}

std::optional<std::string>
FormHandlersJavaScriptFeature::GetScriptMessageHandlerName() const {
  return kScriptMessageName;
}

void FormHandlersJavaScriptFeature::ScriptMessageReceived(
    web::WebState* web_state,
    const web::ScriptMessage& message) {
  // Delegate to FormActivityTabHelper for all other messages.
  FormActivityTabHelper* helper =
      FormActivityTabHelper::GetOrCreateForWebState(web_state);
  helper->OnFormMessageReceived(web_state, message);
}

FormHandlersJavaScriptFeature::FormHandlersJavaScriptFeature(
    RemoteFrameRegistrationJavaScriptFeature*
        remote_frame_registration_java_script_feature)
    : web::JavaScriptFeature(ContentWorldForAutofillJavascriptFeatures(),
                             GetFeatureScripts(),
                             {remote_frame_registration_java_script_feature}) {}

}  // namespace autofill
