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

#include "components/autofill/core/browser/autofill_feedback_data.h"

#include "base/json/json_reader.h"
#include "base/test/gmock_expected_support.h"
#include "base/test/task_environment.h"
#include "base/values.h"
#include "components/autofill/core/browser/foundations/autofill_manager_test_api.h"
#include "components/autofill/core/browser/foundations/test_autofill_client.h"
#include "components/autofill/core/browser/foundations/test_autofill_driver.h"
#include "components/autofill/core/browser/foundations/test_browser_autofill_manager.h"
#include "components/autofill/core/browser/foundations/with_test_autofill_client_driver_manager.h"
#include "components/autofill/core/browser/test_utils/autofill_form_test_utils.h"
#include "components/autofill/core/browser/test_utils/autofill_test_utils.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_test_utils.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_data_test_api.h"
#include "testing/gmock/include/gmock/gmock.h"

namespace autofill {
namespace {

using test::CreateTestFormField;

constexpr char kExpectedFeedbackDataJSON[] = R"({
   "formStructures": [ {
      "formSignature": "15183533776559422799",
      "hostFrame": "AAAAAAAAAAAAAAABBBBBBBBBBBBBBBBC",
      "idAttribute": "",
      "mainFrameUrl": "https://example.test",
      "nameAttribute": "",
      "rendererId": "11",
      "sourceUrl": "https://example.com",
      "fields": [ {
         "autocompleteAttribute": "cc-given-name",
         "fieldSignature": "1969735877",
         "fieldTypes": [ "NAME_FIRST" ],
         "heuristicType": "CREDIT_CARD_NAME_FIRST",
         "hostFormSignature": "0",
         "htmlType": "HTML_TYPE_CREDIT_CARD_NAME_FIRST",
         "idAttribute": "",
         "isEmpty": true,
         "isFocusable": true,
         "isVisible": true,
         "labelAttribute": "Credit card first name",
         "parseableNameAttribute": "",
         "placeholderAttribute": "",
         "rank": "0",
         "rankInHostForm": "0",
         "rankInHostFormSignatureGroup": "0",
         "rankInSignatureGroup": "0",
         "section": "cc_name_first_0_11",
         "serverType": "NO_SERVER_DATA",
         "serverTypeIsOverride": false
      }, {
         "autocompleteAttribute": "cc-family-name",
         "fieldSignature": "3826793033",
         "fieldTypes": [ "NAME_LAST" ],
         "heuristicType": "CREDIT_CARD_NAME_LAST",
         "hostFormSignature": "0",
         "htmlType": "HTML_TYPE_CREDIT_CARD_NAME_LAST",
         "idAttribute": "",
         "isEmpty": true,
         "isFocusable": true,
         "isVisible": true,
         "labelAttribute": "Credit card last name",
         "parseableNameAttribute": "",
         "placeholderAttribute": "",
         "rank": "1",
         "rankInHostForm": "1",
         "rankInHostFormSignatureGroup": "0",
         "rankInSignatureGroup": "0",
         "section": "cc_name_first_0_11",
         "serverType": "NO_SERVER_DATA",
         "serverTypeIsOverride": false
      }, {
         "autocompleteAttribute": "",
         "fieldSignature": "1029417091",
         "fieldTypes": [ "EMAIL_ADDRESS" ],
         "heuristicType": "EMAIL_ADDRESS",
         "hostFormSignature": "0",
         "htmlType": "HTML_TYPE_UNSPECIFIED",
         "idAttribute": "",
         "isEmpty": true,
         "isFocusable": true,
         "isVisible": true,
         "labelAttribute": "E-mail address",
         "parseableNameAttribute": "",
         "placeholderAttribute": "",
         "rank": "2",
         "rankInHostForm": "2",
         "rankInHostFormSignatureGroup": "0",
         "rankInSignatureGroup": "0",
         "section": "cc_name_first_0_11",
         "serverType": "NO_SERVER_DATA",
         "serverTypeIsOverride": false
      } ]
   } ]
})";

FormData CreateFeedbackTestFormData() {
  return test::GetFormData({
      .fields = {{.role = FieldType::CREDIT_CARD_NAME_FIRST,
                  .autocomplete_attribute = "cc-given-name",
                  .form_control_type = FormControlType::kInputText},
                 {.role = FieldType::CREDIT_CARD_NAME_LAST,
                  .autocomplete_attribute = "cc-family-name",
                  .form_control_type = FormControlType::kInputText},
                 {.role = FieldType::EMAIL_ADDRESS,
                  .form_control_type = FormControlType::kInputEmail}},
  });
}

class AutofillFeedbackDataUnitTest
    : public testing::Test,
      public WithTestAutofillClientDriverManager<> {
 protected:
  void SetUp() override {
    InitAutofillClient();
    CreateAutofillDriver();
  }

  base::test::TaskEnvironment task_environment_{
      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
  test::AutofillUnitTestEnvironment autofill_test_environment_;
};

TEST_F(AutofillFeedbackDataUnitTest, CreatesCompleteReport) {
  FormData form = CreateFeedbackTestFormData();
  autofill_manager().OnFormsSeen(/*updated_forms=*/{form},
                                 /*removed_forms=*/{},
                                 AutofillManagerTestApi::pass_key());

  base::DictValue autofill_feedback_data =
      data_logs::FetchAutofillFeedbackData(&autofill_manager());

  ASSERT_OK_AND_ASSIGN(
      auto expected_data,
      base::JSONReader::ReadAndReturnValueWithError(
          kExpectedFeedbackDataJSON,
          base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS));
  ASSERT_TRUE(expected_data.is_dict());
  EXPECT_EQ(autofill_feedback_data, expected_data.GetDict());
}

TEST_F(AutofillFeedbackDataUnitTest, IncludesLastAutofillEventLogEntry) {
  FormData form = CreateFeedbackTestFormData();
  FormFieldData field = form.fields()[0];
  autofill_manager().OnFormsSeen(/*updated_forms=*/{form},
                                 /*removed_forms=*/{},
                                 AutofillManagerTestApi::pass_key());

  // Simulates an autofill event.
  Suggestion suggestion(u"TestValue", SuggestionType::kIbanEntry);
  autofill_manager().OnSingleFieldSuggestionSelected(
      suggestion, form.global_id(), field.global_id());

  ASSERT_OK_AND_ASSIGN(
      auto expected_data,
      base::JSONReader::ReadAndReturnValueWithError(
          kExpectedFeedbackDataJSON,
          base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS));
  ASSERT_TRUE(expected_data.is_dict());

  // Update the expected data with a last_autofill_event entry.
  base::DictValue last_autofill_event;
  last_autofill_event.Set("associatedCountry", "");
  last_autofill_event.Set("type", "SingleFieldFillerIban");
  expected_data.GetDict().Set("lastAutofillEvent",
                              std::move(last_autofill_event));

  EXPECT_EQ(data_logs::FetchAutofillFeedbackData(&autofill_manager()),
            expected_data.GetDict());
}

TEST_F(AutofillFeedbackDataUnitTest,
       NotIncludeLastAutofillEventIfExceedTimeLimit) {
  FormData form = CreateFeedbackTestFormData();
  const FormFieldData& field = form.fields()[0];
  autofill_manager().OnFormsSeen(/*updated_forms=*/{form},
                                 /*removed_forms=*/{},
                                 AutofillManagerTestApi::pass_key());

  // Simulates an autofill event.
  Suggestion suggestion(u"TestValue", SuggestionType::kIbanEntry);
  autofill_manager().OnSingleFieldSuggestionSelected(
      suggestion, form.global_id(), field.global_id());

  // Advance the clock 4 minutes should disregard the last autofill event log.
  task_environment_.FastForwardBy(base::Minutes(4));

  // Expected data does not contain the last_autofill_event entry.
  ASSERT_OK_AND_ASSIGN(
      auto expected_data,
      base::JSONReader::ReadAndReturnValueWithError(
          kExpectedFeedbackDataJSON,
          base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS));
  ASSERT_TRUE(expected_data.is_dict());

  EXPECT_EQ(data_logs::FetchAutofillFeedbackData(&autofill_manager()),
            expected_data.GetDict());
}

TEST_F(AutofillFeedbackDataUnitTest, IncludesExtraLogs) {
  FormData form = CreateFeedbackTestFormData();
  autofill_manager().OnFormsSeen(/*updated_forms=*/{form},
                                 /*removed_forms=*/{},
                                 AutofillManagerTestApi::pass_key());

  base::DictValue extra_logs;
  extra_logs.Set("triggerFormSignature", "123");
  extra_logs.Set("triggerFieldSignature", "456");

  base::DictValue autofill_feedback_data = data_logs::FetchAutofillFeedbackData(
      &autofill_manager(), extra_logs.Clone());

  ASSERT_OK_AND_ASSIGN(
      auto expected_data,
      base::JSONReader::ReadAndReturnValueWithError(
          kExpectedFeedbackDataJSON,
          base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS));
  ASSERT_TRUE(expected_data.is_dict());
  // Include extra logs in the expected report.
  expected_data.GetDict().Merge(std::move(extra_logs));
  EXPECT_EQ(autofill_feedback_data, expected_data.GetDict());
}

}  // namespace
}  // namespace autofill
