package com.rnboat.framework;


import android.app.Activity;
import android.util.Log;

import com.facebook.react.ReactActivity;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class BoatModule extends ReactContextBaseJavaModule {

    private static final String REACT_APPLICATION_CLASS_NAME = "com.facebook.react.ReactApplication";
    private static final String REACT_NATIVE_HOST_CLASS_NAME = "com.facebook.react.ReactNativeHost";


    public BoatModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    private void loadBundleLegacy(final Activity currentActivity) {
        currentActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                currentActivity.recreate();
            }
        });
    }

    private void loadBundle(boolean clearInstance) {
        final Activity currentActivity = getCurrentActivity();

        if (currentActivity == null) {
            Log.d(getClass().getSimpleName(), "currentActivity is NULL !!!");
        } else if (ReactActivity.class.isInstance(currentActivity)) {

            try {
                ReactActivity reactActivity = (ReactActivity) currentActivity;
                ReactInstanceManager instanceManager;

                try {
                    Method getApplicationMethod = ReactActivity.class.getMethod("getApplication");
                    Object reactApplication = getApplicationMethod.invoke(reactActivity);
                    Class<?> reactApplicationClass = tryGetClass(REACT_APPLICATION_CLASS_NAME);
                    Method getReactNativeHostMethod = reactApplicationClass.getMethod("getReactNativeHost");

                    final ReactNativeHost reactNativeHost = (ReactNativeHost) getReactNativeHostMethod.invoke(reactApplication);

                    if (clearInstance) {
                        currentActivity.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                reactNativeHost.clear();
                            }
                        });
                    }

                    Class<?> reactNativeHostClass = tryGetClass(REACT_NATIVE_HOST_CLASS_NAME);
                    Method getReactInstanceManagerMethod = reactNativeHostClass.getMethod("getReactInstanceManager");
                    instanceManager = (ReactInstanceManager) getReactInstanceManagerMethod.invoke(reactNativeHost);
                } catch (Exception e) {
                    Field instanceManagerField = ReactActivity.class.getDeclaredField("mReactInstanceManager");
                    instanceManagerField.setAccessible(true);
                    instanceManager = (ReactInstanceManager) instanceManagerField.get(reactActivity);
                }

                final Method recreateMethod = instanceManager.getClass().getMethod("recreateReactContextInBackground");

                final ReactInstanceManager finalizedInstanceManager = instanceManager;
                reactActivity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            recreateMethod.invoke(finalizedInstanceManager);
                        } catch (Exception e) {
                            loadBundleLegacy(currentActivity);
                        }
                    }
                });
            } catch (Exception e) {
                loadBundleLegacy(currentActivity);
            }
        } else {
            loadBundleLegacy(currentActivity);
        }
    }

    private Class tryGetClass(String className) {
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            return null;
        }
    }

    @ReactMethod
    public void restart(Boolean clearRnInstance) {
        loadBundle(clearRnInstance);
    }


    @ReactMethod
    public void bundle(String bundlePath) {
        Boat.bundle = bundlePath;
    }

    @Override
    public String getName() {
        return "RNBoat";
    }

}
