/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.tv.settings.autofill;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
import android.text.Html;
import android.widget.Button;

import androidx.annotation.Keep;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;

import com.android.settingslib.applications.DefaultAppInfo;
import com.android.tv.settings.R;
import com.android.tv.settings.RadioPreference;
import com.android.tv.settings.SettingsPreferenceFragment;

import java.util.List;

/**
 * Picker Fragment to select Autofill service
 */
@Keep
public class AutofillPickerFragment extends SettingsPreferenceFragment {

    private static final String AUTOFILL_SERVICE_RADIO_GROUP = "autofill_service_group";

    @VisibleForTesting
    static final String KEY_FOR_NONE = "_none_";

    private static final int FINISH_ACTIVITY_DELAY = 300;

    private PackageManager mPm;

    private final Handler mHandler = new Handler();

    /**
     * Set when the fragment is implementing ACTION_REQUEST_SET_AUTOFILL_SERVICE.
     */
    private DialogInterface.OnClickListener mCancelListener;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final Activity activity = getActivity();
        if (activity != null && activity.getIntent()
                .getStringExtra(AutofillPickerActivity.EXTRA_PACKAGE_NAME) != null) {
            mCancelListener = (d, w) -> {
                activity.setResult(Activity.RESULT_CANCELED);
                activity.finish();
            };
        }
    }

    /**
     * @return new AutofillPickerFragment instance
     */
    public static AutofillPickerFragment newInstance() {
        return new AutofillPickerFragment();
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mPm = context.getPackageManager();
    }

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        setPreferencesFromResource(R.xml.autofill_picker, null);
        final PreferenceScreen screen = getPreferenceScreen();
        bind(screen, savedInstanceState == null);
        setPreferenceScreen(screen);
    }

    @VisibleForTesting
    void bind(PreferenceScreen screen, boolean scrollToSelection) {
        Context context = getContext();

        List<DefaultAppInfo> candidates = AutofillHelper.getAutofillCandidates(context,
                mPm, UserHandle.myUserId());
        DefaultAppInfo current = AutofillHelper.getCurrentAutofill(context, candidates);

        RadioPreference activePref = null;
        for (final DefaultAppInfo appInfo : candidates) {
            final RadioPreference radioPreference = new RadioPreference(context);
            radioPreference.setKey(appInfo.getKey());
            radioPreference.setPersistent(false);
            radioPreference.setTitle(appInfo.loadLabel());
            radioPreference.setRadioGroup(AUTOFILL_SERVICE_RADIO_GROUP);
            radioPreference.setLayoutResource(R.layout.preference_reversed_widget);

            if (current == appInfo) {
                radioPreference.setChecked(true);
                activePref = radioPreference;
            }
            screen.addPreference(radioPreference);
        }
        if (activePref == null) {
            // select the none
            activePref = ((RadioPreference) screen.findPreference(KEY_FOR_NONE));
            activePref.setChecked(true);
        }

        if (activePref != null && scrollToSelection) {
            scrollToPreference(activePref);
        }
    }

    @Override
    public boolean onPreferenceTreeClick(Preference preference) {
        if (preference instanceof RadioPreference) {

            final Context context = getContext();
            List<DefaultAppInfo> candidates = AutofillHelper.getAutofillCandidates(context,
                    mPm, UserHandle.myUserId());
            final DefaultAppInfo current = AutofillHelper.getCurrentAutofill(context,
                    candidates);
            final String currentKey = current != null ? current.getKey() : KEY_FOR_NONE;

            final RadioPreference newPref = (RadioPreference) preference;
            final String newKey = newPref.getKey();
            final boolean clickOnCurrent = currentKey.equals(newKey);

            if (!clickOnCurrent && !KEY_FOR_NONE.equals(newKey)) {
                // Undo checked state change and wait dialog to confirm click
                RadioPreference currentPref = (RadioPreference) findPreference(currentKey);
                currentPref.setChecked(true);
                currentPref.clearOtherRadioPreferences(getPreferenceScreen());
                CharSequence confirmationMessage = Html.fromHtml(getContext().getString(
                        R.string.autofill_confirmation_message,
                        Html.escapeHtml(newPref.getTitle())));
                displayAlert(confirmationMessage, (dialog, which) -> {
                    RadioPreference pref = (RadioPreference) findPreference(newKey);
                    if (pref != null) {
                        pref.setChecked(true);
                        pref.clearOtherRadioPreferences(getPreferenceScreen());
                        setAutofillService(newKey);
                    }
                });
            } else {
                // Either clicked on already checked or click on "none": just close the fragment
                newPref.setChecked(true);
                newPref.clearOtherRadioPreferences(getPreferenceScreen());
                setAutofillService(newKey);
            }
        }
        return true;
    }

    private void setAutofillService(String key) {
        AutofillHelper.setCurrentAutofill(getContext(), key);
        // Check if activity was launched from Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE
        // intent, and set proper result if so...
        final Activity activity = getActivity();
        if (activity != null) {
            final String packageName = activity.getIntent()
                    .getStringExtra(AutofillPickerActivity.EXTRA_PACKAGE_NAME);
            if (packageName != null) {
                ComponentName componentName = ComponentName.unflattenFromString(key);
                final int result = componentName != null
                        && componentName.getPackageName().equals(packageName)
                        ? Activity.RESULT_OK : Activity.RESULT_CANCELED;
                finishActivity(true, result);
            } else {
                if (!getFragmentManager().popBackStackImmediate()) {
                    finishActivity(false, 0);
                }
            }
        }
    }

    private void finishActivity(final boolean sendResult, final int result) {
        // RadioPreference does not update UI if activity is marked as finished.
        // Wait a little bit for the RadioPreference UI update.
        mHandler.postDelayed(() -> {
            if (sendResult) {
                getActivity().setResult(result);
            }
            getActivity().finish();
        }, FINISH_ACTIVITY_DELAY);
    }

    private void displayAlert(
            CharSequence message,
            DialogInterface.OnClickListener positiveOnClickListener) {

        final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
                .setMessage(message)
                .setCancelable(true)
                .setPositiveButton(android.R.string.ok, positiveOnClickListener)
                .setNegativeButton(android.R.string.cancel, mCancelListener);
        final AlertDialog dialog = builder.create();
        dialog.setOnShowListener((dialogInterface) -> {
            final Button negative = dialog.getButton(AlertDialog.BUTTON_NEGATIVE);
            negative.requestFocus();
        });
        dialog.show();
    }
}