package com.dynatrace.android.agent;

import com.dynatrace.android.agent.crash.PlatformType;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactMethod;

import java.util.Hashtable;
import java.util.HashMap;
import java.util.Map;

import android.location.Location;

import com.dynatrace.android.agent.conf.DataCollectionLevel;

public class DynatraceRNBridge extends ReactContextBaseJavaModule {

    private Hashtable<Integer, DTXAction> actions;
    private static final String PLATFORM_ANDROID = "android";
    private static final String PLATFORM_IOS = "ios";
    private static final String DATA_COLLECTION_OFF = "OFF";
    private static final String DATA_COLLECTION_USER = "USER_BEHAVIOR";
    private static final String DATA_COLLECTION_PERFORMANCE = "PERFORMANCE";

    private static PrivateDTBridge _internal;

    public DynatraceRNBridge(ReactApplicationContext reactContext, PrivateDTBridge internal) {
        super(reactContext);
        actions = new Hashtable<>();
        _internal = internal;
    }

    @Override
    public String getName(){
//         return "DynatraceBridge";
        return "CloudwiseBridge";
    }

    @Override
    public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap<>();
        constants.put("PLATFORM_ANDROID", PLATFORM_ANDROID);
        constants.put("PLATFORM_IOS", PLATFORM_IOS);
        constants.put("DATA_COLLECTION_OFF", DATA_COLLECTION_OFF);
        constants.put("DATA_COLLECTION_USER", DATA_COLLECTION_USER);
        constants.put("DATA_COLLECTION_PERFORMANCE", DATA_COLLECTION_PERFORMANCE);
        return constants;
    }

    //
    // Expects a key which is generated in JS. This is to circumvent the async callback system.
    //
    @ReactMethod
    public void enterAction(String name, int key, String platform) {
        if (this.shouldWorkOnAndroid(platform)) {
            try {
                newAction(name, key);
            }
            catch (Exception e) {}
        }
    }

    @ReactMethod
    public void leaveAction(int key, String platform) {
        if (this.shouldWorkOnAndroid(platform)) {
            DTXAction action = getAction(key);
            if (action == null) return;
            if (action instanceof DTXAutoAction){
                ((DTXAutoAction) action).startTimer();
            }else{
                action.leaveAction();
            }

            actions.remove(Integer.valueOf(key));
        }
    }

    @ReactMethod
    public void endVisit(String platform) {
        if (this.shouldWorkOnAndroid(platform)) {
            Dynatrace.endVisit();
        }
    }

    @ReactMethod
    public void reportErrorWithoutStacktrace(String errorName, int errorCode, String platform) {
        if (this.shouldWorkOnAndroid(platform)) {
            Dynatrace.reportError(errorName, errorCode);
        }
    }

    /**
     * Reports a stacktrace - Used primary for the internal error
     * handler
     * @param errorName Non or Fatal React Native Error
     * @param errorValue Name of the Error - SyntaxError
     * @param reason Reason for the Error
     * @param stacktrace Whole Stacktrace
     * @param platform Platform wise or both
     */
    @ReactMethod
    public void reportError(String errorName, String errorValue, String reason, String stacktrace, String platform){
        if (this.shouldWorkOnAndroid(platform)) {
            Dynatrace.reportError(PlatformType.JAVA_SCRIPT, errorName, errorValue, reason, stacktrace);
        }
    }

    @ReactMethod
    public void reportCrash(String errorName, String reason, String stacktrace, String platform){
        if (this.shouldWorkOnAndroid(platform)) {
            Dynatrace.reportCrash(PlatformType.JAVA_SCRIPT, errorName, reason, stacktrace);
            Dynatrace.createNewSession();
        }
    }

    @ReactMethod
    public void reportErrorInAction(int key, String errorName, int errorCode, String platform) {
        if (this.shouldWorkOnAndroid(platform)) {
            DTXAction action = getAction(key);
            if (action == null) return;
            action.reportError(errorName, errorCode);
        }
    }

    @ReactMethod
    public void reportValue(int key, String valueName, String value, String platform) {
        if (this.shouldWorkOnAndroid(platform)) {
            DTXAction action = getAction(key);
            if (action == null) return;
            action.reportValue(valueName, value);
        }
    }

    @ReactMethod
    public void getRequestTag(Promise promise){
        promise.resolve(Dynatrace.getRequestTagHeader());
    }

    @ReactMethod
    public void identifyUser(String user, String plaform) {
        if (this.shouldWorkOnAndroid(plaform)) {
            Dynatrace.identifyUser(user);
        }
    }

    @ReactMethod
    public void reportEventInAction(int actionKey, String name, String platform) {
        if (this.shouldWorkOnAndroid(platform)) {
            DTXAction action = getAction(actionKey);
            if (action == null) return;
            action.reportEvent(name);
        }
    }

    @ReactMethod
    public void reportStringValueInAction(int actionKey, String name, String value, String platform) {
        if (this.shouldWorkOnAndroid(platform)) {
            DTXAction action = getAction(actionKey);
            if (action == null) return;
            action.reportValue(name, value);
        }
    }

    @ReactMethod
    public void reportIntValueInAction(int actionKey, String name, int value, String platform) {
        if (this.shouldWorkOnAndroid(platform)) {
            DTXAction action = getAction(actionKey);
            if (action == null) return;
            action.reportValue(name, value);
        }
    }

    @ReactMethod
    public void reportDoubleValueInAction(int actionKey, String name, double value, String platform) {
        if (this.shouldWorkOnAndroid(platform)) {
            DTXAction action = getAction(actionKey);
            if (action == null) return;
            action.reportValue(name, value);
        }
    }

    @ReactMethod
    public void setGPSLocation(double latitude, double longitude, String platform){
        if(this.shouldWorkOnAndroid(platform)){
            Location location = new Location("");
            location.setLatitude(latitude);
            location.setLongitude(longitude);
            Dynatrace.setGpsLocation(location);
        }
    }

    @ReactMethod
    public void flushEvents(String platform){
        if(this.shouldWorkOnAndroid(platform)){
            Dynatrace.flushEvents();
        }
    }

    @ReactMethod
    public void isCrashReportingOptedIn(String platform, Promise promise){
        if(this.shouldWorkOnAndroid(platform)){
            promise.resolve(Dynatrace.isCrashReportingOptedIn());
        }
    }

    @ReactMethod
    public void setCrashReportingOptedIn(boolean crashReporting, String platform){
        if(this.shouldWorkOnAndroid(platform)){
            Dynatrace.setCrashReportingOptedIn(crashReporting);
        }
    }

    @ReactMethod
    public void setDataCollectionLevel(String collectionLevel, String platform){
        if(this.shouldWorkOnAndroid(platform)){
            Dynatrace.setDataCollectionLevel(DataCollectionLevel.valueOf(collectionLevel));
        }
    }

    @ReactMethod
    public void getDataCollectionLevel(String platform, Promise promise){
        if(this.shouldWorkOnAndroid(platform)){
            DataCollectionLevel level = Dynatrace.getDataCollectionLevel();
            promise.resolve(level.name());
        }
    }

    private void newAction(String name, int key) throws Exception {
        if (name == null) throw new Exception("action name is null");
        actions.put(Integer.valueOf(key), _internal.enterAction(name));
    }

    private DTXAction getAction(int key){
        return actions.get(Integer.valueOf(key));
    }

    private Boolean shouldWorkOnAndroid(String platform) {
        return platform == null || platform.equals(PLATFORM_ANDROID) || platform.equals("");
    }
}
