package com.remobile.update;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;

import com.facebook.react.ReactActivity;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactApplication;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.JSBundleLoader;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;


public class RCTUpdate extends ReactContextBaseJavaModule {
    private Activity activity;
    private RCTUpdateMgr updateMgr;

    public RCTUpdate(ReactApplicationContext reactContext, Activity activity, RCTUpdateMgr updateMgr) {
        super(reactContext);
        this.activity = activity;
        this.updateMgr = updateMgr;
    }

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

    @Override
    public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap<>();
        constants.put("mainBundleFilePath", updateMgr.mainBundleFilePath);
        constants.put("documentFilePath", updateMgr.documentFilePath);
        constants.put("versionName", updateMgr.appVersion);
        constants.put("versionCode", updateMgr.buildVersion);
        return constants;
    }

    @ReactMethod
    public void installApk(final String file) throws Exception {
        final Activity activity = this.activity;
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setDataAndType(Uri.fromFile(new File(file)), "application/vnd.android.package-archive");
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                activity.startActivity(intent);
                android.os.Process.killProcess(android.os.Process.myPid());
            }
        });
    }

    @ReactMethod
    public void restartApp() {
        loadBundle();
    }

    @ReactMethod
    public void getLocalValue(String tag, Callback callback) {
        String ret = updateMgr.getLocalValue(tag);
        callback.invoke(ret);
    }

    @ReactMethod
    public void setLocalValue(String tag, String value) {
        updateMgr.setLocalValue(tag, value);
    }

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

    private ReactInstanceManager resolveInstanceManager() throws NoSuchFieldException, IllegalAccessException {
        ReactInstanceManager instanceManager;
        final Activity currentActivity = getCurrentActivity();
        if (currentActivity == null) {
            return null;
        }

        ReactApplication reactApplication = (ReactApplication) currentActivity.getApplication();
        instanceManager = reactApplication.getReactNativeHost().getReactInstanceManager();

        return instanceManager;
    }

    private void loadBundle() {
        try {
            final ReactInstanceManager instanceManager = resolveInstanceManager();
            if (instanceManager == null) {
                return;
            }
            setJSBundle(instanceManager, updateMgr.getBundleUrl());
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    try {
                        instanceManager.recreateReactContextInBackground();
                    } catch (Exception e) {
                        loadBundleLegacy();
                    }
                }
            });
        } catch (Exception e) {
            loadBundleLegacy();
        }
    }

    private void setJSBundle(ReactInstanceManager instanceManager, String latestJSBundleFile) throws IllegalAccessException {
       try {
           JSBundleLoader latestJSBundleLoader;
           if (latestJSBundleFile.toLowerCase().startsWith("assets://")) {
               latestJSBundleLoader = JSBundleLoader.createAssetLoader(getReactApplicationContext(), latestJSBundleFile, false);
           } else {
               latestJSBundleLoader = JSBundleLoader.createFileLoader(latestJSBundleFile);
           }

           Field bundleLoaderField = instanceManager.getClass().getDeclaredField("mBundleLoader");
           bundleLoaderField.setAccessible(true);
           bundleLoaderField.set(instanceManager, latestJSBundleLoader);
       } catch (Exception e) {
           throw new IllegalAccessException("Could not setJSBundle");
       }
   }
}