// 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/supervised_user/supervised_user_browser_utils.h"

#include <string>

#include "base/check.h"
#include "base/feature_list.h"
#include "base/strings/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_selections.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/supervised_user/child_accounts/child_account_service_factory.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/webui_url_constants.h"
#include "components/prefs/pref_service.h"
#include "components/security_interstitials/content/security_interstitial_tab_helper.h"
#include "components/signin/public/base/consent_level.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/signin/public/identity_manager/tribool.h"
#include "components/supervised_user/core/browser/child_account_service.h"
#include "components/supervised_user/core/browser/family_link_user_capabilities.h"
#include "components/supervised_user/core/common/features.h"
#include "components/supervised_user/core/common/pref_names.h"
#include "components/supervised_user/core/common/supervised_user_constants.h"
#include "components/url_matcher/url_util.h"
#include "content/public/browser/navigation_handle.h"
#include "extensions/buildflags/buildflags.h"
#include "extensions/common/extension_urls.h"
#include "google_apis/gaia/core_account_id.h"
#include "url/url_constants.h"

#if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_type.h"
#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
#include "chrome/browser/supervised_user/supervised_user_verification_controller_client.h"
#include "chrome/browser/supervised_user/supervised_user_verification_page_blocked_sites.h"
#include "chrome/browser/supervised_user/supervised_user_verification_page_youtube.h"
#endif

namespace supervised_user {

bool IsSupportedChromeExtensionURL(const GURL& effective_url) {
#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
  static const char* const kCrxDownloadUrls[] = {
      "https://clients2.googleusercontent.com/crx/blobs/",
      "https://chrome.google.com/webstore/download/"};

  // Chrome Webstore.
  if (extension_urls::IsWebstoreDomain(
          url_matcher::util::Normalize(effective_url))) {
    return true;
  }

  // Allow webstore crx downloads. This applies to both extension installation
  // and updates.
  if (extension_urls::GetWebstoreUpdateUrl() ==
      url_matcher::util::Normalize(effective_url)) {
    return true;
  }

  // The actual CRX files are downloaded from other URLs. Allow them too.
  // These URLs have https scheme.
  if (!effective_url.SchemeIs(url::kHttpsScheme)) {
    return false;
  }

  for (const char* crx_download_url_str : kCrxDownloadUrls) {
    GURL crx_download_url(crx_download_url_str);
    if (crx_download_url.host() == effective_url.host() &&
        base::StartsWith(effective_url.path(), crx_download_url.path(),
                         base::CompareCase::SENSITIVE)) {
      return true;
    }
  }
  return false;
#else
  return false;
#endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE)
}

bool SupervisedUserCanSkipExtensionParentApprovals(const Profile* profile) {
#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
  return profile->IsChild() &&
         profile->GetPrefs()->GetBoolean(
             prefs::kSkipParentApprovalToInstallExtensions);
#else
  return false;
#endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE)
}

bool AreExtensionsPermissionsEnabled(Profile* profile) {
#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
  return profile->IsChild();
#else
  return false;
#endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE)
}

bool ShouldContentSkipParentAllowlistFiltering(content::WebContents* contents) {
  // Note that |contents| can be an inner WebContents. Get the outer most
  // WebContents and check if it belongs to the EDUCoexistence login flow.
  content::WebContents* outer_most_content =
      contents->GetOutermostWebContents();

  return outer_most_content->GetLastCommittedURL() ==
         GURL(chrome::kChromeUIEDUCoexistenceLoginURLV2);
}

ProfileSelections BuildProfileSelectionsForRegularAndGuest() {
#if BUILDFLAG(IS_CHROMEOS)
  return ProfileSelections::Builder()
      .WithRegular(ProfileSelection::kRedirectedToOriginal)
      .WithGuest(ProfileSelection::kOwnInstance)
      // TODO(crbug.com/41488885): Check if this is needed for Ash Internals.
      .WithAshInternals(ProfileSelection::kOriginalOnly)
      .Build();
#else
  // Do not create for Incognito profile.
  return ProfileSelections::Builder()
      .WithRegular(ProfileSelection::kOriginalOnly)
      .WithGuest(ProfileSelection::kRedirectedToOriginal)
      .Build();
#endif
}

std::string GetAccountGivenName(Profile& profile) {
  signin::IdentityManager* identity_manager =
      IdentityManagerFactory::GetForProfile(profile.GetOriginalProfile());
  CHECK(identity_manager);

  const CoreAccountId primary_account_id =
      identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSignin);
  const AccountInfo account_info =
      identity_manager->FindExtendedAccountInfoByAccountId(primary_account_id);
  return std::string(account_info.GetGivenName().value_or(""));
}

void AssertChildStatusOfTheUser(Profile* profile, bool is_child) {
#if BUILDFLAG(IS_CHROMEOS)
  user_manager::User* user =
      ash::ProfileHelper::Get()->GetUserByProfile(profile);
  if (user && is_child != (user->GetType() == user_manager::UserType::kChild)) {
    LOG(FATAL) << "User child flag has changed: " << is_child;
  }
  if (!user && ash::ProfileHelper::IsUserProfile(profile)) {
    LOG(FATAL) << "User instance not found while setting child account flag.";
  }
#endif
}

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
std::string CreateReauthenticationInterstitialForYouTube(
    content::NavigationHandle& navigation_handle) {
  content::WebContents* web_contents = navigation_handle.GetWebContents();
  Profile* profile =
      Profile::FromBrowserContext(web_contents->GetBrowserContext());
  GURL request_url = navigation_handle.GetURL();
  bool is_main_frame = navigation_handle.GetNavigatingFrameType() ==
                       content::FrameType::kPrimaryMainFrame;

  std::unique_ptr<SupervisedUserVerificationPageForYouTube> blocking_page =
      std::make_unique<SupervisedUserVerificationPageForYouTube>(
          web_contents, profile->GetProfileUserName(), request_url,
          ChildAccountServiceFactory::GetForProfile(profile),
          std::make_unique<SupervisedUserVerificationControllerClient>(
              web_contents, profile->GetPrefs(),
              g_browser_process->GetApplicationLocale(),
              chrome::ChromeUINewTabURLAsGURL(), request_url),
          is_main_frame);

  std::string interstitial_html = blocking_page->GetHTMLContents();
  security_interstitials::SecurityInterstitialTabHelper::AssociateBlockingPage(
      &navigation_handle, std::move(blocking_page));
  return interstitial_html;
}

std::string CreateReauthenticationInterstitialForBlockedSites(
    content::NavigationHandle& navigation_handle) {
  content::WebContents* web_contents = navigation_handle.GetWebContents();
  Profile* profile =
      Profile::FromBrowserContext(web_contents->GetBrowserContext());
  GURL request_url = navigation_handle.GetURL();
  bool is_main_frame = navigation_handle.GetNavigatingFrameType() ==
                       content::FrameType::kPrimaryMainFrame;

  std::unique_ptr<SupervisedUserVerificationPageForBlockedSites> blocking_page =
      std::make_unique<SupervisedUserVerificationPageForBlockedSites>(
          web_contents, profile->GetProfileUserName(), request_url,
          ChildAccountServiceFactory::GetForProfile(profile),
          std::make_unique<SupervisedUserVerificationControllerClient>(
              web_contents, profile->GetPrefs(),
              g_browser_process->GetApplicationLocale(),
              chrome::ChromeUINewTabURLAsGURL(), request_url),
          is_main_frame);

  std::string interstitial_html = blocking_page->GetHTMLContents();
  security_interstitials::SecurityInterstitialTabHelper::AssociateBlockingPage(
      &navigation_handle, std::move(blocking_page));
  return interstitial_html;
}
#endif

}  // namespace supervised_user
