// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.infobar;

import android.os.Bundle;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;

import org.chromium.base.annotations.CalledByNative;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
import org.chromium.components.browser_ui.settings.SettingsLauncher;
import org.chromium.components.browser_ui.site_settings.SingleCategorySettings;
import org.chromium.components.browser_ui.site_settings.SiteSettingsCategory;
import org.chromium.components.infobars.ConfirmInfoBar;
import org.chromium.components.infobars.InfoBarCompactLayout;
import org.chromium.components.infobars.InfoBarLayout;
import org.chromium.components.permissions.AndroidPermissionRequester;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.text.NoUnderlineClickableSpan;

/**
 * An infobar used for prompting the user to grant a web API permission.
 */
public class PermissionInfoBar
        extends ConfirmInfoBar implements AndroidPermissionRequester.RequestDelegate {
    /** The window which this infobar will be displayed upon. */
    protected final WindowAndroid mWindow;

    /** The content settings types corresponding to the permission requested in this infobar. */
    protected int[] mContentSettingsTypes;

    /** Whether the secondary button should act as a "Manage" button to open settings. */
    protected boolean mSecondaryButtonShouldOpenSettings;

    /**
     * Whether the last clicked button opened settings, requiring the dialog to stay interactive
     * when the user switches back.
     */
    protected boolean mLastClickOpenedSettings;

    /** Whether the infobar should be shown as a compact mini-infobar or a classic expanded one. */
    private boolean mIsExpanded;

    /** The text of the link shown in the compact state. */
    private String mCompactLinkText;

    /** The message text in the compact state. */
    private String mCompactMessage;

    /** The secondary text shown below the message in the expanded state. */
    private String mDescription;

    /** The text of the `Learn more` link shown in the expanded state after the description. */
    private String mLearnMoreLinkText;

    protected PermissionInfoBar(WindowAndroid window, int[] contentSettingsTypes,
            int iconDrawableId, String compactMessage, String compactLinkText, String message,
            String description, String learnMoreLinktext, String primaryButtonText,
            String secondaryButtonText, boolean secondaryButtonShouldOpenSettings) {
        super(iconDrawableId, R.color.infobar_icon_drawable_color, null /* iconBitmap */, message,
                null /* linkText */, primaryButtonText, secondaryButtonText);
        mWindow = window;
        mContentSettingsTypes = contentSettingsTypes;
        mSecondaryButtonShouldOpenSettings = secondaryButtonShouldOpenSettings;
        mLastClickOpenedSettings = false;
        mIsExpanded = false;
        mCompactLinkText = compactLinkText;
        mCompactMessage = compactMessage;
        mDescription = description;
        mLearnMoreLinkText = learnMoreLinktext;
    }

    @Override
    protected boolean usesCompactLayout() {
        return !mIsExpanded;
    }

    @Override
    protected void createCompactLayoutContent(InfoBarCompactLayout layout) {
        new InfoBarCompactLayout.MessageBuilder(layout)
                .withText(mCompactMessage)
                .withLink(mCompactLinkText, view -> onLinkClicked())
                .buildAndInsert();
    }

    @Override
    public boolean areControlsEnabled() {
        // The controls need to be enbled after the user clicks `manage` since they will return to
        // the page and the infobar still needs to be kept active.
        return super.areControlsEnabled() || mLastClickOpenedSettings;
    }

    @Override
    public void onButtonClicked(final boolean isPrimaryButton) {
        mLastClickOpenedSettings = false;
        if (getContext() == null) {
            onButtonClickedInternal(isPrimaryButton);
            return;
        }

        if (isPrimaryButton) {
            // requestAndroidPermissions will call back into this class to finalize the action if it
            // returns true.
            if (AndroidPermissionRequester.requestAndroidPermissions(
                        mWindow, mContentSettingsTypes.clone(), this)) {
                return;
            }
        } else if (mSecondaryButtonShouldOpenSettings) {
            launchNotificationsSettingsPage();
        }

        onButtonClickedInternal(isPrimaryButton);
    }

    @Override
    public void onLinkClicked() {
        if (!mIsExpanded) {
            mIsExpanded = true;
            replaceView(createView());
        }

        super.onLinkClicked();
    }

    @Override
    public void createContent(InfoBarLayout layout) {
        super.createContent(layout);

        SpannableStringBuilder descriptionMessage = new SpannableStringBuilder(mDescription);
        if (mLearnMoreLinkText != null && !mLearnMoreLinkText.isEmpty()) {
            SpannableString link = new SpannableString(mLearnMoreLinkText);
            link.setSpan(new NoUnderlineClickableSpan(layout.getContext(), view -> onLinkClicked()),
                    0, link.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
            descriptionMessage.append(" ").append(link);
        }
        layout.getMessageLayout().addDescription(descriptionMessage);
    }

    @Override
    public void onAndroidPermissionAccepted() {
        onButtonClickedInternal(true);
    }

    @Override
    public void onAndroidPermissionCanceled() {
        onCloseButtonClicked();
    }

    private void onButtonClickedInternal(boolean isPrimaryButton) {
        super.onButtonClicked(isPrimaryButton);
    }

    private void launchNotificationsSettingsPage() {
        mLastClickOpenedSettings = true;
        Bundle fragmentArguments = new Bundle();
        fragmentArguments.putString(SingleCategorySettings.EXTRA_CATEGORY,
                SiteSettingsCategory.preferenceKey(SiteSettingsCategory.Type.NOTIFICATIONS));
        SettingsLauncher settingsLauncher = new SettingsLauncherImpl();
        settingsLauncher.launchSettingsActivity(
                getContext(), SingleCategorySettings.class, fragmentArguments);
    }

    /**
     * Creates and begins the process for showing a PermissionInfoBar.
     * @param window                The window this infobar will be displayed upon.
     * @param contentSettingsTypes  The list of ContentSettingTypes being requested by this infobar.
     * @param iconId                ID corresponding to the icon that will be shown for the infobar.
     * @param compactMessage        Message to show in the compact state.
     * @param compactLinkText       Text of link displayed right to the message in compact state.
     * @param message               Primary message in the extended state.
     * @param description           Secondary message (description) in the expanded state.
     * @param learnMoreLinkText     String to display on the `Learn more` link.
     * @param primaryButtonText     String to display on the primary button.
     * @param secondaryButtonText   String to display on the secondary button.
     * @param secondaryButtonShouldOpenSettings  Whether the secondary button should open site
     *         settings.
     */
    @CalledByNative
    private static PermissionInfoBar create(WindowAndroid window, int[] contentSettingsTypes,
            int iconId, String compactMessage, String compactLinkText, String message,
            String description, String learnMoreLinkText, String primaryButtonText,
            String secondaryButtonText, boolean secondaryButtonShouldOpenSettings) {
        PermissionInfoBar infoBar = new PermissionInfoBar(window, contentSettingsTypes, iconId,
                compactMessage, compactLinkText, message, description, learnMoreLinkText,
                primaryButtonText, secondaryButtonText, secondaryButtonShouldOpenSettings);

        return infoBar;
    }
}
