// 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.

package org.chromium.chrome.browser.autofill;

import android.content.Context;
import android.text.Editable;
import android.text.TextUtils;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.TextView.BufferType;

import androidx.core.text.TextUtilsCompat;
import androidx.core.view.ViewCompat;

import org.chromium.chrome.R;
import org.chromium.ui.modaldialog.DialogDismissalCause;
import org.chromium.ui.modaldialog.ModalDialogProperties;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.text.EmptyTextWatcher;

import java.util.Locale;

/**
 * Prompt that asks users to confirm user's name before saving card to Google.
 */
public class AutofillNameFixFlowPrompt
        extends AutofillSaveCardPromptBase implements EmptyTextWatcher {
    /**
     * An interface to handle the interaction with
     * an AutofillNameFixFlowPrompt object.
     */
    public interface AutofillNameFixFlowPromptDelegate extends AutofillSaveCardPromptBaseDelegate {
        /**
         * Called when user accepted/confirmed the prompt.
         *
         * @param name Card holder name.
         */
        void onUserAcceptCardholderName(String name);
    }

    /**
     * Create a dialog prompt for the use of infobar. This prompt does not include legal lines.
     *
     * @param context The current context.
     * @param delegate A {@link AutofillNameFixFlowPromptDelegate} to handle events.
     * @param inferredName Name inferred from the account. Empty string for user to fill in.
     * @param title Title of the prompt.
     * @param drawableId Drawable id on the title.
     * @param confirmButtonLabel Label for the confirm button.
     * @return A {@link AutofillNameFixFlowPrompt} to confirm name.
     */
    public static AutofillNameFixFlowPrompt createAsInfobarFixFlowPrompt(Context context,
            AutofillNameFixFlowPromptDelegate delegate, String inferredName, String title,
            int drawableId, String confirmButtonLabel) {
        return new AutofillNameFixFlowPrompt(
                context, delegate, inferredName, title, drawableId, confirmButtonLabel, false);
    }

    private final AutofillNameFixFlowPromptDelegate mDelegate;

    private final EditText mUserNameInput;
    private final ImageView mNameFixFlowTooltipIcon;
    private PopupWindow mNameFixFlowTooltipPopup;

    /**
     * Fix flow prompt to confirm user name before saving the card to Google.
     */
    private AutofillNameFixFlowPrompt(Context context, AutofillNameFixFlowPromptDelegate delegate,
            String inferredName, String title, int drawableId, String confirmButtonLabel,
            boolean filledConfirmButton) {
        super(context, delegate, R.layout.autofill_name_fixflow, title, drawableId,
                confirmButtonLabel, filledConfirmButton);
        mDelegate = delegate;
        // Dialog of infobar doesn't show any details of the cc.
        mDialogView.findViewById(R.id.cc_details).setVisibility(View.GONE);
        mUserNameInput = (EditText) mDialogView.findViewById(R.id.cc_name_edit);
        mUserNameInput.setText(inferredName, BufferType.EDITABLE);
        mNameFixFlowTooltipIcon = (ImageView) mDialogView.findViewById(R.id.cc_name_tooltip_icon);
        mDialogModel.set(ModalDialogProperties.POSITIVE_BUTTON_DISABLED, inferredName.isEmpty());

        // Do not show tooltip if inferred name is empty.
        if (TextUtils.isEmpty(inferredName)) {
            mNameFixFlowTooltipIcon.setVisibility(View.GONE);
        } else {
            mNameFixFlowTooltipIcon.setOnClickListener((view) -> onTooltipIconClicked());
        }

        // Hitting the "submit" button on the software keyboard should submit, unless the name field
        // is empty.
        mUserNameInput.setOnEditorActionListener((view, actionId, event) -> {
            if (actionId == EditorInfo.IME_ACTION_DONE) {
                if (mUserNameInput.getText().toString().trim().length() != 0) {
                    onClick(mDialogModel, ModalDialogProperties.ButtonType.POSITIVE);
                }
                return true;
            }
            return false;
        });
        mUserNameInput.addTextChangedListener(this);
    }

    @Override
    public void afterTextChanged(Editable s) {
        mDialogModel.set(ModalDialogProperties.POSITIVE_BUTTON_DISABLED,
                mUserNameInput.getText().toString().trim().isEmpty());
    }

    /**
     * Handle tooltip icon clicked. If tooltip is already opened, don't show another. Otherwise
     * create a new one.
     */
    private void onTooltipIconClicked() {
        if (mNameFixFlowTooltipPopup != null) return;

        mNameFixFlowTooltipPopup = new PopupWindow(mContext);
        Runnable dismissAction = () -> {
            mNameFixFlowTooltipPopup = null;
        };
        boolean isLeftToRight = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault())
                == ViewCompat.LAYOUT_DIRECTION_LTR;
        AutofillUiUtils.showTooltip(mContext, mNameFixFlowTooltipPopup,
                R.string.autofill_save_card_prompt_cardholder_name_tooltip,
                new AutofillUiUtils.OffsetProvider() {
                    @Override
                    public int getXOffset(TextView textView) {
                        int xOffset =
                                mNameFixFlowTooltipIcon.getLeft() - textView.getMeasuredWidth();
                        return Math.max(0, xOffset);
                    }

                    @Override
                    public int getYOffset(TextView textView) {
                        return 0;
                    }
                },
                // If the layout is right to left then anchor on the edit text field else anchor on
                // the tooltip icon, which would be on the left.
                isLeftToRight ? mUserNameInput : mNameFixFlowTooltipIcon, dismissAction);
    }

    @Override
    public void onClick(PropertyModel model, int buttonType) {
        if (buttonType == ModalDialogProperties.ButtonType.POSITIVE) {
            mDelegate.onUserAcceptCardholderName(mUserNameInput.getText().toString());
            mModalDialogManager.dismissDialog(model, DialogDismissalCause.POSITIVE_BUTTON_CLICKED);
        } else if (buttonType == ModalDialogProperties.ButtonType.NEGATIVE) {
            mModalDialogManager.dismissDialog(model, DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
        }
    }

    @Override
    public void onDismiss(PropertyModel model, int dismissalCause) {
        // Do not call onUserDismiss if dialog was dismissed either because the user
        // accepted to save the card or was dismissed by native code.
        if (dismissalCause == DialogDismissalCause.NEGATIVE_BUTTON_CLICKED) {
            mDelegate.onUserDismiss();
        }
        // Call whenever the dialog is dismissed.
        mDelegate.onPromptDismissed();
    }
}
