// Copyright 2018 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/ui/test_autofill_external_delegate.h"

#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
#include "components/autofill/core/browser/metrics/suggestions_list_metrics.h"
#include "components/autofill/core/browser/suggestions/suggestion.h"
#include "components/autofill/core/browser/suggestions/suggestion_hiding_reason.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect_f.h"

namespace autofill {

TestAutofillExternalDelegate::TestAutofillExternalDelegate(
    BrowserAutofillManager* autofill_manager)
    : AutofillExternalDelegate(autofill_manager) {}

TestAutofillExternalDelegate::~TestAutofillExternalDelegate() = default;

void TestAutofillExternalDelegate::OnSuggestionsShown(
    base::span<const Suggestion> suggestions,
    base::optional_ref<const SuggestionMetadata> parent_suggestion_metadata) {
  popup_hidden_ = false;

  AutofillExternalDelegate::OnSuggestionsShown(suggestions,
                                               parent_suggestion_metadata);
}

void TestAutofillExternalDelegate::OnSuggestionsHidden(
    SuggestionHidingReason reason) {
  popup_hidden_ = true;

  run_loop_.Quit();
}

void TestAutofillExternalDelegate::OnQuery(
    const FormData& form,
    const FormFieldData& field,
    const gfx::Rect& caret_bounds,
    AutofillSuggestionTriggerSource trigger_source) {
  on_query_seen_ = true;
  on_suggestions_returned_seen_ = false;
  trigger_source_ = trigger_source;
  AutofillExternalDelegate::OnQuery(form, field, caret_bounds, trigger_source);
}

void TestAutofillExternalDelegate::OnSuggestionsReturned(
    const FormFieldData& trigger_field,
    const std::vector<Suggestion>& suggestions,
    std::u16string prefilled_query) {
  on_suggestions_returned_seen_ = true;
  field_id_ = trigger_field.global_id();
  suggestions_ = suggestions;
  AutofillExternalDelegate::OnSuggestionsReturned(trigger_field, suggestions,
                                                  std::move(prefilled_query));
}

bool TestAutofillExternalDelegate::HasActiveScreenReader() const {
  return has_active_screen_reader_;
}

void TestAutofillExternalDelegate::OnAutofillAvailabilityEvent(
    mojom::AutofillSuggestionAvailability suggestion_availability) {
  if (suggestion_availability ==
      mojom::AutofillSuggestionAvailability::kAutofillAvailable) {
    has_suggestions_available_on_field_focus_ = true;
  } else if (suggestion_availability ==
             mojom::AutofillSuggestionAvailability::kNoSuggestions) {
    has_suggestions_available_on_field_focus_ = false;
  }
}

void TestAutofillExternalDelegate::WaitForPopupHidden() {
  if (popup_hidden_)
    return;

  run_loop_.Run();
}

void TestAutofillExternalDelegate::CheckSuggestions(
    FieldGlobalId field_id,
    const std::vector<Suggestion>& expected_suggestions) {
  // Ensure that these results are from the most recent query.
  EXPECT_TRUE(on_suggestions_returned_seen_);

  EXPECT_EQ(field_id, field_id_);
  ASSERT_EQ(expected_suggestions.size(), suggestions_.size());
  for (size_t i = 0; i < suggestions_.size(); ++i) {
    SCOPED_TRACE(base::StringPrintf("i: %" PRIuS, i));
    EXPECT_EQ(expected_suggestions[i].main_text.value,
              suggestions_[i].main_text.value);
    ASSERT_EQ(expected_suggestions[i].minor_texts.size(),
              suggestions_[i].minor_texts.size());
    EXPECT_EQ(expected_suggestions[i].minor_texts, suggestions_[i].minor_texts);
    EXPECT_EQ(expected_suggestions[i].labels, suggestions_[i].labels);
    EXPECT_EQ(expected_suggestions[i].icon, suggestions_[i].icon);
    EXPECT_EQ(expected_suggestions[i].type, suggestions_[i].type);
    EXPECT_EQ(expected_suggestions[i].IsAcceptable(),
              suggestions_[i].IsAcceptable());
  }
}

void TestAutofillExternalDelegate::CheckSuggestionsNotReturned(
    FieldGlobalId field_id) {
  if (on_suggestions_returned_seen_) {
    EXPECT_NE(field_id, field_id_);
  }
}

void TestAutofillExternalDelegate::CheckNoSuggestions(FieldGlobalId field_id) {
  CheckSuggestions(field_id, {});
}

void TestAutofillExternalDelegate::CheckSuggestionCount(
    FieldGlobalId field_id,
    size_t expected_num_suggestions) {
  // Ensure that these results are from the most recent query.
  EXPECT_TRUE(on_suggestions_returned_seen_);

  EXPECT_EQ(field_id, field_id_);
  ASSERT_EQ(expected_num_suggestions, suggestions_.size());
}

const std::vector<Suggestion>& TestAutofillExternalDelegate::suggestions()
    const {
  return suggestions_;
}

bool TestAutofillExternalDelegate::on_query_seen() const {
  return on_query_seen_;
}

bool TestAutofillExternalDelegate::on_suggestions_returned_seen() const {
  return on_suggestions_returned_seen_;
}

AutofillSuggestionTriggerSource TestAutofillExternalDelegate::trigger_source()
    const {
  return trigger_source_;
}

bool TestAutofillExternalDelegate::popup_hidden() const {
  return popup_hidden_;
}

void TestAutofillExternalDelegate::set_has_active_screen_reader(
    bool has_active_screen_reader) {
  has_active_screen_reader_ = has_active_screen_reader;
}

bool TestAutofillExternalDelegate::has_suggestions_available_on_field_focus()
    const {
  return has_suggestions_available_on_field_focus_;
}

}  // namespace autofill
