/*
 * 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.emergency.preferences;

import android.app.AlertDialog;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import androidx.annotation.VisibleForTesting;
import androidx.preference.DialogPreference;
import com.android.emergency.CircleFramedDrawable;
import com.android.emergency.R;
import com.android.internal.util.UserIcons;
import com.android.settingslib.CustomDialogPreference;

import java.io.File;

/**
 * Custom {@link DialogPreference} that allows us to editing the user name and photo.
 */
public class EmergencyNamePreference extends CustomDialogPreference {

    private static final String KEY_AWAITING_RESULT = "awaiting_result";
    private static final String KEY_SAVED_PHOTO = "pending_photo";

    private UserManager mUserManager = getContext().getSystemService(UserManager.class);
    private EditUserPhotoController mEditUserPhotoController;
    private Fragment mFragment;
    private Bitmap mSavedPhoto;
    private EditText mUserNameView;
    private ImageView mUserPhotoView;
    private boolean mWaitingForActivityResult = false;

    public EmergencyNamePreference(Context context, AttributeSet attrs,
            int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        setSummary(mUserManager.getUserName());
        setIcon(getCircularUserIcon());
        setDialogLayoutResource(R.layout.edit_user_info_dialog_content);
    }

    public EmergencyNamePreference(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public EmergencyNamePreference(Context context, AttributeSet attrs) {
        this(context, attrs, androidx.preference.R.attr.dialogPreferenceStyle);
    }

    public EmergencyNamePreference(Context context) {
        this(context, null);
    }

    /**
     * Setup fragment for Dialog and EditUserPhotoController.
     */
    public void setFragment(Fragment fragment) {
        mFragment = fragment;
    }

    /**
     * Reload user name and photo form UserManager.
     */
    public void reloadFromUserManager() {
        setSummary(mUserManager.getUserName());
        setIcon(getCircularUserIcon());
    }

    /**
     * Restore user photo when EditUserPhotoController had pending photo.
     */
    public void onRestoreInstanceState(Bundle icicle) {
        String pendingPhoto = icicle.getString(KEY_SAVED_PHOTO);
        if (pendingPhoto != null) {
            mSavedPhoto = EditUserPhotoController.loadNewUserPhotoBitmap(new File(pendingPhoto));
        }
        mWaitingForActivityResult = icicle.getBoolean(KEY_AWAITING_RESULT, false);
    }

    /**
     * Save a temp user photo when layout need to recreating but Dialog is showing.
     */
    public void onSaveInstanceState(Bundle outState) {
        if (getDialog() != null && getDialog().isShowing()
                && mEditUserPhotoController != null) {
            // Bitmap cannot be stored into bundle because it may exceed parcel limit
            // Store it in a temporary file instead
            File file = mEditUserPhotoController.saveNewUserPhotoBitmap();
            if (file != null) {
                outState.putString(KEY_SAVED_PHOTO, file.getPath());
            }
        }
        if (mWaitingForActivityResult) {
            outState.putBoolean(KEY_AWAITING_RESULT, mWaitingForActivityResult);
        }
    }

    /**
     * Set mWaitingForActivityResult to true when EmergencyNamePreferenceDialogFragment
     * startActivityForResult, means we are waiting the activity result.
     */
    public void startingActivityForResult() {
        mWaitingForActivityResult = true;
    }

    /**
     * Reset mWaitingForActivityResult and send the result code to EditUserPhotoController when
     * EmergencyNamePreferenceDialogFragment onActivityResult.
     */
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        mWaitingForActivityResult = false;

        if (getDialog() != null) {
            mEditUserPhotoController.onActivityResult(requestCode, resultCode, data);
        }
    }

    @Override
    protected void onBindDialogView(View view) {
        super.onBindDialogView(view);

        mUserNameView = view.findViewById(R.id.user_name);
        mUserNameView.setText(mUserManager.getUserName());
        mUserPhotoView = view.findViewById(R.id.user_photo);
        Drawable drawable;
        if (mSavedPhoto != null) {
            drawable = CircleFramedDrawable.getInstance(getContext(), mSavedPhoto);
        } else {
            drawable = getCircularUserIcon();
        }
        mUserPhotoView.setImageDrawable(drawable);

        mEditUserPhotoController = createEditUserPhotoController(mUserPhotoView,
                getCircularUserIcon());
    }

    @Override
    protected void onPrepareDialogBuilder(AlertDialog.Builder builder,
            DialogInterface.OnClickListener listener) {
        super.onPrepareDialogBuilder(builder, listener);
        builder.setTitle(R.string.name)
                .setCancelable(true)
                .setPositiveButton(android.R.string.ok, listener)
                .setNegativeButton(android.R.string.cancel, listener)
                .create();
    }

    @Override
    protected void onDialogClosed(boolean positiveResult) {
        super.onDialogClosed(positiveResult);
        if (positiveResult) {
            // Update the name if changed.
            CharSequence userName = mUserNameView.getText();
            if (!TextUtils.isEmpty(userName)) {
                if (mUserManager.getUserName() == null
                        || !userName.toString().equals(mUserManager.getUserName())) {
                    mUserManager.setUserName(UserHandle.myUserId(), userName.toString());
                    setSummary(userName);
                }
            }
            // Update the photo if changed.
            Drawable drawable = mEditUserPhotoController.getNewUserPhotoDrawable();
            Bitmap bitmap = mEditUserPhotoController.getNewUserPhotoBitmap();
            if (drawable != null && bitmap != null
                    && !drawable.equals(getCircularUserIcon())) {
                new AsyncTask<Void, Void, Void>() {
                    @Override
                    protected Void doInBackground(Void... params) {
                        mUserManager.setUserIcon(UserHandle.myUserId(),
                                mEditUserPhotoController.getNewUserPhotoBitmap());
                        return null;
                    }
                }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
                setIcon(drawable);
            }
            if (mFragment != null) {
                mFragment.getActivity().removeDialog(1);
            }
        }
        clear();
    }

    private void clear() {
        mEditUserPhotoController.removeNewUserPhotoBitmapFile();
        mSavedPhoto = null;
    }

    private Drawable getCircularUserIcon() {
        Bitmap bitmapUserIcon = mUserManager.getUserIcon(UserHandle.myUserId());

        if (bitmapUserIcon == null) {
            // get default user icon.
            final Drawable defaultUserIcon = UserIcons.getDefaultUserIcon(
                    getContext().getResources(), UserHandle.myUserId(), false);
            bitmapUserIcon = UserIcons.convertToBitmap(defaultUserIcon);
        }
        Drawable drawableUserIcon = new CircleFramedDrawable(bitmapUserIcon,
                (int) getContext().getResources().getDimension(R.dimen.circle_avatar_size));

        return drawableUserIcon;
    }

    @VisibleForTesting
    EditUserPhotoController createEditUserPhotoController(ImageView userPhotoView,
                Drawable drawable) {
        return new EditUserPhotoController(mFragment, userPhotoView,
                mSavedPhoto, drawable, mWaitingForActivityResult);
    }

    public static class EmergencyNamePreferenceDialogFragment extends
            CustomPreferenceDialogFragment {

        public static CustomDialogPreference.CustomPreferenceDialogFragment newInstance(
                String key) {
            final CustomDialogPreference.CustomPreferenceDialogFragment
                    fragment = new EmergencyNamePreferenceDialogFragment();
            final Bundle b = new Bundle(1 /* capacity */);
            b.putString(ARG_KEY, key);
            fragment.setArguments(b);
            return fragment;
        }

        private EmergencyNamePreference getEmergencyNamePreference() {
            return (EmergencyNamePreference) getPreference();
        }

        @Override
        public void onCreate(Bundle icicle) {
            super.onCreate(icicle);
            getEmergencyNamePreference().setFragment(this);
            if (icicle != null) {
                getEmergencyNamePreference().onRestoreInstanceState(icicle);
            }
        }

        @Override
        public void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            getEmergencyNamePreference().onSaveInstanceState(outState);
        }

        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            getEmergencyNamePreference().onActivityResult(requestCode, resultCode, data);
        }

        @Override
        public void startActivityForResult(Intent intent, int requestCode) {
            getEmergencyNamePreference().startingActivityForResult();
            super.startActivityForResult(intent, requestCode);
        }
    }
}
