// 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/profiles/profile_metrics.h"

#include <string>
#include <vector>

#include "base/files/file_path.h"
#include "base/strings/to_string.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/time/time.h"
#include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_attributes_init_params.h"
#include "chrome/browser/profiles/profile_attributes_storage.h"
#include "components/prefs/testing_pref_service.h"
#include "content/public/test/browser_task_environment.h"
#include "google_apis/gaia/gaia_id.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

struct ProfileConfig {
  std::u16string gaia_name;
  bool active = true;
  bool sync_consent = false;
  bool supervised = false;
  bool managed = false;
};

struct ProfileMetricsParam {
  std::vector<ProfileConfig> profiles;
  int expected_managed_profile_count = 0;
  int expected_sync_consent_profile_count = 0;
  int expected_active_profile_count = 0;
};

const ProfileMetricsParam profile_metrics_test_params[] = {
    // Single signed out active profile
    {.profiles = {ProfileConfig()}, .expected_active_profile_count = 1},
    // Inactive profile.
    {.profiles = {{.active = false}}},
    // Supervised profile.
    {.profiles = {{.supervised = true}},
     .expected_managed_profile_count = 1,
     .expected_active_profile_count = 1},
    // Syncing in profile.
    {.profiles = {{.sync_consent = true}},
     .expected_sync_consent_profile_count = 1,
     .expected_active_profile_count = 1},
    // With Gaia name.
    {
        .profiles = {{.gaia_name = u"FirstName"}},
        .expected_active_profile_count = 1,
    },
    // Multiple profiles with various states.
    {
        .profiles = {{.active = false},
                     {.sync_consent = true, .supervised = true},
                     {.gaia_name = u"Name1", .active = false},
                     {.gaia_name = u"Name2"}},
        .expected_managed_profile_count = 1,
        .expected_sync_consent_profile_count = 1,
        .expected_active_profile_count = 2,
    },
    // Duplicate Gaia name (non-managed).
    {
        .profiles = {{.gaia_name = u"Name"}, {.gaia_name = u"Name"}},
        .expected_active_profile_count = 2,
    },
    // Duplicate Gaia name (managed).
    {
        .profiles = {{.gaia_name = u"Name"},
                     {.gaia_name = u"Name", .managed = true}},
        .expected_active_profile_count = 2,
    },
    // Duplicate Gaia name: non-managed takes priority over managed.
    {
        .profiles = {{.gaia_name = u"Name"},
                     {.gaia_name = u"Name"},
                     {.gaia_name = u"Name", .managed = true}},
        .expected_active_profile_count = 3,
    },
    // Multiple names with mixed sharing status.
    {
        .profiles = {{ProfileConfig()},
                     {.gaia_name = u"Name1"},
                     {.gaia_name = u"Name1"},
                     {.gaia_name = u"Name2", .managed = true},
                     {.gaia_name = u"Name3"},
                     {.gaia_name = u"Name2", .managed = true},
                     {.gaia_name = u"Name4"},
                     {.gaia_name = u"Name1"}},
        .expected_active_profile_count = 8,
    },
};

}  // namespace

class ProfileMetricsParamsTest
    : public testing::TestWithParam<ProfileMetricsParam> {
 protected:
  content::BrowserTaskEnvironment task_environment_;
  TestingPrefServiceSimple prefs_;
};

TEST_P(ProfileMetricsParamsTest, LogNumberOfProfiles) {
  ProfileAttributesStorage::RegisterPrefs(prefs_.registry());
  const ProfileMetricsParam test_param = GetParam();
  base::FilePath user_data_dir = base::FilePath(FILE_PATH_LITERAL("/Foo"));
  ProfileAttributesStorage storage(&prefs_, user_data_dir);

  int i = 0;
  for (const ProfileConfig& profile_config : test_param.profiles) {
    ProfileAttributesInitParams profile_init_params;
    base::FilePath profile_path = user_data_dir.AppendASCII(base::ToString(i));
    profile_init_params.profile_path = profile_path;
    profile_init_params.profile_name = u"profile name";
    storage.AddProfile(std::move(profile_init_params));
    ProfileAttributesEntry* entry =
        storage.GetProfileAttributesWithPath(profile_path);
    CHECK(entry);
    entry->SetGAIAGivenName(profile_config.gaia_name);
    if (profile_config.active) {
      entry->SetActiveTimeToNow();
    }
    if (profile_config.supervised) {
      entry->SetSupervisedUserId("supervised id");
    }
    if (profile_config.sync_consent) {
      entry->SetAuthInfo(GaiaId("gaia"), u"email", true);
    }
    entry->SetUserAcceptedAccountManagement(profile_config.managed);
    ++i;
  }

  base::HistogramTester histogram_tester;
  ProfileMetrics::LogNumberOfProfiles(&storage);

  histogram_tester.ExpectUniqueSample("Profile.NumberOfProfiles",
                                      test_param.profiles.size(), 1);
  histogram_tester.ExpectUniqueSample(
      "Profile.NumberOfSignedInProfiles",
      test_param.expected_sync_consent_profile_count, 1);
  histogram_tester.ExpectUniqueSample(
      "Profile.NumberOfSignedInProfiles.1Day",
      test_param.expected_sync_consent_profile_count, 1);
  histogram_tester.ExpectUniqueSample(
      "Profile.NumberOfSignedInProfiles.7Days",
      test_param.expected_sync_consent_profile_count, 1);

  histogram_tester.ExpectUniqueSample("Profile.NumberOfManagedProfiles",
                                      test_param.expected_managed_profile_count,
                                      1);
  histogram_tester.ExpectUniqueSample("Profile.NumberOfManagedProfiles.1Day",
                                      test_param.expected_managed_profile_count,
                                      1);
  histogram_tester.ExpectUniqueSample("Profile.NumberOfManagedProfiles.7Days",
                                      test_param.expected_managed_profile_count,
                                      1);
#if BUILDFLAG(IS_ANDROID)
  // All profiles are considered active on Android.
  histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles",
                                      test_param.profiles.size(), 1);
  histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles.1Day",
                                      test_param.profiles.size(), 1);
  histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles.7Days",
                                      test_param.profiles.size(), 1);

  histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles", 0, 1);
  histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles.1Day", 0,
                                      1);
  histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles.7Days", 0,
                                      1);
#else
  histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles",
                                      test_param.expected_active_profile_count,
                                      1);
  histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles.1Day",
                                      test_param.expected_active_profile_count,
                                      1);
  histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles.7Days",
                                      test_param.expected_active_profile_count,
                                      1);

  histogram_tester.ExpectUniqueSample(
      "Profile.NumberOfUnusedProfiles",
      test_param.profiles.size() - test_param.expected_active_profile_count, 1);
  histogram_tester.ExpectUniqueSample(
      "Profile.NumberOfUnusedProfiles.1Day",
      test_param.profiles.size() - test_param.expected_active_profile_count, 1);
  histogram_tester.ExpectUniqueSample(
      "Profile.NumberOfUnusedProfiles.7Days",
      test_param.profiles.size() - test_param.expected_active_profile_count, 1);
#endif  // BUILDFLAG(IS_ANDROID)
}

INSTANTIATE_TEST_SUITE_P(,
                         ProfileMetricsParamsTest,
                         testing::ValuesIn(profile_metrics_test_params));

#if !BUILDFLAG(IS_ANDROID)
TEST(ProfileMetrics, ThresholdTest) {
  content::BrowserTaskEnvironment task_environment{
      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
  TestingPrefServiceSimple prefs_;
  ProfileAttributesStorage::RegisterPrefs(prefs_.registry());

  base::FilePath user_data_dir = base::FilePath(FILE_PATH_LITERAL("/Foo"));
  ProfileAttributesStorage storage(&prefs_, user_data_dir);
  // Create 2 profiles.
  base::FilePath profile_path = user_data_dir.AppendASCII("profile");
  {
    ProfileAttributesInitParams profile_init_params;
    profile_init_params.profile_path = profile_path;
    profile_init_params.profile_name = u"profile";
    storage.AddProfile(std::move(profile_init_params));
  }

  ProfileAttributesEntry* entry =
      storage.GetProfileAttributesWithPath(profile_path);
  CHECK(entry);
  entry->SetActiveTimeToNow();

  {
    base::HistogramTester histogram_tester;
    ProfileMetrics::LogNumberOfProfiles(&storage);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfProfiles", 1, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles.1Day",
                                        1, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles.7Days",
                                        1, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles", 1, 1);

    histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles.1Day",
                                        0, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles.7Days",
                                        0, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles", 0, 1);
  }

  // Total fast forward: 2 Days.
  task_environment.FastForwardBy(base::Days(2));
  {
    base::HistogramTester histogram_tester;
    ProfileMetrics::LogNumberOfProfiles(&storage);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfProfiles", 1, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles.1Day",
                                        0, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles.7Days",
                                        1, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles", 1, 1);

    histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles.1Day",
                                        1, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles.7Days",
                                        0, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles", 0, 1);
  }

  // Total fast forward: 8 Days.
  task_environment.FastForwardBy(base::Days(6));
  {
    base::HistogramTester histogram_tester;
    ProfileMetrics::LogNumberOfProfiles(&storage);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfProfiles", 1, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles.1Day",
                                        0, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles.7Days",
                                        0, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles", 1, 1);

    histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles.1Day",
                                        1, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles.7Days",
                                        1, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles", 0, 1);
  }

  // Total fast forward: 29 Days.
  task_environment.FastForwardBy(base::Days(21));
  {
    base::HistogramTester histogram_tester;
    ProfileMetrics::LogNumberOfProfiles(&storage);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfProfiles", 1, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles.1Day",
                                        0, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles.7Days",
                                        0, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles", 0, 1);

    histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles.1Day",
                                        1, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles.7Days",
                                        1, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles", 1, 1);
  }

  // Make profile active now again, all histograms should record.
  entry->SetActiveTimeToNow();
  {
    base::HistogramTester histogram_tester;
    ProfileMetrics::LogNumberOfProfiles(&storage);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfProfiles", 1, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles.1Day",
                                        1, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles.7Days",
                                        1, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfActiveProfiles", 1, 1);

    histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles.1Day",
                                        0, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles.7Days",
                                        0, 1);
    histogram_tester.ExpectUniqueSample("Profile.NumberOfUnusedProfiles", 0, 1);
  }
}
#endif  // !BUILDFLAG(IS_ANDROID)
