package com.rnboat.framework.base;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;

import com.blankj.utilcode.util.AppUtils;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.ReactRootView;
import com.facebook.react.bridge.Callback;
import com.facebook.react.devsupport.DoubleTapReloadRecognizer;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.modules.core.PermissionListener;
//import com.qianmi.qmlogger.QMLog;
import com.rnboat.framework.model.FrameworkConfig;

import java.util.Collections;
import java.util.List;

import javax.annotation.Nullable;

public class RNBoatReactActivityDelegate extends ReactActivityDelegate {
    private final static String TAG = "RNBoatReactActivityDelegate";

    private final @Nullable
    Activity mActivity;
    private final @Nullable
    FragmentActivity mFragmentActivity;
    private final @Nullable
    String mMainComponentName;

    private @Nullable
    ReactRootView mReactRootView;
    private @Nullable
    DoubleTapReloadRecognizer mDoubleTapReloadRecognizer;
    private @Nullable
    PermissionListener mPermissionListener;
    private @Nullable
    Callback mPermissionsCallback;
    private RNBoatReactNativeHost mRNBoatReactNativeHost;

    protected String mJSBundlePath;

    private Bundle launchOptions;

    public void initNativeHost(final String mJSBundlePath) {
        this.mJSBundlePath = mJSBundlePath;

        String bundleAssetName = FrameworkConfig.State == FrameworkConfig.FrameworkState.Release ? "updateService.bundle" : "index.android";

        if (AppUtils.isAppDebug())
            Toast.makeText(mActivity, "FrameworkConfig.State:" + FrameworkConfig.State, Toast.LENGTH_LONG).show();

        if (mJSBundlePath != null)
            bundleAssetName = null;

        mRNBoatReactNativeHost = new RNBoatReactNativeHost(getPlainActivity().getApplication(), mJSBundlePath, bundleAssetName) {
            @Override
            public boolean getUseDeveloperSupport() {
                return FrameworkConfig.State == FrameworkConfig.FrameworkState.Release ? false :
                        (FrameworkConfig.State == FrameworkConfig.FrameworkState.SuperDev && mJSBundlePath != null ? false : true);
            }

            @Override
            protected List<ReactPackage> getPackages() {
                if (getApplication() instanceof RNBoatApplication) {
                    return ((RNBoatApplication) getApplication()).getPackages();
                }
//                QMLog.e(TAG, "main application must be implements RNBoatApplication");
                return Collections.emptyList();
            }

            @Override
            protected String getJSMainModuleName() {
                return "index.android";
            }
        };
    }

    public RNBoatReactActivityDelegate(Activity activity, @Nullable String mainComponentName) {
        super(activity, mainComponentName);
        mActivity = activity;
        mMainComponentName = mainComponentName;
        mFragmentActivity = null;
    }

    protected @Nullable
    Bundle getLaunchOptions() {
        return this.launchOptions;
    }

    public void setLaunchOptions(Bundle launchOptions) {
        this.launchOptions = launchOptions;
    }

    protected ReactRootView createRootView() {
        ReactRootView reactRootView = new ReactRootView(getContext());
        reactRootView.setEventListener(new ReactRootView.ReactRootViewEventListener() {
            @SuppressLint("LongLogTag")
            @Override
            public void onAttachedToReactInstance(ReactRootView rootView) {
                Log.e(TAG, "onAttachedToReactInstance");
            }
        });
        return reactRootView;
    }

    /**
     * Get the {@link ReactNativeHost} used by this app. By default, assumes
     * {@link Activity#getApplication()} is an instance of {@link ReactApplication} and calls
     * {@link ReactApplication#getReactNativeHost()}. Override this method if your application class
     * does not implement {@code ReactApplication} or you simply have a different mechanism for
     * storing a {@code ReactNativeHost}, e.g. as a static field somewhere.
     */
    public ReactNativeHost getReactNativeHost() {
        return mRNBoatReactNativeHost;
    }

    public ReactInstanceManager getReactInstanceManager() {
        return getReactNativeHost().getReactInstanceManager();
    }

    public void onCreate(Bundle savedInstanceState) {
        if (mMainComponentName != null) {
            loadApp(mMainComponentName);
        }
        mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
    }

    @SuppressLint("LongLogTag")
    protected void loadApp(String appKey) {
        if (mReactRootView != null) {
            throw new IllegalStateException("Cannot loadApp while app is already running.");
        }

        mReactRootView = createRootView();
        mReactRootView.startReactApplication(
                getReactNativeHost().getReactInstanceManager(),
                appKey,
                getLaunchOptions());
        getPlainActivity().setContentView(mReactRootView);

        Log.e(TAG, "loadApp");
    }

    protected void onPause() {
        if (getReactNativeHost().hasInstance()) {
            getReactNativeHost().getReactInstanceManager().onHostPause(getPlainActivity());
        }
    }

    public void onResume() {
        if (getReactNativeHost().hasInstance()) {
            getReactNativeHost().getReactInstanceManager().onHostResume(
                    getPlainActivity(),
                    (DefaultHardwareBackBtnHandler) getPlainActivity());
        }

        if (mPermissionsCallback != null) {
            mPermissionsCallback.invoke();
            mPermissionsCallback = null;
        }
    }

    public void onDestroy() {
        if (mReactRootView != null) {
            mReactRootView.unmountReactApplication();
            mReactRootView = null;
        }
        if (getReactNativeHost().hasInstance()) {
            getReactNativeHost().getReactInstanceManager().onHostDestroy(getPlainActivity());
        }
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (getReactNativeHost().hasInstance()) {
            getReactNativeHost().getReactInstanceManager()
                    .onActivityResult(getPlainActivity(), requestCode, resultCode, data);
        }
    }

    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (getReactNativeHost().hasInstance() && getReactNativeHost().getUseDeveloperSupport()) {
            if (keyCode == KeyEvent.KEYCODE_MENU) {
                getReactNativeHost().getReactInstanceManager().showDevOptionsDialog();
                return true;
            }
            boolean didDoubleTapR = Assertions.assertNotNull(mDoubleTapReloadRecognizer)
                    .didDoubleTapR(keyCode, getPlainActivity().getCurrentFocus());
            if (didDoubleTapR) {
                getReactNativeHost().getReactInstanceManager().getDevSupportManager().handleReloadJS();
                return true;
            }
        }
        return false;
    }

    public boolean onBackPressed() {
        if (getReactNativeHost().hasInstance()) {
            getReactNativeHost().getReactInstanceManager().onBackPressed();
            return true;
        }
        return false;
    }

    public boolean onNewIntent(Intent intent) {
        if (getReactNativeHost().hasInstance()) {
            getReactNativeHost().getReactInstanceManager().onNewIntent(intent);
            return true;
        }
        return false;
    }

    @TargetApi(Build.VERSION_CODES.M)
    public void requestPermissions(
            String[] permissions,
            int requestCode,
            PermissionListener listener) {
        mPermissionListener = listener;
        getPlainActivity().requestPermissions(permissions, requestCode);
    }

    public void onRequestPermissionsResult(
            final int requestCode,
            final String[] permissions,
            final int[] grantResults) {
        mPermissionsCallback = new Callback() {
            @Override
            public void invoke(Object... args) {
                if (mPermissionListener != null && mPermissionListener.onRequestPermissionsResult(requestCode, permissions, grantResults)) {
                    mPermissionListener = null;
                }
            }
        };
    }

    private Context getContext() {
        if (mActivity != null) {
            return mActivity;
        }
        return Assertions.assertNotNull(mFragmentActivity);
    }

    private Activity getPlainActivity() {
        return ((Activity) getContext());
    }
}
