// Copyright 2024 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/ui/autofill/autofill_message_controller_impl.h"

#include <memory>

#include "base/strings/strcat.h"
#include "base/test/metrics/histogram_tester.h"
#include "chrome/browser/ui/autofill/autofill_message_controller_test_api.h"
#include "chrome/browser/ui/autofill/autofill_message_model.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "components/messages/android/message_enums.h"
#include "components/messages/android/mock_message_dispatcher_bridge.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace autofill {
class AutofillMessageControllerImplTest
    : public ChromeRenderViewHostTestHarness {
 public:
  AutofillMessageControllerImplTest() = default;

  void SetUp() override {
    ChromeRenderViewHostTestHarness::SetUp();
    messages::MessageDispatcherBridge::SetInstanceForTesting(
        &message_dispatcher_bridge_);
  }

  AutofillMessageModel* CreateAndShowSaveCardFailureMessage() {
    std::unique_ptr<AutofillMessageModel> message =
        AutofillMessageModel::CreateForSaveCardFailure();
    AutofillMessageModel* message_ptr = message.get();

    controller().Show(std::move(message));

    return message_ptr;
  }

  AutofillMessageModel* CreateAndShowEntitySaveUpdateFlowMessage() {
    std::unique_ptr<AutofillMessageModel> message =
        std::make_unique<AutofillMessageModel>(
            std::make_unique<messages::MessageWrapper>(
                messages::MessageIdentifier::SAVE_UPDATE_ENTITY),
            AutofillMessageModel::Type::kEntitySaveUpdateFlow);
    AutofillMessageModel* message_ptr = message.get();

    controller().Show(std::move(message));

    return message_ptr;
  }

  // Expect a `EnqueueMessage` call to the message dispatcher bridge `times`
  // number of times.
  void ExpectEnqueueMessageCall(int times = 1) {
    EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage).Times(times);
  }

  // Expect a `DismissMessage` call to the message dispatcher bridge with
  // `reason` as the dismiss reason and `times` number of times.
  void ExpectDismissMessageCallWithReason(messages::DismissReason reason,
                                          int times = 1) {
    EXPECT_CALL(message_dispatcher_bridge_, DismissMessage(testing::_, reason))
        .Times(times);
  }

  // Find a message model owned by the controller.
  AutofillMessageModel* FindMessageModel(
      AutofillMessageModel* message_model_ptr) {
    auto message_models = test_api(controller()).GetMessageModels();
    auto it = message_models.find(message_model_ptr);
    if (it == message_models.end()) {
      return nullptr;
    }
    return (*it).get();
  }

  AutofillMessageControllerImpl& controller() {
    if (!controller_) {
      controller_ = new AutofillMessageControllerImpl(web_contents());
    }
    return *controller_;
  }

  std::set<raw_ptr<AutofillMessageModel>> message_models() {
    return test_api(controller()).GetMessageModels();
  }

 private:
  raw_ptr<AutofillMessageControllerImpl> controller_;
  messages::MockMessageDispatcherBridge message_dispatcher_bridge_;
};

TEST_F(AutofillMessageControllerImplTest, Show) {
  ExpectEnqueueMessageCall();

  AutofillMessageModel* message = CreateAndShowSaveCardFailureMessage();

  EXPECT_EQ(FindMessageModel(message), message);
}

TEST_F(AutofillMessageControllerImplTest, ShowTwiceWithoutDismiss) {
  ExpectEnqueueMessageCall(/*times=*/2);

  CreateAndShowSaveCardFailureMessage();
  CreateAndShowSaveCardFailureMessage();

  EXPECT_THAT(message_models(), testing::SizeIs(2));
}

TEST_F(AutofillMessageControllerImplTest, OnDismissed) {
  AutofillMessageModel* first_message = CreateAndShowSaveCardFailureMessage();
  AutofillMessageModel* second_message = CreateAndShowSaveCardFailureMessage();

  test_api(controller())
      .OnDismissed(first_message, messages::DismissReason::PRIMARY_ACTION);

  EXPECT_THAT(message_models(), testing::SizeIs(1));
  EXPECT_EQ(FindMessageModel(second_message), second_message);
}

TEST_F(AutofillMessageControllerImplTest, Dismiss) {
  CreateAndShowSaveCardFailureMessage();
  CreateAndShowSaveCardFailureMessage();

  ExpectDismissMessageCallWithReason(messages::DismissReason::UNKNOWN,
                                     /*times=*/2);

  test_api(controller()).Dismiss();
}

TEST_F(AutofillMessageControllerImplTest, DismissWithoutMessages) {
  ExpectDismissMessageCallWithReason(messages::DismissReason::UNKNOWN,
                                     /*times=*/0);

  test_api(controller()).Dismiss();
}

TEST_F(AutofillMessageControllerImplTest, Metrics_Show_EntitySaveUpdateFlow) {
  base::HistogramTester histogram_tester;
  AutofillMessageModel* message = CreateAndShowEntitySaveUpdateFlowMessage();

  histogram_tester.ExpectUniqueSample(
      base::StrCat({"Autofill.Message.", message->GetTypeAsString(), ".Shown"}),
      true, 1);
}

TEST_F(AutofillMessageControllerImplTest,
       Metrics_OnActionClicked_EntitySaveUpdateFlow) {
  base::HistogramTester histogram_tester;
  AutofillMessageModel* message = CreateAndShowEntitySaveUpdateFlowMessage();

  test_api(controller()).OnActionClicked(message);

  histogram_tester.ExpectUniqueSample(
      base::StrCat(
          {"Autofill.Message.", message->GetTypeAsString(), ".ActionClicked"}),
      true, 1);
}

TEST_F(AutofillMessageControllerImplTest,
       Metrics_OnDismissed_EntitySaveUpdateFlow) {
  base::HistogramTester histogram_tester;
  messages::DismissReason dismiss_reason =
      messages::DismissReason::PRIMARY_ACTION;
  AutofillMessageModel* message = CreateAndShowEntitySaveUpdateFlowMessage();
  std::string_view type_as_string = message->GetTypeAsString();

  test_api(controller()).OnDismissed(message, dismiss_reason);

  histogram_tester.ExpectUniqueSample(
      base::StrCat({"Autofill.Message.", type_as_string, ".Dismissed"}),
      dismiss_reason, 1);
}

TEST_F(AutofillMessageControllerImplTest, Metrics_Show_OtherTypesNoMetrics) {
  base::HistogramTester histogram_tester;
  AutofillMessageModel* message = CreateAndShowSaveCardFailureMessage();

  histogram_tester.ExpectTotalCount(
      base::StrCat({"Autofill.Message.", message->GetTypeAsString(), ".Shown"}),
      0);
}

TEST_F(AutofillMessageControllerImplTest,
       Metrics_OnActionClicked_OtherTypesNoMetrics) {
  base::HistogramTester histogram_tester;
  AutofillMessageModel* message = CreateAndShowSaveCardFailureMessage();

  test_api(controller()).OnActionClicked(message);

  histogram_tester.ExpectTotalCount(
      base::StrCat(
          {"Autofill.Message.", message->GetTypeAsString(), ".ActionClicked"}),
      0);
}

TEST_F(AutofillMessageControllerImplTest,
       Metrics_OnDismissed_OtherTypesNoMetrics) {
  base::HistogramTester histogram_tester;
  messages::DismissReason dismiss_reason =
      messages::DismissReason::PRIMARY_ACTION;
  AutofillMessageModel* message = CreateAndShowSaveCardFailureMessage();
  std::string_view type_as_string = message->GetTypeAsString();

  test_api(controller()).OnDismissed(message, dismiss_reason);

  histogram_tester.ExpectTotalCount(
      base::StrCat({"Autofill.Message.", type_as_string, ".Dismissed"}), 0);
}

}  // namespace autofill
