package me.thekey.android.view.dialog;

import android.app.Activity;
import android.app.Dialog;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.webkit.WebView;
import android.widget.FrameLayout;

import java.lang.ref.WeakReference;

import me.thekey.android.TheKey;
import me.thekey.android.core.CodeGrantAsyncTask;
import me.thekey.android.view.Builder;
import me.thekey.android.view.LoginWebViewClient;
import me.thekey.android.view.fragment.FragmentBuilder;
import me.thekey.android.view.util.DisplayUtil;
import timber.log.Timber;

public class LoginDialogFragment extends DialogFragment {
    public interface Listener {
        void onLoginSuccess(LoginDialogFragment dialog, String guid);

        void onLoginFailure(LoginDialogFragment dialog);
    }

    // login WebView
    private FrameLayout frame = null;
    private WebView mLoginView = null;

    public static Builder<LoginDialogFragment> builder() {
        return new FragmentBuilder<>(LoginDialogFragment.class);
    }

    /* BEGIN lifecycle */

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setRetainInstance(true);
    }

    @Override
    public Dialog onCreateDialog(final Bundle savedInstanceState) {
        final AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());

        // build dialog
        final FrameLayout frame =
                (FrameLayout) LayoutInflater.from(this.getActivity()).inflate(R.layout.thekey_login, null);
        this.attachLoginView(frame);
        builder.setView(frame);

        // handle back button presses to navigate back in the WebView if possible
        builder.setOnKeyListener((dialog, keyCode, event) -> {
            if (event.getAction() == KeyEvent.ACTION_UP &&
                    keyCode == KeyEvent.KEYCODE_BACK &&
                    event.isTracking() && !event.isCanceled()) {
                return DisplayUtil.navigateBackIfPossible(mLoginView);
            }
            return false;
        });

        return builder.create();
    }

    @Override
    public void onDestroyView() {
        // HACK: Work around bug
        // HACK: http://code.google.com/p/android/issues/detail?id=17423
        // HACK: https://issuetracker.google.com/issues/36929400
        final Dialog dialog = this.getDialog();
        if ((dialog != null) && this.getRetainInstance()) {
            dialog.setDismissMessage(null);
        }

        super.onDestroyView();
    }

    /* END lifecycle */

    private void attachLoginView(final FrameLayout frame) {
        this.detachLoginView();

        // create a Login WebView if one doesn't exist already
        if (mLoginView == null) {
            final Bundle args = getArguments();
            mLoginView = DisplayUtil.createLoginWebView(frame.getContext(), new LoginDialogWebViewClient(args), args);
        }

        // attach the login view to the current frame
        this.frame = frame;
        this.frame.addView(mLoginView);
    }

    private void detachLoginView() {
        // remove the login view from any existing frame
        if (this.frame != null) {
            try {
                this.frame.removeView(mLoginView);
            } catch (final IllegalArgumentException e) {
                // XXX: KEYAND-12 IllegalArgumentException: Receiver not registered: android.webkit.WebViewClassic
                Timber.e(e, "error removing Login WebView, let's just reset the login view");
                mLoginView = null;
            }
            this.frame = null;
        }
    }

    class LoginDialogWebViewClient extends LoginWebViewClient {
        LoginDialogWebViewClient(@Nullable final Bundle args) {
            super(requireContext(), args);
        }

        @Override
        protected void onAuthorizeSuccess(@NonNull final Uri uri, @NonNull final String code,
                                          @Nullable final String state) {
            new LoginDialogCodeGrantAsyncTask(LoginDialogFragment.this, mTheKey, uri).execute();
        }

        @Override
        @SuppressWarnings("unchecked")
        protected void onAuthorizeError(final Uri uri, final String errorCode) {
            final Activity activity = getActivity();
            if (activity instanceof Listener) {
                ((Listener) activity).onLoginFailure(LoginDialogFragment.this);
            }

            // close the dialog if it is still active (added to the activity)
            if (isAdded()) {
                dismissAllowingStateLoss();
            }
        }
    }

    static final class LoginDialogCodeGrantAsyncTask extends CodeGrantAsyncTask {
        private final WeakReference<LoginDialogFragment> mDialog;

        LoginDialogCodeGrantAsyncTask(@NonNull final LoginDialogFragment dialog, @NonNull final TheKey thekey,
                                      @NonNull final Uri dataUri) {
            super(thekey, dataUri);
            mDialog = new WeakReference<>(dialog);
        }

        @SuppressWarnings("unchecked")
        @Override
        protected void onPostExecute(final String guid) {
            super.onPostExecute(guid);

            final LoginDialogFragment dialog = mDialog.get();
            if (dialog != null) {
                final Activity activity = dialog.getActivity();
                if (activity instanceof Listener) {
                    // trigger the correct callback
                    if (guid != null) {
                        ((Listener) activity).onLoginSuccess(dialog, guid);
                    } else {
                        ((Listener) activity).onLoginFailure(dialog);
                    }
                }

                // close the dialog if it is still active (added to the activity)
                if (dialog.isAdded()) {
                    dialog.dismissAllowingStateLoss();
                }
            }
        }
    }
}

@@ -81,32 +81,64 @@
 oid.app.Dialog;%0A
+import android.content.Context;%0A
 import android.n
@@ -1142,16 +1142,89 @@
  = null;
+%0A    @Nullable%0A    private LoginWebViewClient mLoginWebViewClient = null;
 %0A%0A    pu
@@ -1371,24 +1371,164 @@
 fecycle */%0A%0A
+    @Override%0A    public void onAttach(final Context context) %7B%0A        super.onAttach(context);%0A        updateLoginWebViewClient();%0A    %7D%0A%0A
     @Overrid
@@ -3134,52 +3134,55 @@
 ate 
-a
+the
  Login
- 
 WebView
+Client
  if 
-on
+w
 e do
-es
 n't 
-exist already
+have one yet
 %0A   
@@ -3196,20 +3196,29 @@
  (mLogin
+Web
 View
+Client
  == null
@@ -3237,43 +3237,223 @@
     
-final Bundle args = getArguments();
+mLoginWebViewClient = new LoginDialogWebViewClient(getArguments());%0A            updateLoginWebViewClient();%0A        %7D%0A%0A        // create a Login WebView if one doesn't exist already%0A        if (mLoginView == null) %7B
 %0A   
@@ -3525,31 +3525,22 @@
 text(), 
-new 
+m
 Login
-Dialog
 WebViewC
@@ -3548,20 +3548,24 @@
 ient
-(args), args
+, getArguments()
 );%0A 
@@ -3699,24 +3699,190 @@
 ew);%0A    %7D%0A%0A
+    private void updateLoginWebViewClient() %7B%0A        if (mLoginWebViewClient != null) %7B%0A            mLoginWebViewClient.setActivity(getActivity());%0A        %7D%0A    %7D%0A%0A
     private 

update LoginDialogFragment to track the Activity on the LoginWebViewClient