// 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 "chrome/browser/btm/btm_browser_signin_detector.h"

#include <cstddef>

#include "base/check.h"
#include "base/strings/strcat.h"
#include "base/time/time.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/btm_service.h"


const char kIdentityProviderDomain[] = "google.com";

BtmBrowserSigninDetector::BtmBrowserSigninDetector(
    base::PassKey<BtmBrowserSigninDetectorFactory>,
    content::BtmService* dips_service,
    signin::IdentityManager* identity_manager)
    : dips_service_(dips_service), identity_manager_(identity_manager) {
  CHECK(dips_service_);
  if (!identity_manager_) {
    // If there's no identity manager, then don't try to observe it.
    return;
  }
  scoped_observation_.Observe(identity_manager_.get());

  // No need to check the cookie jar if there's no presence of a primary
  // account.
  if (!identity_manager_->HasPrimaryAccount(signin::ConsentLevel::kSignin)) {
    return;
  }

  auto accounts = identity_manager_->GetAccountsInCookieJar();

  // Check the cookie jar in case the identity manager updated the accounts
  // before the observation kicked-in.
  for (const auto& account : accounts.GetPotentiallyInvalidSignedInAccounts()) {
    RecordUserActivationsIfRelevant(
        identity_manager_->FindExtendedAccountInfoByAccountId(account.id));
  }
}

BtmBrowserSigninDetector::~BtmBrowserSigninDetector() = default;

void BtmBrowserSigninDetector::Shutdown() {
  scoped_observation_.Reset();
  dips_service_ = nullptr;
  identity_manager_ = nullptr;
}

// Evaluates whether an information is relevant for DIPS. An info is relevant if
// its core infos are non empty and the |hosted_domain| info is provided.
bool IsInfoRelevant(const AccountInfo& info) {
  // Note: extended infos such as |hosted_domain| are filled asynchronously.
  return !info.CoreAccountInfo::IsEmpty() && info.GetHostedDomain().has_value();
}

void BtmBrowserSigninDetector::RecordUserActivationsIfRelevant(
    const AccountInfo& info) {
  if (!IsInfoRelevant(info)) {
    return;
  }
  CHECK(info.GetHostedDomain().has_value());

  // Record a user activation for `kIdentityProviderDomain`.
  // Note: All accounts in the identity manager are GAIA accounts. Thus,
  // non-enterprise accounts (ex. "gmail.com", "yahoo.com") will be treated as
  // having a user activation with `kIdentityProviderDomain`.
  dips_service_->RecordBrowserSignIn(kIdentityProviderDomain);

  // Skip handled cases.
  if (std::optional<std::string_view> hosted_domain = info.GetHostedDomain();
      hosted_domain->empty() || *hosted_domain == kIdentityProviderDomain) {
    return;
  }

  // Record a user activation for the |info.host_domain| of all enterprise
  // accounts.
  dips_service_->RecordBrowserSignIn(*info.GetHostedDomain());
}

void BtmBrowserSigninDetector::OnExtendedAccountInfoUpdated(
    const AccountInfo& info) {
  RecordUserActivationsIfRelevant(info);
}
