package im.shimo.baidumjt;

import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;

import com.baidu.mobstat.SendStrategyEnum;
import com.baidu.mobstat.StatService;
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.ReadableMap;
import com.facebook.react.modules.core.PermissionAwareActivity;
import com.facebook.react.modules.core.PermissionListener;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

/**
 * Created by bell on 2017/8/29.
 */

public class RNBaiduMjtModule extends ReactContextBaseJavaModule {
    private static final String E_CALLBACK_ERROR = "E_CALLBACK_ERROR";
    private static final String E_PERMISSIONS_MISSING = "E_PERMISSIONS_MISSING";

    private ReactApplicationContext mContext;
    private Promise mPromise;
    private boolean mHasPermission = false;

    public RNBaiduMjtModule(ReactApplicationContext reactContext) {
        super(reactContext);
        mContext = reactContext;
    }

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

    @ReactMethod
    public void start(final ReadableMap options, final Promise promise) {
        final Activity activity = getCurrentActivity();
        if (activity != null) {
            permissionsCheck(activity, promise, Arrays.asList(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE), new Callable<Void>() {
                @Override
                public Void call() throws Exception {
                    mHasPermission = true;
                    doStart(options);
                    promise.resolve(null);
                    return null;
                }
            });
        }
    }

    @ReactMethod
    public void logEvent(String eventId, String eventLabel, ReadableMap attributes) {
        if (!mHasPermission) {
            return;
        }
        StatService.onEvent(mContext, eventId, eventLabel, 1, toStringHashMap(attributes));
    }

    @ReactMethod
    public void logEventWithDurationTime(String eventId, String eventLabel, int duration, ReadableMap attributes) {
        if (!mHasPermission) {
            return;
        }
        StatService.onEventDuration(mContext, eventId, eventLabel, duration, toStringHashMap(attributes));
    }

    @ReactMethod
    public void eventStart(String eventId, String eventLabel) {
        if (!mHasPermission) {
            return;
        }
        StatService.onEventStart(mContext, eventId, eventLabel);
    }

    @ReactMethod
    public void eventEnd(String eventId, String eventLabel, ReadableMap attributes) {
        if (!mHasPermission) {
            return;
        }
        StatService.onEventEnd(mContext, eventId, eventLabel, toStringHashMap(attributes));
    }

    private void doStart(ReadableMap options) {
        if (options.hasKey("channel")) {
            StatService.setAppChannel(mContext, options.getString("channel"), true);
        }

        // 打开 Exception 接口
        if (options.hasKey("enableExceptionLog")) {
            StatService.setOn(mContext, options.getInt("enableExceptionLog"));
        }

        if (options.hasKey("sessionResumeInterval")) {
            StatService.setSessionTimeOut(options.getInt("sessionResumeInterval"));
        }

        // logStrategy 为 2 才有效
        if (options.hasKey("logSendInterval")) {
            StatService.setLogSenderDelayed(options.getInt("logSendInterval"));
        }

        if (options.hasKey("logStrategy")) {
            int logStrategy = options.getInt("logStrategy");
            if (logStrategy == 2) {
                StatService.setSendLogStrategy(mContext, SendStrategyEnum.SET_TIME_INTERVAL, logStrategy);
            } else if (logStrategy == 1) {
                StatService.setSendLogStrategy(mContext, SendStrategyEnum.ONCE_A_DAY, logStrategy);
            } else {
                StatService.setSendLogStrategy(mContext, SendStrategyEnum.APP_START, logStrategy);
            }
        }

        if (options.hasKey("enableDebug")) {
            StatService.setDebugOn(options.getBoolean("enableDebug"));
        }

        if (options.hasKey("appKey")) {
            StatService.setAppKey(options.getString("appKey"));
        }

        StatService.start(mContext);
    }

    private HashMap<String, String> toStringHashMap(ReadableMap source) {
        if (source == null) {
            return null;
        }
        HashMap<String, String> result = new HashMap<>();
        for (Map.Entry<String, Object> entry : source.toHashMap().entrySet()) {
            if (entry.getValue() instanceof String) {
                result.put(entry.getKey(), (String) entry.getValue());
            }
        }
        return result;
    }

    private void permissionsCheck(final Activity activity, final Promise promise, final List<String> requiredPermissions, final Callable<Void> callback) {

        List<String> missingPermissions = new ArrayList<>();

        for (String permission : requiredPermissions) {
            int status = ActivityCompat.checkSelfPermission(activity, permission);
            if (status != PackageManager.PERMISSION_GRANTED) {
                missingPermissions.add(permission);
            }
        }

        if (!missingPermissions.isEmpty()) {
            ((PermissionAwareActivity) activity).requestPermissions(missingPermissions.toArray(new String[missingPermissions.size()]), 1, new PermissionListener() {

                @Override
                public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
                    if (requestCode == 1) {
                        for (int grantResult : grantResults) {
                            if (grantResult == PackageManager.PERMISSION_DENIED) {
                                promise.reject(E_PERMISSIONS_MISSING, "Required permission missing");
                                return true;
                            }
                        }
                        try {
                            callback.call();
                        } catch (Exception e) {
                            promise.reject(E_CALLBACK_ERROR, "Unknown error", e);
                        }
                    }
                    return true;
                }
            });
            return;
        }
        // all permissions granted
        try {
            callback.call();
        } catch (Exception e) {
            promise.reject(E_CALLBACK_ERROR, "Unknown error", e);
        }
    }
}
