package com.rnboat.framework;

import android.os.Handler;
import android.util.Log;
import android.widget.Toast;

import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableNativeArray;
import com.facebook.react.bridge.ReadableNativeMap;
import com.google.gson.Gson;
import com.rnboat.framework.base.BaseActivity;
import com.rnboat.framework.base.BaseRNActivity;
import com.rnboat.framework.base.RNBoatApplication;
import com.rnboat.framework.diskcache.AsyncDiskCache;
import com.rnboat.framework.model.AppConfig;
import com.rnboat.framework.model.FrameworkConfig;
import com.rnboat.framework.updatepluginlib.UpdateBuilder;
import com.rnboat.framework.updatepluginlib.UpdateConfig;
import com.rnboat.framework.updatepluginlib.base.UpdateParser;
import com.rnboat.framework.updatepluginlib.impl.RNBoatDefaultCheckWorker;
import com.rnboat.framework.updatepluginlib.impl.RNBoatDefaultUpdateChecker;
import com.rnboat.framework.updatepluginlib.model.Update;
import com.rnboat.framework.util.AllDialogShowStrategy;
import com.rnboat.framework.util.AppUtils;
import com.rnboat.framework.util.DataCleanManager;
import com.rnboat.framework.util.LogcatHelper;
import com.rnboat.framework.util.NotificationDownloadCreator;
import com.rnboat.framework.util.OkhttpDownloadWorker;
import com.rnboat.framework.util.RNBoatApkFileCreator;
import com.rnboat.framework.util.RNBoatFileChecker;
import com.rnboat.framework.util.ToastCallback;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Nullable;

/**
 * Created by Castiel on 2018/3/30.
 */

public class FrameworkModule extends ReactContextBaseJavaModule {

    private static String MODULE_NAME = "Framework";

    public FrameworkModule(ReactApplicationContext reactContext) {
        super(reactContext);
        reactContext.addLifecycleEventListener(new LifecycleEventListener() {
            @Override
            public void onHostResume() {
                Log.e("DispatcherModule", "onHostResume");
            }

            @Override
            public void onHostPause() {
                Log.e("DispatcherModule", "onHostPause");
            }

            @Override
            public void onHostDestroy() {
                Log.e("DispatcherModule", "onHostDestroy");
            }
        });
    }

    @Override
    public String getName() {
        return MODULE_NAME;
    }

    @ReactMethod
    public void init(String params, Promise promise) {
        if (getCurrentActivity() instanceof BaseRNActivity) {
            ((BaseRNActivity) getCurrentActivity()).setCurrentActivityState(FrameworkConfig.State);
        }

        if (params.toLowerCase().equals("release")) {
            FrameworkConfig.State = FrameworkConfig.FrameworkState.Release;
        }
        if (params.toLowerCase().equals("dev")) {
            FrameworkConfig.State = FrameworkConfig.isDebug() ? FrameworkConfig.FrameworkState.Dev : FrameworkConfig.FrameworkState.Release;
        }
        if (params.toLowerCase().equals("superdev")) {
            FrameworkConfig.State = FrameworkConfig.FrameworkState.SuperDev;
        }

        promise.resolve(FrameworkConfig.State != FrameworkConfig.FrameworkState.Dev);
    }

    @ReactMethod
    public void getFrameworkState(Promise promise) {
        promise.resolve(FrameworkConfig.State);
    }

    @ReactMethod
    public void setBundleID(String bundleID) {
        ConfigManager.BUNDLE_ID = bundleID;
        AsyncDiskCache.asyncWriteCache("bundleID", bundleID, null);
    }

    @ReactMethod
    public void setSV(int sv) {
        ConfigManager.SV = sv;
        AsyncDiskCache.asyncWriteCache("sv", sv, null);
    }

    @ReactMethod
    public void setENV(int env) {
        ConfigManager.ENV = env;
        AsyncDiskCache.asyncWriteCache("env", env, new AsyncDiskCache.IWriteCacheListener() {
            @Override
            public void onWriteSuccess() {
                if (getCurrentActivity() != null && getCurrentActivity() instanceof BaseRNActivity) {
                    getCurrentActivity().runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            ((BaseRNActivity) getCurrentActivity()).showLoadingDialog();
                            ((BaseRNActivity) getCurrentActivity()).reCreateNewInstance(null, null);
                        }
                    });
                }
            }
            @Override
            public void onWriteFail() {
            }
        });
    }

    @ReactMethod
    public void saveAppConfig(ReadableMap params) {
        ReadableNativeMap middleMap = (ReadableNativeMap) params;
        HashMap nativeMap = middleMap.toHashMap();
        final AppConfig appConfig = AppConfig.decodeParams(nativeMap);
        if (appConfig != null) {
            AsyncDiskCache.syncWriteCache(ConfigManager.APP_CONFIG_KEY, appConfig);
            ConfigManager.APPCONFIG = appConfig;

            if (appConfig != null && appConfig.getApp() != null && getCurrentActivity() != null) {
                getCurrentActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //是否初始化守护进程
                        if (getCurrentActivity().getApplication() instanceof RNBoatApplication) {
                            ((RNBoatApplication) getCurrentActivity().getApplication()).configureDaemonService();
                        }

                        //是否全屏
                        if (getCurrentActivity() instanceof BaseActivity) {
                            ((BaseRNActivity) getCurrentActivity()).configureSystemUI(getCurrentActivity().getWindow().getDecorView());
                        }

                        //检测更新
                        UpdateConfig rnBoatUpdateConfig = UpdateConfig.createConfig();
                        rnBoatUpdateConfig.setUpdateParser(new UpdateParser() {
                            @Override
                            public Update parse() {
                                Update update = new Update();
                                // 此apk包的下载地址
                                update.setUpdateUrl(appConfig.getApp().getUrl());
                                // 此apk包的版本号
                                update.setVersionCode(appConfig.getApp().getVersionCode());
                                // 此apk包的版本名称
                                update.setVersionName(appConfig.getApp().getVersionName());
                                // 此apk包的更新内容
                                update.setUpdateContent(appConfig.getApp().getUpdateContent());
                                // 此apk包是否为强制更新
                                update.setForced(appConfig.getApp().isForce());
                                // 是否显示忽略此次版本更新按钮
                                update.setIgnore(false);
                                update.setMd5(null);
                                return update;
                            }
                        });
                        UpdateBuilder builder = UpdateBuilder.create(rnBoatUpdateConfig);
                        // 配置toast通知的回调
                        ToastCallback callback = new ToastCallback(getCurrentActivity());
                        builder.setDownloadCallback(callback);
                        builder.setCheckCallback(callback);
                        builder.setCheckWorker(RNBoatDefaultCheckWorker.class);
                        builder.setUpdateChecker(new RNBoatDefaultUpdateChecker());
                        builder.setUpdateStrategy(new AllDialogShowStrategy());
                        builder.setDownloadNotifier(new NotificationDownloadCreator());
                        builder.setFileCreator(new RNBoatApkFileCreator());
                        builder.setDownloadWorker(OkhttpDownloadWorker.class);
                        builder.setFileChecker(new RNBoatFileChecker());
                        builder.check();
                    }
                });
            }
        }
    }

    @ReactMethod
    public void getAppConfig(Promise promise) {
        promise.resolve((new Gson()).toJson(ConfigManager.APPCONFIG));
    }

    @ReactMethod
    public void onDebugSuccess() {
        if (getCurrentActivity() != null && getCurrentActivity() instanceof BaseRNActivity) {
            ((BaseRNActivity) getCurrentActivity()).setOnDebugSuccess(true);
        }
    }

    @ReactMethod
    public void setNoPropagatedKeyCodes(ReadableArray readableArray) {
        if (getCurrentActivity() != null && getCurrentActivity() instanceof BaseRNActivity) {
            ReadableNativeArray middleArray = (ReadableNativeArray) readableArray;
            ArrayList nativeArray = middleArray.toArrayList();
            ((BaseRNActivity) getCurrentActivity()).setNoPropagatedKeyCodes(nativeArray);
        }
    }

    @ReactMethod
    public void sendError(int errorCode) {
        switch (errorCode) {
            case -1: {
                sendLoadingError(R.string.InitSceneNotSet, true);
                break;
            }
            case -2: {
                sendLoadingError(R.string.ConfigErrorCatches, true);
                break;
            }
            case -10: {
                sendLoadingError(R.string.ConfigErrorNotCatch, true);
                break;
            }
            default: {
                break;
            }
        }
    }

    @ReactMethod
    public void forceKill() {
        AppUtils.forceKill(getReactApplicationContext());
    }

    @ReactMethod
    public void startLogcatHelper() {
        LogcatHelper.getInstance(getReactApplicationContext()).start();
    }

    @ReactMethod
    public void stopLogcatHelper() {
        LogcatHelper.getInstance(getReactApplicationContext()).stop();
    }

    @ReactMethod
    public void uploadLogs() {
        final LogcatHelper logcatHelper = LogcatHelper.getInstance(getReactApplicationContext());
        logcatHelper.stop();
        logcatHelper.uploadAllFiles(new LogcatHelper.OnUploadSuccessCallback() {
            @Override
            public void onUploadSuccess() {
                if (getCurrentActivity() != null && getCurrentActivity() instanceof BaseActivity) {
                    getCurrentActivity().runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(getReactApplicationContext(), R.string.UploadLogsSuccess, Toast.LENGTH_LONG).show();
                        }
                    });
                }
                logcatHelper.start();
            }
        });
    }

    @ReactMethod
    public void clearAppData() {
        DataCleanManager.cleanApplicationData(getReactApplicationContext());
        final Runnable exitRunnable = new Runnable() {
            @Override
            public void run() {
                System.exit(0);
            }
        };
        if (getCurrentActivity() != null)
            getCurrentActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getReactApplicationContext(), R.string.clear_cache_completion, Toast.LENGTH_LONG).show();
                    new Handler().postDelayed(exitRunnable, 2000);
                }
            });
    }

    @Nullable
    @Override
    public Map<String, Object> getConstants() {
        HashMap<String, Object> constants = new HashMap<>();
        constants.put("bundleID", ConfigManager.BUNDLE_ID);
        constants.put("sv", ConfigManager.SV);
        constants.put("env", ConfigManager.ENV);
        return constants;
    }

    private void sendLoadingError(final int resId, final boolean showCloseBtn) {
        if (getCurrentActivity() != null && getCurrentActivity() instanceof BaseActivity) {
            getCurrentActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    ((BaseActivity) getCurrentActivity()).sendLoadingError(resId, showCloseBtn);
                }
            });
        }
    }
}
