// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// clang-format off
import '//resources/cr_components/localized_link/localized_link.js';
import '//resources/cr_elements/cr_radio_button/cr_radio_button.js';
import '//resources/cr_elements/cr_radio_group/cr_radio_group.js';
import '//resources/cr_elements/cr_toggle/cr_toggle.js';
import '//resources/cr_elements/cr_shared_style.css.js';
import '//resources/cr_elements/cr_shared_vars.css.js';
import '//resources/cr_elements/policy/cr_policy_indicator.js';
import '../settings_shared.css.js';
import { WebUiListenerMixin } from '//resources/cr_elements/web_ui_listener_mixin.js';
import { assert } from '//resources/js/assert.js';
import { PolymerElement } from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import { shouldShowSyncTogglesForStatusAction, SignedInState, StatusAction, SyncBrowserProxyImpl, syncPrefsIndividualDataTypes, UserSelectableType } from '/shared/settings/people_page/sync_browser_proxy.js';
import { routes } from '../route.js';
import { Router } from '../router.js';
import { getTemplate } from './sync_controls.html.js';
import { loadTimeData } from '../i18n_setup.js';
import { RouteObserverMixin } from '../router.js';
import { PluralStringProxyImpl } from 'chrome://resources/js/plural_string_proxy.js';
import { sanitizeInnerHtml } from 'chrome://resources/js/parse_html_subset.js';
import { BatchUploadPromoProxyImpl } from 'chrome://resources/js/batch_upload_promo/batch_upload_promo_proxy.js';
// clang-format on
/**
 * Names of the radio buttons which allow the user to choose their data sync
 * mechanism.
 */
var RadioButtonNames;
(function (RadioButtonNames) {
    RadioButtonNames["SYNC_EVERYTHING"] = "sync-everything";
    RadioButtonNames["CUSTOMIZE_SYNC"] = "customize-sync";
})(RadioButtonNames || (RadioButtonNames = {}));
/**
 * @fileoverview
 * 'settings-sync-controls' contains all sync data type controls.
 */
const SettingsSyncControlsElementBase = RouteObserverMixin(WebUiListenerMixin(PolymerElement));
export class SettingsSyncControlsElement extends SettingsSyncControlsElementBase {
    static get is() {
        return 'settings-sync-controls';
    }
    static get template() {
        return getTemplate();
    }
    static get properties() {
        return {
            hidden: {
                type: Boolean,
                value: false,
                computed: 'syncControlsHidden_(' +
                    'syncStatus.signedIn, syncStatus.disabled, ' +
                    'syncStatus.hasError, isAccountSettingsPage_, ' +
                    'syncPrefs.localSyncEnabled)',
                reflectToAttribute: true,
            },
            /**
             * The current sync preferences, supplied by SyncBrowserProxy.
             */
            syncPrefs: Object,
            /**
             * The current sync status, supplied by the parent.
             */
            syncStatus: {
                type: Object,
                observer: 'syncStatusChanged_',
            },
            /** Expose UserSelectableType enum to HTML bindings. */
            UserSelectableTypeEnum_: {
                type: Object,
                value: UserSelectableType,
            },
            /**
             * Communicates to the user that the toggles are disabled because sync is
             * disabled by their administrator.
             */
            showSyncDisabledInformation: {
                type: Boolean,
                value: false,
                computed: 'computeShowSyncDisabledInformation_(syncStatus.disabled, ' +
                    'isAccountSettingsPage_)',
                reflectToAttribute: true,
            },
            /**
             * Returns whether this element is currently displayed on the account
             * settings page. True when `replaceSyncPromosWithSignInPromos` is enabled
             * and the user navigates to the account page.
             */
            isAccountSettingsPage_: {
                type: Boolean,
                value: false,
            },
            batchUploadPromoHTML_: {
                type: String,
                value: window.trustedTypes.emptyHTML,
                observer: 'attachOpenBatchUploadLinkClick_',
            },
        };
    }
    syncBrowserProxy_ = SyncBrowserProxyImpl.getInstance();
    cachedSyncPrefs_;
    constructor() {
        super();
        /**
         * Caches the individually selected synced data types. This is used to
         * be able to restore the selections after checking and unchecking Sync All.
         */
        this.cachedSyncPrefs_ = null;
    }
    connectedCallback() {
        super.connectedCallback();
        this.addWebUiListener('sync-prefs-changed', this.handleSyncPrefsChanged_.bind(this));
        const showBatchUploadPromo = loadTimeData.valueExists('unoPhase2FollowUp') ?
            loadTimeData.getBoolean('unoPhase2FollowUp') :
            loadTimeData.getBoolean('replaceSyncPromosWithSignInPromos');
        if (showBatchUploadPromo) {
            BatchUploadPromoProxyImpl.getInstance()
                .callbackRouter.onLocalDataCountChanged.addListener((localDataCount) => {
                this.batchUploadPromoLocalDataCountChanged_(localDataCount);
            });
            BatchUploadPromoProxyImpl.getInstance()
                .handler.getBatchUploadPromoLocalDataCount()
                .then(({ localDataCount }) => {
                this.batchUploadPromoLocalDataCountChanged_(localDataCount);
            });
        }
        const router = Router.getInstance();
        const currentRoute = router.getCurrentRoute();
        if (currentRoute === routes.SYNC_ADVANCED) {
            this.syncBrowserProxy_.didNavigateToSyncPage();
        }
        if (loadTimeData.getBoolean('replaceSyncPromosWithSignInPromos') &&
            currentRoute === routes.ACCOUNT) {
            this.isAccountSettingsPage_ = true;
            this.syncBrowserProxy_.didNavigateToAccountSettingsPage();
        }
    }
    /**
     * Handler for when the sync preferences are updated.
     */
    handleSyncPrefsChanged_(syncPrefs) {
        this.syncPrefs = syncPrefs;
    }
    async batchUploadPromoLocalDataCountChanged_(localDataCount) {
        const showBatchUploadPromo = loadTimeData.valueExists('unoPhase2FollowUp') ?
            loadTimeData.getBoolean('unoPhase2FollowUp') :
            loadTimeData.getBoolean('replaceSyncPromosWithSignInPromos');
        if (!showBatchUploadPromo) {
            return;
        }
        if (localDataCount === 0) {
            this.batchUploadPromoHTML_ = window.trustedTypes.emptyHTML;
            return;
        }
        const batchUploadPromoString = await PluralStringProxyImpl.getInstance().getPluralString('batchUploadPromoLabel', localDataCount);
        // We need the HTML representation instead of the string since the string
        // holds a link.
        this.batchUploadPromoHTML_ =
            sanitizeInnerHtml(batchUploadPromoString, { tags: ['a'], attrs: ['id'] });
    }
    shouldShowBatchUploadPromo_() {
        const showBatchUploadPromo = loadTimeData.valueExists('unoPhase2FollowUp') ?
            loadTimeData.getBoolean('unoPhase2FollowUp') :
            loadTimeData.getBoolean('replaceSyncPromosWithSignInPromos');
        if (!showBatchUploadPromo) {
            return false;
        }
        if (!this.isAccountSettingsPage_) {
            return false;
        }
        return this.batchUploadPromoHTML_ !== window.trustedTypes.emptyHTML;
    }
    /** Attach the click action and aria label to the batch upload promo link. */
    attachOpenBatchUploadLinkClick_() {
        const element = this.shadowRoot?.querySelector(`#openBatchUploadLink`);
        if (element !== null && element !== undefined) {
            element.addEventListener('click', (me) => {
                this.onPromoClicked_(me);
            });
            // Since there is a link for the batch upload, we can also be sure that
            // the containing element exists.
            const batchUploadElement = this.shadowRoot?.querySelector(`#batchUploadPromo`);
            element.setAttribute('aria-label', batchUploadElement.textContent);
        }
    }
    onPromoClicked_(event) {
        assert(this.shouldShowBatchUploadPromo_());
        // Prevent navigation to href='#' and open the batch upload dialog instead.
        event.preventDefault();
        BatchUploadPromoProxyImpl.getInstance().handler.onBatchUploadPromoClicked();
    }
    /**
     * @return Computed binding returning the selected sync data radio button.
     */
    selectedSyncDataRadio_() {
        return this.syncPrefs.syncAllDataTypes ? RadioButtonNames.SYNC_EVERYTHING :
            RadioButtonNames.CUSTOMIZE_SYNC;
    }
    /**
     * Called when the sync data radio button selection changes.
     */
    onSyncDataRadioSelectionChanged_(event) {
        const syncAllDataTypes = event.detail.value === RadioButtonNames.SYNC_EVERYTHING;
        const previous = this.syncPrefs.syncAllDataTypes;
        if (previous !== syncAllDataTypes) {
            this.set('syncPrefs.syncAllDataTypes', syncAllDataTypes);
            this.handleSyncAllDataTypesChanged_(syncAllDataTypes);
        }
    }
    currentRouteChanged(newRoute, oldRoute) {
        if (!loadTimeData.getBoolean('replaceSyncPromosWithSignInPromos')) {
            return;
        }
        this.isAccountSettingsPage_ = newRoute === routes.ACCOUNT;
        if (this.isAccountSettingsPage_ && oldRoute !== routes.ACCOUNT) {
            this.syncBrowserProxy_.didNavigateToAccountSettingsPage();
        }
    }
    mergedHistoryTabsToggleDisabled_(syncStatus, tabsManaged, historyManaged) {
        return !syncStatus || syncStatus.disabled || !this.syncPrefs ||
            (tabsManaged && historyManaged);
    }
    mergedHistoryTabsTogglePolicyIndicatorShown_(syncStatus, tabsManaged, historyManaged) {
        return !!syncStatus && !syncStatus.disabled && tabsManaged &&
            historyManaged;
    }
    mergedHistoryTabsToggleChecked_(syncPrefs) {
        return syncPrefs.typedUrlsSynced || syncPrefs.tabsSynced ||
            syncPrefs.savedTabGroupsSynced;
    }
    onMergedHistoryTabsToggleChanged_(event) {
        assert(this.isAccountSettingsPage_);
        const toggle = event.target;
        this.syncBrowserProxy_.setSyncDatatype(UserSelectableType.HISTORY, toggle.checked);
        this.syncBrowserProxy_.setSyncDatatype(UserSelectableType.TABS, toggle.checked);
        this.syncBrowserProxy_.setSyncDatatype(UserSelectableType.SAVED_TAB_GROUPS, toggle.checked);
    }
    handleSyncAllDataTypesChanged_(syncAllDataTypes) {
        if (syncAllDataTypes) {
            this.set('syncPrefs.syncAllDataTypes', true);
            // Cache the previously selected preference before checking every box.
            this.cachedSyncPrefs_ = {};
            for (const dataType of syncPrefsIndividualDataTypes) {
                // These are all booleans, so this shallow copy is sufficient.
                this.cachedSyncPrefs_[dataType] =
                    this.syncPrefs[dataType];
                this.set(['syncPrefs', dataType], true);
            }
        }
        else if (this.cachedSyncPrefs_) {
            // Restore the previously selected preference.
            for (const dataType of syncPrefsIndividualDataTypes) {
                this.set(['syncPrefs', dataType], this.cachedSyncPrefs_[dataType]);
            }
        }
        chrome.metricsPrivate.recordUserAction(syncAllDataTypes ? 'Sync_SyncEverything' : 'Sync_CustomizeSync');
        this.onSingleSyncDataTypeChanged_();
    }
    /**
     * Handler for when any sync data type checkbox is changed.
     */
    onSingleSyncDataTypeChanged_(_event) {
        if (this.isAccountSettingsPage_) {
            assert(_event);
            const toggle = _event?.target;
            const type = Number(toggle.dataset['type']);
            assert(!isNaN(type));
            this.syncBrowserProxy_.setSyncDatatype(type, toggle.checked);
            return;
        }
        assert(this.syncPrefs);
        this.syncBrowserProxy_.setSyncDatatypes(this.syncPrefs);
    }
    disableTypeCheckBox_(syncStatus, syncAllDataTypes, dataTypeManaged) {
        if (!syncStatus) {
            return true;
        }
        if (dataTypeManaged) {
            return true;
        }
        if (syncStatus.signedInState === SignedInState.SYNCING) {
            return syncAllDataTypes;
        }
        // Toggles should be disabled on the account settings page if sync is
        // disabled, or if the sync prefs are undefined, which is the case e.g.
        // right after startup.
        return syncStatus.disabled || !this.syncPrefs;
    }
    showPolicyIndicator_(syncStatus, dataTypeManaged) {
        // Do not show the indicator on the account settings page if sync is
        // disabled, as this would make the UI look too crowded and the toggles are
        // already deactivated. In the sync settings page, the toggles are hidden if
        // sync is disabled (see `syncControlsHidden_()`), so we do not need to
        // specify whether we show the indicator or not.
        if (this.isAccountSettingsPage_) {
            return !!syncStatus && !syncStatus.disabled && dataTypeManaged;
        }
        return dataTypeManaged;
    }
    computeShowSyncDisabledInformation_(syncDisabled) {
        return this.isAccountSettingsPage_ && syncDisabled;
    }
    // 
    syncStatusChanged_() {
        const router = Router.getInstance();
        if (router.getCurrentRoute() === routes.SYNC_ADVANCED &&
            this.syncControlsHidden_()) {
            // Try to navigate the user to the account page, where they can find the
            // toggles. If the page does not exist, they will be redirected to the
            // people settings page from there.
            if (loadTimeData.getBoolean('replaceSyncPromosWithSignInPromos')) {
                router.navigateTo(routes.ACCOUNT);
                return;
            }
            router.navigateTo(routes.SYNC);
        }
    }
    /**
     * @return Whether the sync controls are hidden.
     */
    syncControlsHidden_() {
        if (!this.syncStatus) {
            // Show sync controls by default.
            return false;
        }
        // The account page is not shown when the user is not signed in or if they
        // are in sign in pending state, so we don't need to check for the signed in
        // state here. However, the controls should be hidden if there is a generic
        // sync error (e.g. a passphrase is required), or if the user has local sync
        // enabled.
        if (this.isAccountSettingsPage_) {
            return (!!this.syncStatus.hasError &&
                this.syncStatus.statusAction !== StatusAction.UPGRADE_CLIENT &&
                this.syncStatus.statusAction !==
                    StatusAction.SHOW_BOOKMARKS_LIMIT_HELP_ARTICLE) ||
                (!!this.syncPrefs && this.syncPrefs.localSyncEnabled);
        }
        if (this.syncStatus.signedInState !== SignedInState.SYNCING ||
            this.syncStatus.disabled) {
            return true;
        }
        return !!this.syncStatus.hasError &&
            !shouldShowSyncTogglesForStatusAction(this.syncStatus.statusAction);
    }
}
customElements.define(SettingsSyncControlsElement.is, SettingsSyncControlsElement);
