// Copyright 2025 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/webui/settings/saved_info_handler.h"

#include "base/test/scoped_feature_list.h"
#include "chrome/browser/affiliations/affiliation_service_factory.h"
#include "chrome/browser/autofill/valuables_data_manager_factory.h"
#include "chrome/browser/password_manager/factories/account_password_store_factory.h"
#include "chrome/browser/password_manager/factories/profile_password_store_factory.h"
#include "chrome/browser/password_manager/password_manager_test_util.h"
#include "chrome/browser/ui/hats/hats_service_factory.h"
#include "chrome/browser/ui/hats/mock_hats_service.h"
#include "chrome/browser/ui/hats/survey_config.h"
#include "chrome/browser/ui/webui/settings/saved_info_handler_test_api.h"
#include "chrome/browser/webauthn/passkey_model_factory.h"
#include "chrome/test/base/testing_profile.h"
#include "components/affiliations/core/browser/fake_affiliation_service.h"
#include "components/autofill/core/browser/data_manager/test_personal_data_manager.h"
#include "components/autofill/core/browser/data_manager/valuables/test_valuables_data_manager.h"
#include "components/autofill/core/browser/data_manager/valuables/valuables_data_manager_test_api.h"
#include "components/autofill/core/browser/data_model/valuables/loyalty_card.h"
#include "components/autofill/core/browser/test_utils/valuables_data_test_utils.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_store/password_form_converters.h"
#include "components/password_manager/core/browser/password_store/test_password_store.h"
#include "components/webauthn/core/browser/test_passkey_model.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_web_ui.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace settings {

using autofill::LoyaltyCard;
using autofill::TestPersonalDataManager;
using autofill::TestValuablesDataManager;
using password_manager::PasswordForm;
using password_manager::TestPasswordStore;
using ::testing::_;

class SavedInfoHandlerTest : public testing::Test {
 public:
  SavedInfoHandlerTest() = default;
  ~SavedInfoHandlerTest() override = default;

  void SetUp() override {
    profile_ = std::make_unique<TestingProfile>();
    profile_store_ = CreateAndUseTestPasswordStore(profile_.get());
    AccountPasswordStoreFactory::GetInstance()->SetTestingFactory(
        profile_.get(),
        base::BindOnce(
            [](content::BrowserContext* context)
                -> scoped_refptr<RefcountedKeyedService> { return nullptr; }));
    PasskeyModelFactory::GetInstance()->SetTestingFactory(
        profile_.get(), base::BindOnce([](content::BrowserContext* context)
                                           -> std::unique_ptr<KeyedService> {
          return std::make_unique<webauthn::TestPasskeyModel>();
        }));
    AffiliationServiceFactory::GetInstance()->SetTestingFactory(
        profile_.get(),
        base::BindOnce(&SavedInfoHandlerTest::CreateAfilliationService,
                       base::Unretained(this)));
    valuables_data_manager_ = static_cast<TestValuablesDataManager*>(
        autofill::ValuablesDataManagerFactory::GetInstance()
            ->SetTestingFactoryAndUse(
                profile_.get(),
                base::BindOnce([](content::BrowserContext* context)
                                   -> std::unique_ptr<KeyedService> {
                  return std::make_unique<TestValuablesDataManager>();
                })));
    mock_hats_service_ = static_cast<MockHatsService*>(
        HatsServiceFactory::GetInstance()->SetTestingFactoryAndUse(
            profile_.get(), base::BindRepeating(&BuildMockHatsService)));
  }

  void TearDown() override { profile_store_->ShutdownOnUIThread(); }

  content::TestWebUI* web_ui() { return &web_ui_; }
  TestingProfile* profile() { return profile_.get(); }
  TestPasswordStore* profile_store() { return profile_store_.get(); }
  webauthn::TestPasskeyModel* passkey_model() {
    return static_cast<webauthn::TestPasskeyModel*>(
        PasskeyModelFactory::GetForProfile(profile_.get()));
  }
  affiliations::FakeAffiliationService* affiliation_service() {
    return &affiliation_service_;
  }
  TestValuablesDataManager* valuables_data_manager() {
    return valuables_data_manager_;
  }
  MockHatsService* mock_hats_service() { return mock_hats_service_; }

  void RunUntilIdle() { task_environment_.RunUntilIdle(); }

  std::unique_ptr<KeyedService> CreateAfilliationService(
      content::BrowserContext* context) {
    return std::make_unique<affiliations::FakeAffiliationService>();
  }

 private:
  content::BrowserTaskEnvironment task_environment_;
  std::unique_ptr<TestingProfile> profile_;
  content::TestWebUI web_ui_;
  scoped_refptr<TestPasswordStore> profile_store_;
  affiliations::FakeAffiliationService affiliation_service_;
  raw_ptr<TestValuablesDataManager> valuables_data_manager_;
  raw_ptr<MockHatsService> mock_hats_service_;
};

TEST_F(SavedInfoHandlerTest, HandleGetPasswordCount) {
  // Add 2 passwords.
  PasswordForm form;
  form.url = GURL("https://example.com");
  form.signon_realm = form.url.spec();
  form.username_value = u"username";
  form.password_value = u"password";
  form.in_store = PasswordForm::Store::kProfileStore;
  profile_store()->AddLogin(password_manager::FromPasswordForm(form));
  form.username_value = u"admin";
  form.password_value = u"hunter2";
  form.in_store = PasswordForm::Store::kProfileStore;
  profile_store()->AddLogin(password_manager::FromPasswordForm(form));

  // Add 1 passkey.
  sync_pb::WebauthnCredentialSpecifics passkey;
  passkey.set_credential_id("credential_id");
  passkey.set_rp_id("rp_id");
  passkey.set_user_id("user_id");
  passkey_model()->AddNewPasskeyForTesting(passkey);

  auto handler = std::make_unique<SavedInfoHandler>(profile());
  test_api(*handler).set_web_ui(web_ui());
  handler->RegisterMessages();
  handler->AllowJavascriptForTesting();
  RunUntilIdle();  // Allow presenter to initialize

  web_ui()->ClearTrackedCalls();

  base::ListValue args;
  args.Append("test_callback_id");
  test_api(*handler).HandleGetPasswordCount(args);

  EXPECT_EQ(1U, web_ui()->call_data().size());
  const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
  EXPECT_EQ("cr.webUIResponse", data.function_name());
  EXPECT_EQ("test_callback_id", data.arg1()->GetString());
  EXPECT_TRUE(data.arg2()->GetBool());

  const base::DictValue& dict = data.arg3()->GetDict();
  EXPECT_EQ(2, dict.FindInt("passwordCount"));
  EXPECT_EQ(1, dict.FindInt("passkeyCount"));
}

TEST_F(SavedInfoHandlerTest, HandleGetLoyaltyCardsCount) {
  // Add 2 loyalty cards.
  std::vector<LoyaltyCard> loyalty_cards;
  loyalty_cards.push_back(autofill::test::CreateLoyaltyCard());
  loyalty_cards.push_back(autofill::test::CreateLoyaltyCard2());
  autofill::test_api(*valuables_data_manager()).SetLoyaltyCards(loyalty_cards);

  auto handler = std::make_unique<SavedInfoHandler>(profile());
  test_api(*handler).set_web_ui(web_ui());
  handler->RegisterMessages();
  handler->AllowJavascriptForTesting();
  RunUntilIdle();  // Allow presenter to initialize

  web_ui()->ClearTrackedCalls();

  base::ListValue args;
  args.Append("test_callback_id");
  test_api(*handler).HandleGetLoyaltyCardsCount(args);

  EXPECT_EQ(1U, web_ui()->call_data().size());
  const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
  EXPECT_EQ("cr.webUIResponse", data.function_name());
  EXPECT_EQ("test_callback_id", data.arg1()->GetString());
  EXPECT_TRUE(data.arg2()->GetBool());
  EXPECT_TRUE(data.arg3()->is_int());
  EXPECT_EQ(2, data.arg3()->GetInt());
}

TEST_F(SavedInfoHandlerTest, RequestDataManagementSurvey) {
  base::test::ScopedFeatureList features(
      autofill::features::kManageYourSavedInfoPerceptionSurvey);

  auto handler = std::make_unique<SavedInfoHandler>(profile());
  test_api(*handler).set_web_ui(web_ui());
  handler->RegisterMessages();
  handler->AllowJavascriptForTesting();

  EXPECT_CALL(
      *mock_hats_service(),
      LaunchDelayedSurvey(kHatsSurveyTriggerManageYourSavedInfoPerception,
                          10000, _, _));

  base::ListValue args;
  args.Append(0);     // DataManagementSurvey::kYourSavedInfo
  args.Append(true);  // fromHomePage
  test_api(*handler).HandleRequestDataManagementSurvey(args);
}

}  // namespace settings
