// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/sync/sync_ui_util.h"

#include <utility>

#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/signin/signin_util.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/singleton_tabs.h"
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/strings/grit/components_strings.h"
#include "components/sync/driver/sync_service.h"
#include "components/sync/driver/sync_user_settings.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "net/base/url_util.h"

#if defined(OS_CHROMEOS)
#include "chromeos/constants/chromeos_features.h"
#endif

namespace sync_ui_util {

namespace {

StatusLabels GetStatusForUnrecoverableError(bool is_user_signout_allowed) {
#if !defined(OS_CHROMEOS)
  int status_label_string_id =
      is_user_signout_allowed
          ? IDS_SYNC_STATUS_UNRECOVERABLE_ERROR
          :
          // The message for managed accounts is the same as that on ChromeOS.
          IDS_SYNC_STATUS_UNRECOVERABLE_ERROR_NEEDS_SIGNOUT;
#else
  int status_label_string_id =
      IDS_SYNC_STATUS_UNRECOVERABLE_ERROR_NEEDS_SIGNOUT;
#endif

  return {SYNC_ERROR, status_label_string_id, IDS_SYNC_RELOGIN_BUTTON,
          REAUTHENTICATE};
}

// Depending on the authentication state, returns labels to be used to display
// information about the sync status.
StatusLabels GetStatusForAuthError(const GoogleServiceAuthError& auth_error) {
  switch (auth_error.state()) {
    case GoogleServiceAuthError::NONE:
      NOTREACHED();
      break;
    case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
      return {SYNC_ERROR, IDS_SYNC_SERVICE_UNAVAILABLE,
              IDS_SETTINGS_EMPTY_STRING, NO_ACTION};
    case GoogleServiceAuthError::CONNECTION_FAILED:
      // Note that there is little the user can do if the server is not
      // reachable. Since attempting to re-connect is done automatically by
      // the Syncer, we do not show the (re)login link.
      return {SYNC_ERROR, IDS_SYNC_SERVER_IS_UNREACHABLE,
              IDS_SETTINGS_EMPTY_STRING, NO_ACTION};
    case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
    case GoogleServiceAuthError::SERVICE_ERROR:
    default:
      return {SYNC_ERROR, IDS_SYNC_RELOGIN_ERROR, IDS_SYNC_RELOGIN_BUTTON,
              REAUTHENTICATE};
  }

  NOTREACHED();
  return StatusLabels();
}

StatusLabels GetStatusLabelsImpl(const syncer::SyncService* service,
                                 bool is_user_signout_allowed,
                                 const GoogleServiceAuthError& auth_error) {
  DCHECK(service);

  if (!service->IsAuthenticatedAccountPrimary()) {
    return {PRE_SYNCED, IDS_SETTINGS_EMPTY_STRING, IDS_SETTINGS_EMPTY_STRING,
            NO_ACTION};
  }

  // If local Sync were enabled, then the SyncService shouldn't report having a
  // primary (or any) account.
  DCHECK(!service->IsLocalSyncEnabled());

  // First check if Chrome needs to be updated.
  if (service->RequiresClientUpgrade()) {
    return {SYNC_ERROR, IDS_SYNC_UPGRADE_CLIENT, IDS_SYNC_UPGRADE_CLIENT_BUTTON,
            UPGRADE_CLIENT};
  }

  // Then check for an unrecoverable error.
  if (service->HasUnrecoverableError()) {
    return GetStatusForUnrecoverableError(is_user_signout_allowed);
  }

  // Then check for an auth error.
  if (auth_error.state() != GoogleServiceAuthError::NONE) {
    return GetStatusForAuthError(auth_error);
  }

  // Check if Sync is disabled by policy.
  if (service->HasDisableReason(
          syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY)) {
    // TODO(crbug.com/911153): Is SYNCED correct for this case?
    return {SYNCED, IDS_SIGNED_IN_WITH_SYNC_DISABLED_BY_POLICY,
            IDS_SETTINGS_EMPTY_STRING, NO_ACTION};
  }

  // Check to see if sync has been disabled via the dashboard and needs to be
  // set up once again.
  if (!service->GetUserSettings()->IsSyncRequested()) {
    return {SYNC_ERROR, IDS_SIGNED_IN_WITH_SYNC_STOPPED_VIA_DASHBOARD,
            IDS_SETTINGS_EMPTY_STRING, NO_ACTION};
  }

  if (service->GetUserSettings()->IsFirstSetupComplete()) {
    // Check for a passphrase error.
    if (service->GetUserSettings()
            ->IsPassphraseRequiredForPreferredDataTypes()) {
      // TODO(mastiz): This should return PASSWORDS_ONLY_SYNC_ERROR if only
      // passwords are encrypted as per IsEncryptEverythingEnabled().
      return {SYNC_ERROR, IDS_SYNC_STATUS_NEEDS_PASSWORD,
              IDS_SYNC_STATUS_NEEDS_PASSWORD_BUTTON, ENTER_PASSPHRASE};
    }

    if (service->IsSyncFeatureActive() &&
        service->GetUserSettings()
            ->IsTrustedVaultKeyRequiredForPreferredDataTypes()) {
      return {service->GetUserSettings()->IsEncryptEverythingEnabled()
                  ? SYNC_ERROR
                  : PASSWORDS_ONLY_SYNC_ERROR,
              IDS_SETTINGS_EMPTY_STRING, IDS_SYNC_STATUS_NEEDS_KEYS_BUTTON,
              RETRIEVE_TRUSTED_VAULT_KEYS};
    }

    // At this point, there is no Sync error.
    if (service->IsSyncFeatureActive()) {
      return {SYNCED,
              service->GetUserSettings()->IsSyncEverythingEnabled()
                  ? IDS_SYNC_ACCOUNT_SYNCING
                  : IDS_SYNC_ACCOUNT_SYNCING_CUSTOM_DATA_TYPES,
              IDS_SETTINGS_EMPTY_STRING, NO_ACTION};
    } else {
      // Sync is still initializing.
      return {SYNCED, IDS_SETTINGS_EMPTY_STRING, IDS_SETTINGS_EMPTY_STRING,
              NO_ACTION};
    }
  }

  // If first setup is in progress, show an "in progress" message.
  if (service->IsSetupInProgress()) {
    return {PRE_SYNCED, IDS_SYNC_SETUP_IN_PROGRESS, IDS_SETTINGS_EMPTY_STRING,
            NO_ACTION};
  }

  // At this point we've ruled out all other cases - all that's left is a
  // missing Sync confirmation.
  DCHECK(ShouldRequestSyncConfirmation(service));
  return {SYNC_ERROR, IDS_SYNC_SETTINGS_NOT_CONFIRMED,
          IDS_SYNC_ERROR_USER_MENU_CONFIRM_SYNC_SETTINGS_BUTTON,
          CONFIRM_SYNC_SETTINGS};
}

void FocusWebContents(Browser* browser) {
  auto* const contents = browser->tab_strip_model()->GetActiveWebContents();
  if (contents)
    contents->Focus();
}

void OpenTabForSyncKeyRetrievalWithURL(Browser* browser, const GURL& url) {
  DCHECK(browser);
  FocusWebContents(browser);

  NavigateParams params(GetSingletonTabNavigateParams(browser, url));
  // Allow the window to close itself.
  params.created_with_opener = true;
  Navigate(&params);
}

// Returns true if the user has consented to browser sync-the-feature or
// Chrome OS sync.
bool HasUserOptedInToSync(const syncer::SyncUserSettings* settings) {
  if (settings->IsFirstSetupComplete())
    return true;
#if defined(OS_CHROMEOS)
  if (chromeos::features::IsSplitSettingsSyncEnabled() &&
      settings->IsOsSyncFeatureEnabled()) {
    return true;
  }
#endif  // defined(OS_CHROMEOS)
  return false;
}

}  // namespace

StatusLabels GetStatusLabels(syncer::SyncService* sync_service,
                             signin::IdentityManager* identity_manager,
                             bool is_user_signout_allowed) {
  if (!sync_service) {
    // This can happen if Sync is disabled via the command line.
    return {PRE_SYNCED, IDS_SETTINGS_EMPTY_STRING, IDS_SETTINGS_EMPTY_STRING,
            NO_ACTION};
  }
  DCHECK(identity_manager);
  CoreAccountInfo account_info = sync_service->GetAuthenticatedAccountInfo();
  GoogleServiceAuthError auth_error =
      identity_manager->GetErrorStateOfRefreshTokenForAccount(
          account_info.account_id);
  return GetStatusLabelsImpl(sync_service, is_user_signout_allowed, auth_error);
}

StatusLabels GetStatusLabels(Profile* profile) {
  DCHECK(profile);
  return GetStatusLabels(ProfileSyncServiceFactory::GetForProfile(profile),
                         IdentityManagerFactory::GetForProfile(profile),
                         signin_util::IsUserSignoutAllowedForProfile(profile));
}

MessageType GetStatus(Profile* profile) {
  return GetStatusLabels(profile).message_type;
}

AvatarSyncErrorType GetMessagesForAvatarSyncError(
    Profile* profile,
    int* content_string_id,
    int* button_string_id) {
  const syncer::SyncService* service =
      ProfileSyncServiceFactory::GetForProfile(profile);

  // If there is no SyncService (probably because sync is disabled from the
  // command line), then there's no error to show.
  if (!service)
    return NO_SYNC_ERROR;

  // The order or priority is going to be: 1. Unrecoverable errors.
  // 2. Auth errors. 3. Outdated client errors. 4. Passphrase errors.
  // Note that an unrecoverable error is sometimes caused by the Chrome client
  // being outdated; that case is handled separately below.
  if (service->HasUnrecoverableError() && !service->RequiresClientUpgrade()) {
    // Display different messages and buttons for managed accounts.
    if (!signin_util::IsUserSignoutAllowedForProfile(profile)) {
      // For a managed user, the user is directed to the signout
      // confirmation dialogue in the settings page.
      *content_string_id = IDS_SYNC_ERROR_USER_MENU_SIGNOUT_MESSAGE;
      *button_string_id = IDS_SYNC_ERROR_USER_MENU_SIGNOUT_BUTTON;
      return MANAGED_USER_UNRECOVERABLE_ERROR;
    }
    // For a non-managed user, we sign out on the user's behalf and prompt
    // the user to sign in again.
    *content_string_id = IDS_SYNC_ERROR_USER_MENU_SIGNIN_AGAIN_MESSAGE;
    *button_string_id = IDS_SYNC_ERROR_USER_MENU_SIGNIN_AGAIN_BUTTON;
    return UNRECOVERABLE_ERROR;
  }

  // Check for an auth error.
  CoreAccountInfo account_info = service->GetAuthenticatedAccountInfo();
  GoogleServiceAuthError auth_error =
      IdentityManagerFactory::GetForProfile(profile)
          ->GetErrorStateOfRefreshTokenForAccount(account_info.account_id);

  if (auth_error.state() != GoogleServiceAuthError::State::NONE) {
    // The user can reauth to resolve the signin error.
    *content_string_id = IDS_SYNC_ERROR_USER_MENU_SIGNIN_MESSAGE;
    *button_string_id = IDS_SYNC_ERROR_USER_MENU_SIGNIN_BUTTON;
    return AUTH_ERROR;
  }

  // Check if the Chrome client needs to be updated.
  if (service->RequiresClientUpgrade()) {
    *content_string_id = IDS_SYNC_ERROR_USER_MENU_UPGRADE_MESSAGE;
    *button_string_id = IDS_SYNC_ERROR_USER_MENU_UPGRADE_BUTTON;
    return UPGRADE_CLIENT_ERROR;
  }

  // Check for a sync passphrase error.
  if (ShouldShowPassphraseError(service)) {
    *content_string_id = IDS_SYNC_ERROR_USER_MENU_PASSPHRASE_MESSAGE;
    *button_string_id = IDS_SYNC_ERROR_USER_MENU_PASSPHRASE_BUTTON;
    return PASSPHRASE_ERROR;
  }

  // Check for a sync confirmation error.
  if (ShouldRequestSyncConfirmation(service)) {
    *content_string_id = IDS_SYNC_SETTINGS_NOT_CONFIRMED;
    *button_string_id = IDS_SYNC_ERROR_USER_MENU_CONFIRM_SYNC_SETTINGS_BUTTON;
    return SETTINGS_UNCONFIRMED_ERROR;
  }

  // Check for sync encryption keys missing.
  if (ShouldShowSyncKeysMissingError(service)) {
    *content_string_id = IDS_SYNC_ERROR_USER_MENU_RETRIEVE_KEYS_MESSAGE;
    *button_string_id = IDS_SYNC_ERROR_USER_MENU_RETRIEVE_KEYS_BUTTON;
    return service->GetUserSettings()->IsEncryptEverythingEnabled()
               ? TRUSTED_VAULT_KEY_MISSING_FOR_EVERYTHING_ERROR
               : TRUSTED_VAULT_KEY_MISSING_FOR_PASSWORDS_ERROR;
  }

  // There is no error.
  return NO_SYNC_ERROR;
}

bool ShouldRequestSyncConfirmation(const syncer::SyncService* service) {
  // This method mostly handles two situations:
  // 1. The initial Sync setup was aborted without actually disabling Sync
  //    again. That generally shouldn't happen, but it might if Chrome crashed
  //    while the setup was ongoing, or due to past bugs in the setup flow.
  // 2. Sync was reset from the dashboard. That usually signs out the user too,
  //    but it doesn't on ChromeOS, or for managed (enterprise) accounts where
  //    sign-out is prohibited.
  // Note that we do not check IsSyncRequested() here: In situation 1 it'd
  // usually be true, but in situation 2 it's false. Note that while there is a
  // primary account, IsSyncRequested() can only be false if Sync was reset from
  // the dashboard.
  return !service->IsLocalSyncEnabled() &&
         service->IsAuthenticatedAccountPrimary() &&
         !service->IsSetupInProgress() &&
         !service->GetUserSettings()->IsFirstSetupComplete();
}

bool ShouldShowPassphraseError(const syncer::SyncService* service) {
  const syncer::SyncUserSettings* settings = service->GetUserSettings();
  return HasUserOptedInToSync(settings) &&
         settings->IsPassphraseRequiredForPreferredDataTypes();
}

bool ShouldShowSyncKeysMissingError(const syncer::SyncService* service) {
  const syncer::SyncUserSettings* settings = service->GetUserSettings();
  return HasUserOptedInToSync(settings) &&
         settings->IsTrustedVaultKeyRequiredForPreferredDataTypes();
}

void OpenTabForSyncKeyRetrieval(Browser* browser) {
  const GURL continue_url =
      GURL(UIThreadSearchTermsData().GoogleBaseURLValue());
  GURL retrieval_url = GaiaUrls::GetInstance()->signin_chrome_sync_keys_url();
  if (continue_url.is_valid()) {
    retrieval_url = net::AppendQueryParameter(retrieval_url, "continue",
                                              continue_url.spec());
  }
  OpenTabForSyncKeyRetrievalWithURL(browser, retrieval_url);
}

void OpenTabForSyncKeyRetrievalWithURLForTesting(Browser* browser,
                                                 const GURL& url) {
  OpenTabForSyncKeyRetrievalWithURL(browser, url);
}

}  // namespace sync_ui_util
