package io.appgain.reactsdk;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;

import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableNativeMap;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.util.HashMap;
import java.util.Map;
import android.os.Bundle;

import io.appgain.sdk.controller.Appgain;
import io.appgain.sdk.interfaces.AppgainDataCallback;
import io.appgain.sdk.model.BaseResponse;
import io.appgain.sdk.model.deferredlinking.DeferredDeepLinkingResponse;

public class AppgainSDKJavaModule extends ReactContextBaseJavaModule {

    private final ReactApplicationContext reactContext;
    private Gson gson;
    private boolean isInitialized = false;

    public AppgainSDKJavaModule(ReactApplicationContext reactContext) {
      super(reactContext);
      this.reactContext = reactContext;
      this.gson = new GsonBuilder().create();
    }

      @Override
      public String getName() {
          return "AppgainSDK";
      }
  
    @ReactMethod
    public void initAppgainSDK(
        final String projectId, final String apiKey, final boolean autoconfig, final Callback successCallback, final Callback errorCallback
    ){
        try{
            Appgain.initialize(getReactApplicationContext(), projectId, apiKey, true,  new AppgainDataCallback<Void>() {
                @Override
                public void onSuccess(Void data) {
                    isInitialized = true;
                    successCallback.invoke("{}");
                }
                @Override
                public void onFailure(BaseResponse failure) {
                    errorCallback.invoke(gson.toJson(failure));
                }
            });
        }catch(Exception e){
            errorCallback.invoke(gson.toJson(e));
        }
    }

    @ReactMethod
    public void inituser(
            final String email,
            final String pass,
            final String username,
            final Callback successCallback,
            final Callback errorCallback
    ){
        try {
            if(isInitialized){
                successCallback.invoke("{}");
            }else{
                Exception exception = new RuntimeException("please call initAppgainSDK() first");
                errorCallback.invoke(gson.toJson(exception));
            }
        } catch (Exception e) {
            errorCallback.invoke(gson.toJson(e));
        }
    }

    @ReactMethod
    public void getuserId(final Callback successCallback,
                                 final Callback errorCallback
    ){
        try{
            try{
                String userId = Appgain.getUserId();
                if(userId != null && !userId.isEmpty()){
                    successCallback.invoke("{\"userId\":" + userId + "}");
                }else{
                    errorCallback.invoke("{\"message\": \"UserId is not found\"}");
                }
            }catch(Exception e){
                errorCallback.invoke(gson.toJson(e));
            }
        }catch(Exception e){
            errorCallback.invoke(gson.toJson(e));
        }
    }

    @ReactMethod
    public void fireAutomatorWithPersonalization(final String triggerPointName, final ReadableMap personalizationMap,
                              final Callback successCallback, final Callback errorCallback){
        try {
            HashMap<String, Object> objHashmap =personalizationMap.toHashMap();
            HashMap<String, String> strHashmap = new HashMap<>();
            for (Map.Entry<String, Object> entry : objHashmap.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                if(value != null){
                    strHashmap.put(key, value.toString());
                }else{
                    strHashmap.put(key, "");
                }
            }
            Appgain.fireAutomator(triggerPointName, strHashmap, new AppgainDataCallback<Void>() {
                @Override
                public void onSuccess(Void data) {
                    successCallback.invoke("{}");
                }

                @Override
                public void onFailure(BaseResponse failure) {
                    errorCallback.invoke(gson.toJson(failure));
                }
            });
        } catch (Exception e) {
            errorCallback.invoke(gson.toJson(e));
        }
    }

    @ReactMethod
    public void fireAutomator(final String triggerPointName, final Callback successCallback, final Callback errorCallback){
        try {
            Map<String,String> personalizationMap = new HashMap<>();
            Appgain.fireAutomator(triggerPointName, personalizationMap, new AppgainDataCallback<Void>() {
                @Override
                public void onSuccess(Void data) {
                    successCallback.invoke("{}");
                }

                @Override
                public void onFailure(BaseResponse failure) {
                    errorCallback.invoke(gson.toJson(failure));
                }
            });
        } catch (Exception e) {
            errorCallback.invoke(gson.toJson(e));
        }
    }


    @ReactMethod
    public void matchLink(final Callback successCallback, final Callback errorCallback){
        try {
            Appgain.matchLink(new AppgainDataCallback<DeferredDeepLinkingResponse>() {
                @Override
                public void onSuccess(DeferredDeepLinkingResponse response) {
                    successCallback.invoke(new Gson().toJson(response));
                }

                @Override
                public void onFailure(BaseResponse failure) {
                    errorCallback.invoke(gson.toJson(failure));
                }
            });
        } catch (Exception e) {
            errorCallback.invoke(gson.toJson(e));
        }
    }

    @ReactMethod
    public void addPurchase(String productName, float amount, String curruncy, final Callback successCallback, final Callback errorCallback){
        try{
            Appgain.logPurchase(productName, amount, curruncy, new AppgainDataCallback<Void>() {
                @Override
                public void onSuccess(Void data) {
                    successCallback.invoke("{}");
                }

                @Override
                public void onFailure(BaseResponse failure) {
                    errorCallback.invoke(gson.toJson(failure));
                }
            });
        }catch(Exception e){
            errorCallback.invoke(gson.toJson(e));
        }
    }

    @ReactMethod
    public void addNotificationChannel(final String type, final String item, final Callback successCallback, final Callback errorCallback){
        try {
            Appgain.createNotificationChannel(type, item, new AppgainDataCallback<Void>() {
                    @Override
                    public void onSuccess(Void data) {
                        successCallback.invoke("{}");
                    }

                    @Override
                    public void onFailure(BaseResponse failure) {
                        errorCallback.invoke(gson.toJson(failure));

                    }
                });

        } catch (Exception e) {
            errorCallback.invoke(gson.toJson(e));
        }
    }


    @ReactMethod
    public void logEvent(final String type, final String action, final ReadableMap extras, final Callback successCallback, final Callback errorCallback){
        try {
            HashMap<String, Object> objHashmap =extras.toHashMap();
            Bundle bundle = new Bundle();
            for (Map.Entry<String, Object> entry : objHashmap.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                if(value != null){
                    bundle.putString(key, value.toString());
                }else{
                    bundle.putString(key, "");
                }
            }
            Appgain.logEvent(type, action, bundle, new AppgainDataCallback<Void>() {
                @Override
                public void onSuccess(Void data) {
                    successCallback.invoke("{}");
                }

                @Override
                public void onFailure(BaseResponse failure) {
                    errorCallback.invoke(gson.toJson(failure));
                }
            });
        } catch (Exception e) {
            errorCallback.invoke(gson.toJson(e));
        }
    }

    @ReactMethod
    public void setuserId(final String userId, final Callback successCallback, final Callback errorCallback){
        try {
            Appgain.updateUserId(userId, new AppgainDataCallback<String>(){
            @Override
            public void onFailure(BaseResponse failure) {
                errorCallback.invoke(gson.toJson(failure));
            }

            @Override
            public void onSuccess(String newUserId) {
                successCallback.invoke("{}");
            }
        });
        } catch (Exception e) {
            errorCallback.invoke(gson.toJson(e));
        }
    }

    private String getCurrentUserId() {
        return Appgain.getUserId();
    }


    @ReactMethod
    public void updateUserData(ReadableMap userData, final Callback successCallback, final Callback errorCallback){
        try {
            HashMap<String, Object> objHashmap = userData.toHashMap();
            HashMap<String, String> strHashmap = new HashMap<>();
            for (Map.Entry<String, Object> entry : objHashmap.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                if(value != null){
                    strHashmap.put(key, value.toString());
                }else{
                    strHashmap.put(key, "");
                }
            }
            Appgain.updateUserData(strHashmap, new AppgainDataCallback<Void>(){
                @Override
                public void onSuccess(Void data) {
                    successCallback.invoke("{}");
                }

                @Override
                public void onFailure(BaseResponse failure) {
                    errorCallback.invoke(gson.toJson(failure));
                }
            });
        } catch (Exception e) {
            errorCallback.invoke(gson.toJson(e));
        }
    }


}
