package com.iqi.responsys;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.telecom.Call;
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.Callback;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.google.firebase.FirebaseApp;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.pushio.manager.PIOBadgeSyncListener;
import com.pushio.manager.PIOBeaconRegion;
import com.pushio.manager.PIODeepLinkListener;
import com.pushio.manager.PIOGeoRegion;
import com.pushio.manager.PIOInteractiveNotificationButton;
import com.pushio.manager.PIOInteractiveNotificationCategory;
import com.pushio.manager.PIOMCMessage;
import com.pushio.manager.PIOMCMessageError;
import com.pushio.manager.PIOMCMessageListener;
import com.pushio.manager.PIOMCRichContentListener;
import com.pushio.manager.PIORegionCompletionListener;
import com.pushio.manager.PIORegionEventType;
import com.pushio.manager.PIORegionException;
import com.pushio.manager.PIORsysIAMHyperlinkListener;
import com.pushio.manager.PushIOActivityLauncher;
import com.pushio.manager.PushIOManager;
import com.pushio.manager.PushIONotificationServiceType;
import com.pushio.manager.exception.PIOMCMessageException;
import com.pushio.manager.exception.PIOMCRichContentException;
import com.pushio.manager.exception.ValidationException;
import com.pushio.manager.preferences.PushIOPreference;
import com.pushio.manager.tasks.PushIOEngagementListener;
import com.pushio.manager.tasks.PushIOListener;
import com.pushio.manager.tasks.PushIONotificationServiceDiscoveryListener;
import com.pushio.manager.BuildConfig;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.google.firebase.messaging.RemoteMessage;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.messaging.FirebaseMessaging;

public class ResponsysModule extends ReactContextBaseJavaModule implements LifecycleEventListener {

    private static ReactApplicationContext reactContext;
    private static String TAG = "Responsys";
    private static Boolean isOn = false, isRegister = false;
    private static final String DURATION_SHORT_KEY = "SHORT";
    private static final String DURATION_LONG_KEY = "LONG";
    PushIOManager pushIOManager;
    private static boolean isLocation = true;
    private static String deviceId = "", userId = "";
    private List<Messages> allPreferences;
    private List<PIOMCMessage> piomcMessageList;
    private List<PushIOPreference> pushIOPreferences;
    Preferences preferences;
    PushIONotificationServiceType pushIONotificationServiceType;
    private BroadcastReceiver mBroadcastReceiver;
    static boolean handleMessage = true;

    private final BroadcastReceiver mHeadsetPlugReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
//            if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
//                boolean plugged = (intent.getIntExtra("state", 0) == 1);
//                String message = plugged ? "Headset plugged in" : "Headset plugged out";
//                Toast.makeText(reactContext, message, Toast.LENGTH_SHORT).show();
//            }
            Bundle extras = getResultExtras(true);
            extras.putInt(PushIOManager.PUSH_STATUS, PushIOManager.PUSH_HANDLED_IN_APP);
            setResultExtras(extras);
            this.abortBroadcast();
        }
    };

    public ResponsysModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
        pushIOManager = PushIOManager.getInstance(getReactApplicationContext());
        registerBroadcastReceiver();
    }

    private void registerBroadcastReceiver() {
//        IntentFilter filter = new IntentFilter();
//        filter.addAction(Intent.ACTION_HEADSET_PLUG);
        reactContext.registerReceiver(mHeadsetPlugReceiver, new IntentFilter("${applicationId}.PUSHIOPUSH") );
    }

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

    @ReactMethod
    public void remoteMessage(Promise promise){
        try {
            final WritableMap[] messageMap = {null};
            final RemoteMessage[] message = null;
            promise.resolve(message);
        }catch (Exception e){
            promise.reject("Remote Message Null", e);
        }
    }

    @ReactMethod
    public void startTracking(){
        registerBroadcastReceiver();
    }

    @ReactMethod
    public void sampleMethod(String stringArgument, int numberArgument, Callback callback) {
        // TODO: Implement some actually useful functionality
        callback.invoke("Received numberArgument: " + numberArgument + " stringArgument: " + stringArgument);
    }

    public PushIOManager getPushIOManager() {
        return PushIOManager.getInstance(getReactApplicationContext());
    }

    public PIODeepLinkListener pioDeepLinkListener(){
        String result = "";
        return new PIODeepLinkListener(){

            @Override
            public void onDeepLinkReceived(String s, String s1) {
                emitDeviceEvent("onDeepLinkReceived", ""+s+"|"+s1);
            }
        };
    }

    @ReactMethod
    public void trackEvent(String event) {
        pushIOManager.trackEvent(event);
    }

    @ReactMethod
    public void initializeApp(){
        pushIOManager = PushIOManager.getInstance(getReactApplicationContext());
        pushIOManager.setInAppFetchEnabled(true);
        pushIOManager.isMessageCenterEnabled();
        pushIOManager.setMessageCenterEnabled(true);
        pushIOManager.registerPushIONotificationServiceDiscoveryListener(new PushIONotificationServiceDiscoveryListener() {
            @Override
            public void onNotificationServiceAvailable(String s) {
                Log.i(TAG, "onNotificationServiceAvailable Dalam : "+s);
            }

            @Override
            public void onNotificationServicesUnavailable(Bundle bundle) {
                Log.i(TAG, "onNotificationServicesUnavailable Dalam : "+bundle.toString());
            }
        });
        pushIONotificationServiceType = new PushIONotificationServiceType();
        Log.i(TAG, "initializeApp: "+pushIONotificationServiceType.toString());
        pushIOManager.setNotificationsStacked(true);
        pushIOPreferences = pushIOManager.getPreferences();
        allPreferences = new ArrayList<>();
        piomcMessageList = new ArrayList<>();
    }

    @ReactMethod
    public void registerPushIOListener(){
        try{
//            pushIOManager.registerPushIOListener(this);
            pushIOManager.registerPushIOListener(new PushIOListener() {
                @Override
                public void onPushIOSuccess() {
                    emitDeviceEvent("registerPushIOListener", "");
                }

                @Override
                public void onPushIOError(String s) {
                    emitDeviceEvent("registerPushIOListener", ""+s);
                }
            });
        }catch (Exception e){

        }
    }

    @ReactMethod
    public void declarePreference(String key, String isian, String type){
        try
        {
            if(type.equalsIgnoreCase("boolean"))
                pushIOManager.declarePreference(key, isian, PushIOPreference.Type.BOOLEAN);  // (key, label, preferenceType)
            if(type.equalsIgnoreCase("string"))
                pushIOManager.declarePreference(key, isian, PushIOPreference.Type.STRING);
            if(type.equalsIgnoreCase("number"))
                pushIOManager.declarePreference(key, isian, PushIOPreference.Type.NUMBER);
        }
        catch(ValidationException ex)
        {
            // Handle exception
        }
    }

    @ReactMethod
    public void trackEngagement(String engagement){
        if(engagement.equalsIgnoreCase("PUSHIO_ENGAGEMENT_METRIC_INAPP_PURCHASE"))
            pushIOManager.trackEngagement(PushIOManager.PUSHIO_ENGAGEMENT_METRIC_INAPP_PURCHASE);
        if(engagement.equalsIgnoreCase("PUSHIO_ENGAGEMENT_METRIC_PREMIUM_CONTENT"))
            pushIOManager.trackEngagement(PushIOManager.PUSHIO_ENGAGEMENT_METRIC_PREMIUM_CONTENT);
        if(engagement.equalsIgnoreCase("PUSHIO_ENGAGEMENT_METRIC_SOCIAL"))
            pushIOManager.trackEngagement(PushIOManager.PUSHIO_ENGAGEMENT_METRIC_SOCIAL);
        if(engagement.equalsIgnoreCase("PUSHIO_ENGAGEMENT_METRsetInAppFetchEnabledIC_OTHER"))
            pushIOManager.trackEngagement(PushIOManager.PUSHIO_ENGAGEMENT_METRIC_OTHER);
        if(engagement.equalsIgnoreCase("PUSHIO_ENGAGEMENT_METRIC_PURCHASE"))
            pushIOManager.trackEngagement(PushIOManager.PUSHIO_ENGAGEMENT_METRIC_PURCHASE);
        if(engagement.equalsIgnoreCase("PUSHIO_ENGAGEMENT_METRIC_ACTIVE_SESSION"))
            pushIOManager.trackEngagement(PushIOManager.PUSHIO_ENGAGEMENT_METRIC_ACTIVE_SESSION);
    }

    @ReactMethod
    public void resetEID(){
        pushIOManager.resetEID();
    }

    @ReactMethod
    public void getPreference(Callback successCallback){
        List<PushIOPreference> allPreferences = pushIOManager.getPreferences();
        WritableArray array = new WritableNativeArray();
        for(int i=0; i<allPreferences.size(); i++){
            preferences = new Preferences();
            preferences.setHasil((String) pushIOPreferences.get(i).getValue());
            preferences.setKey(pushIOPreferences.get(i).getKey());
            preferences.setLabel(pushIOPreferences.get(i).getLabel());
            preferences.setTipe(pushIOPreferences.get(i).getType().toString());

        }
        Log.i(TAG, "getPreference: "+pushIOPreferences.get(0));
        successCallback.invoke(null, "test");
    }

    @ReactMethod
    public void getPreference(String kunci, Callback successCallback){
        Log.i(TAG, "getPreference: "+pushIOManager.getPreference(kunci));
        successCallback.invoke(null, pushIOManager.getPreference(kunci));
    }

    @ReactMethod
    public void clearAllPreferences(){
        pushIOManager.clearAllPreferences();
    }

    @ReactMethod
    public void getPreferences(Callback callback){
        Log.i(TAG, "getPreference: ");
        Gson g = new GsonBuilder().serializeNulls().create();
        WritableArray array = new WritableNativeArray();
        List<PushIOPreference> allPreferences = pushIOManager.getPreferences();
        for (PushIOPreference co : allPreferences) {
            try {
                JSONObject jo = new JSONObject(g.toJson(co));
                WritableMap wm = null;
                wm = convertJsonToMap(jo);
                array.pushMap(wm);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        Log.i(TAG, "getPreference: "+array);
        callback.invoke(null, array);
    }

    @ReactMethod
    public void setPreference(String Item, String isi, String type){
        try {
            if(type.equalsIgnoreCase("boolean")) {
                Boolean xx;
                if(isi.equalsIgnoreCase("true"))
                    xx = true;
                else
                    xx = false;
                pushIOManager.setPreference(Item, xx);
            }
            if(type.equalsIgnoreCase("string")) {
                pushIOManager.setPreference(Item, isi);
            }
            if(type.equalsIgnoreCase("number")) {
                Float aDouble = Float.parseFloat(isi);
                pushIOManager.setPreference(Item, aDouble);
            }
        }catch (ValidationException e){
            Log.e(TAG, "setPreference error : "+e.getMessage() );
        }
    }

    @ReactMethod
    public void setPushNotificationEnable(boolean val){
        handleMessage = val;
    }

    @ReactMethod
    public void getStatus(Callback successCallback) {
        successCallback.invoke(null, isRegister);
    }

    private WritableMap convertJsonToMap(JSONObject jsonObject) throws JSONException {
        WritableMap map = new WritableNativeMap();

        Iterator<String> iterator = jsonObject.keys();
        while (iterator.hasNext()) {
            String key = iterator.next();
            Object value = jsonObject.get(key);
            Log.i(TAG, "convertJsonToMap: "+key+" --> "+value);
            if (value instanceof JSONObject) {
                map.putMap(key, convertJsonToMap((JSONObject) value));
            } else if (value instanceof JSONArray) {
                map.putArray(key, convertJsonToArray((JSONArray) value));
                if(("option_values").equals(key)) {
                    map.putArray("options", convertJsonToArray((JSONArray) value));
                }
            } else if (value instanceof Boolean) {
                map.putBoolean(key, (Boolean) value);
            } else if (value instanceof Integer) {
                map.putInt(key, (Integer) value);
            } else if (value instanceof Double) {
                map.putDouble(key, (Double) value);
            } else if (value instanceof String)  {
                map.putString(key, (String) value);
            } else {
                map.putString(key, value.toString());
            }
        }
        return map;
    }

    private WritableArray convertJsonToArray(JSONArray jsonArray) throws JSONException {
        WritableArray array = new WritableNativeArray();

        for (int i = 0; i < jsonArray.length(); i++) {
            Object value = jsonArray.get(i);
            if (value instanceof JSONObject) {
                array.pushMap(convertJsonToMap((JSONObject) value));
            } else if (value instanceof JSONArray) {
                array.pushArray(convertJsonToArray((JSONArray) value));
            } else if (value instanceof Boolean) {
                array.pushBoolean((Boolean) value);
            } else if (value instanceof Integer) {
                array.pushInt((Integer) value);
            } else if (value instanceof Double) {
                array.pushDouble((Double) value);
            } else if (value instanceof String)  {
                array.pushString((String) value);
            } else {
                array.pushString(value.toString());
            }
        }
        return array;
    }

    private JSONObject convertMapToJson(ReadableMap readableMap) throws JSONException {
        JSONObject object = new JSONObject();
        ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
        while (iterator.hasNextKey()) {
            String key = iterator.nextKey();
            switch (readableMap.getType(key)) {
                case Null:
                    object.put(key, JSONObject.NULL);
                    break;
                case Boolean:
                    object.put(key, readableMap.getBoolean(key));
                    break;
                case Number:
                    object.put(key, readableMap.getDouble(key));
                    break;
                case String:
                    object.put(key, readableMap.getString(key));
                    break;
                case Map:
                    object.put(key, convertMapToJson(readableMap.getMap(key)));
                    break;
                case Array:
                    object.put(key, convertArrayToJson(readableMap.getArray(key)));
                    break;
            }
        }
        return object;
    }

    private JSONArray convertArrayToJson(ReadableArray readableArray) throws JSONException {

        JSONArray array = new JSONArray();

        for (int i = 0; i < readableArray.size(); i++) {
            switch (readableArray.getType(i)) {
                case Null:
                    break;
                case Boolean:
                    array.put(readableArray.getBoolean(i));
                    break;
                case Number:
                    array.put(readableArray.getDouble(i));
                    break;
                case String:
                    array.put(readableArray.getString(i));
                    break;
                case Map:
                    array.put(convertMapToJson(readableArray.getMap(i)));
                    break;
                case Array:
                    array.put(convertArrayToJson(readableArray.getArray(i)));
                    break;
            }
        }
        return array;
    }

    @ReactMethod
    public void setMessageCenterEnabled(boolean xx){
        try{
            pushIOManager.setMessageCenterEnabled(xx);
        }catch (Exception e){
            Log.e(TAG, "setMessageCenterEnabled: "+e.getMessage() );
        }
    }

    @ReactMethod
    public void setCrashLoggingEnabled(boolean yy){
        pushIOManager.setCrashLoggingEnabled(yy);
    }

    @ReactMethod
    public void setChannel(String isian){
        try{
            if(isian.equalsIgnoreCase("i")) {
                pushIOManager.setRIAppId(isian);
                pushIOManager.setNotificationsStacked(false);
                Log.i(TAG, "setChannel: "+pushIOManager.getNotificationStacked());
            }
            else {
                pushIOManager.setNotificationsStacked(true);
                Log.i(TAG, "setChannel: "+pushIOManager.getNotificationStacked());
                pushIOManager.setRIAppId(isian);
                Log.i(TAG, "setChannel: " + pushIOManager.getRIAppId());
            }
        }catch (Exception e){
            Log.e(TAG, "setChannel: "+e.getMessage() );
        }
    }

    @ReactMethod
    public void getBadgeCount(Callback callback){
        try{
            callback.invoke(null, pushIOManager.getBadgeCount());
        }catch (Exception e){
            callback.invoke(e.getMessage(), 0);
        }
    }

    @ReactMethod
    public void resetBadgeCount(boolean b, final Callback successCallback){
        try{
            pushIOManager.resetBadgeCount(b, new PIOBadgeSyncListener(){

                @Override
                public void onBadgeSyncedSuccess(String s) {
                    successCallback.invoke(null, s);
                }

                @Override
                public void onBadgeSyncedFailure(String s) {
                    successCallback.invoke(s, null);
                }
            });
        }catch (Exception e){

        }
    }

    @ReactMethod
    public void setBadgeCount(int badgeCount, boolean b){
        try{
            pushIOManager.setBadgeCount(badgeCount, b, new PIOBadgeSyncListener(){

                @Override
                public void onBadgeSyncedSuccess(String s) {
                    emitDeviceEvent("PIOBadgeSyncListener", ""+s);
                }

                @Override
                public void onBadgeSyncedFailure(String s) {
                    emitDeviceEvent("PIOBadgeSyncListener", ""+s);
                }
            });
        }catch (Exception e){

        }
    }

    @ReactMethod
    public void setMessageCenterBadgingEnabled(boolean messageCenterBadgingEnabled){
        try{
            pushIOManager.setMessageCenterBadgingEnabled(messageCenterBadgingEnabled);
        }catch (Exception e){

        }
    }

    @ReactMethod
    public void fetchRichContentForMessage(String messageId, final Callback successCallback){
        try {
            pushIOManager.fetchRichContentForMessage
                    (messageId, new PIOMCRichContentListener() {
                        @Override
                        public void onSuccess(String messageId, String richContentHtml) {
                            successCallback.invoke(null, richContentHtml);
                            emitDeviceEvent("PIOMCRichContentListener", messageId+"|"+richContentHtml);
                        }

                        @Override
                        public void onFailure(String messageId, PIOMCMessageError piomcMessageError) {
                            successCallback.invoke(piomcMessageError,null);
                            sendEvent("PIOMCRichContentListener", piomcMessageError);
                        }
                    });
        } catch (PIOMCRichContentException e) {
            e.printStackTrace();
        }
    }

    @ReactMethod
    public void setDefaultSmallIcon(int smallIcon){
        pushIOManager.setDefaultSmallIcon(smallIcon);
    }

    @ReactMethod
    public void setDefaultLargeIcon(int largeIcon){
        pushIOManager.setDefaultLargeIcon(largeIcon);
    }

    @ReactMethod
    public void fetchMessagesForMessageCenter(String msgCenter, final Callback successCallback){
        try {
            pushIOManager.isMessageCenterEnabled();
            pushIOManager.setMessageCenterEnabled(true);
//            pushIOManager.fetchMessagesForMessageCenter(null, (PIOMCMessageListener) this);
            pushIOManager.fetchMessagesForMessageCenter(msgCenter, new PIOMCMessageListener() {
                @Override
                public void onSuccess(String s, List<PIOMCMessage> list) {
                    Log.i(TAG, "onSuccess dalem: "+s+", "+list.size()+", "+list);
                    piomcMessageList = list;
                    Gson g = new GsonBuilder().serializeNulls().create();
                    WritableArray array = new WritableNativeArray();

                    for(int i=0;i<list.size();i++){
                        Messages messages = new Messages();
                        messages.setDeeplinkUrl(list.get(i).getDeeplinkUrl());
                        messages.setExpiryTimestamp(list.get(i).getExpiryTimestamp());
                        messages.setIconUrl(list.get(i).getIconUrl());
                        messages.setId(list.get(i).getId());
                        messages.setMessage(list.get(i).getMessage());
                        messages.setMessageCenterName(list.get(i).getMessageCenterName());
                        messages.setRichMessageHtml(list.get(i).getRichMessageHtml());
                        messages.setRichMessageUrl(list.get(i).getRichMessageUrl());
                        messages.setSentTimestamp(list.get(i).getSentTimestamp());
                        messages.setSubject(list.get(i).getSubject());
                        messages.setType("responsys");
                        for(Messages messages1 : allPreferences){
                            if(messages1.getId() != list.get(i).getId()){
                                allPreferences.add(messages);
                            }
                        }
                    }
                    for (PIOMCMessage co : piomcMessageList) {
                        Log.i(TAG, "onSuccess: "+co.getDeeplinkUrl());
                        Log.i(TAG, "onSuccess: "+co.getIconUrl());
                        Log.i(TAG, "onSuccess: "+co.getId());
                        Log.i(TAG, "onSuccess: "+co.getMessage());
                        Log.i(TAG, "onSuccess: "+co.getMessageCenterName());
                        Log.i(TAG, "onSuccess: "+co.getRichMessageUrl());
                        Log.i(TAG, "onSuccess: "+co.getSubject());
                        Log.i(TAG, "onSuccess: "+co.getRichMessageHtml());
                        Log.i(TAG, "onSuccess: "+co.getExpiryTimestamp());
                        Log.i(TAG, "onSuccess: "+co.getSentTimestamp());
                        try {
                            JSONObject jo = new JSONObject(g.toJson(co));
                            WritableMap wm = null;
                            wm = convertJsonToMap(jo);
                            array.pushMap(wm);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                    successCallback.invoke(null, array);
                    sendEvent("PIOMCMessageListener", array);
                }

                @Override
                public void onFailure(String s, PIOMCMessageError piomcMessageError) {
                    Log.e(TAG, "onFailure: "+s+", "+piomcMessageError.getErrorMessage() );
                    successCallback.invoke(piomcMessageError.getErrorMessage(), null);
                    sendEvent("PIOMCMessageListener", piomcMessageError);
                }
            });
        }catch (PIOMCMessageException e){
            Log.e(TAG, "onCreate: PIOMCMessageException --> "+e.getMessage() );
            successCallback.invoke(e.getMessage(), null);
            sendEvent("PIOMCMessageListener", e.getMessage());
        }
    }

    @ReactMethod
    public void getDeviceId(Callback successCallback) {
        deviceId = pushIOManager.getDeviceId();
        successCallback.invoke(null, deviceId);
    }

    @ReactMethod
    public void getRegisteredCategories(Callback callback){
        try{
            Gson g = new GsonBuilder().serializeNulls().create();
            WritableArray array = new WritableNativeArray();
            List<String> strings = pushIOManager.getRegisteredCategories();
            for (String co : strings) {
                try {
                    JSONObject jo = new JSONObject(g.toJson(co));
                    WritableMap wm = null;
                    wm = convertJsonToMap(jo);
                    array.pushMap(wm);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
            Log.i(TAG, "getPreference: "+array);
            callback.invoke(null, array);
        }catch (Exception e){
            callback.invoke(e.getMessage(), null);
        }
    }

    @ReactMethod
    public void getUserId(Callback successCallback) {
        successCallback.invoke(null, userId);
    }

    @ReactMethod
    public void setLogLevel(String logLevel){
        if(logLevel.equalsIgnoreCase("info"))
            pushIOManager.setLogLevel(Log.INFO);
        if(logLevel.equalsIgnoreCase("verbose"))
            pushIOManager.setLogLevel(Log.VERBOSE);
        if(logLevel.equalsIgnoreCase("debug"))
            pushIOManager.setLogLevel(Log.DEBUG);
        if(logLevel.equalsIgnoreCase("error"))
            pushIOManager.setLogLevel(Log.ERROR);
        if(logLevel.equalsIgnoreCase("warn"))
            pushIOManager.setLogLevel(Log.WARN);
        if(logLevel.equalsIgnoreCase("assert"))
            pushIOManager.setLogLevel(Log.ASSERT);
    }


    @ReactMethod
    public void registerApp(){
        pushIOManager = PushIOManager.getInstance(getReactApplicationContext());
        pushIOManager.setInAppFetchEnabled(true);
        pushIOManager.isMessageCenterEnabled();
        pushIOManager.setMessageCenterEnabled(true);
        pushIONotificationServiceType = new PushIONotificationServiceType();
        Log.i(TAG, "initializeApp: "+pushIONotificationServiceType.toString());
        pushIOManager.setNotificationsStacked(true);
        pushIOPreferences = pushIOManager.getPreferences();
        allPreferences = new ArrayList<>();
        piomcMessageList = new ArrayList<>();
        pushIOManager.registerApp(isLocation);
        deviceId = pushIOManager.getDeviceId();
    }

    @ReactMethod
    public void registerUserId(String userId){
        pushIOManager.registerUserId(userId);
        isRegister = true;
    }

    @ReactMethod
    public void getRegisteredUserId(Callback successCallback) {
        try {
            userId = pushIOManager.getRegisteredUserId();
            successCallback.invoke(null, userId);
        }catch (Exception e){
            successCallback.invoke(e.getMessage(), null);
        }
    }

    @ReactMethod
    public void unregisterUserId(){
        pushIOManager.unregisterUserId();
        isRegister = false;
    }

    @ReactMethod
    public void trackEmailConversion(){
        Log.d(TAG, "trackEmailConversion: ");
        pushIOManager.trackEmailConversion(getCurrentActivity().getIntent());
    }

    private void emitDeviceEvent(String eventName, String message) {
      Log.i("GET", "GET " + message);
      reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, message);
    }

    public static void sendEvent(String event, Object body) {
        reactContext.
                getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit(event, body);
    }

    @ReactMethod
    public void addInteractiveNotificationCategory(String categoryId, String buttonId1, String buttonIdLabel, String buttonId2, String buttonId2Label){
        try{
            PIOInteractiveNotificationCategory interactiveNotificationCategory = new PIOInteractiveNotificationCategory();
            interactiveNotificationCategory.setCategory(categoryId);

            PIOInteractiveNotificationButton button1 = new PIOInteractiveNotificationButton();
            button1.setId(buttonId1);
            button1.setLabel(buttonIdLabel);
            button1.setAction("BG");
            interactiveNotificationCategory.addInteractiveNotificationButton(button1);

            PIOInteractiveNotificationButton button2 = new PIOInteractiveNotificationButton();
            button2.setId(buttonId2);
            button2.setLabel(buttonId2Label);
            interactiveNotificationCategory.addInteractiveNotificationButton(button2);

            pushIOManager.addInteractiveNotificationCategory(interactiveNotificationCategory);
        }catch (Exception e){
            Log.e(TAG, "addInteractiveNotificationCategory Exception: "+e.getMessage() );
        }
    }

    @ReactMethod
    public void getInteractiveNotificationCategory(String categoryId, Callback successCallback){
        PIOInteractiveNotificationCategory notificationCategory = pushIOManager.getInteractiveNotificationCategory(categoryId);
        successCallback.invoke(null, notificationCategory);
    }

    @ReactMethod
    public void deleteInteractiveNotificationCategory(String categoryId, Callback callback){
        boolean result = pushIOManager.deleteInteractiveNotificationCategory(categoryId);
        callback.invoke(null, result);
    }

    @ReactMethod
    public void setExecuteRsysWebUrl(boolean executeRsysWebUrl){
        if(executeRsysWebUrl){
            pushIOManager.setExecuteRsysWebUrl(true, new PIORsysIAMHyperlinkListener() {
                @Override
                public void onSuccess(String requestUrl, String deeplinkUrl, String weblinkUrl) {
                    emitDeviceEvent("PIORsysIAMHyperlinkListener", ""+requestUrl+"|"+deeplinkUrl+"|"+weblinkUrl);
                }

                @Override
                public void onFailure(String requestUrl, String reason) {
                    emitDeviceEvent("PIORsysIAMHyperlinkListener", ""+requestUrl+"|"+reason);
                }
            });
        }
        else {
            pushIOManager.setExecuteRsysWebUrl(false, null);
        }
    }

    @ReactMethod
    public void setAdvertisingID(String advertisingID){
        pushIOManager.setAdvertisingID(advertisingID);
    }

    @ReactMethod
    public void getAdvertisingID(Callback callback){
        callback.invoke(null, pushIOManager.getAdvertisingID());
    }

    @ReactMethod
    public void setExternalDeviceTrackingID(String deviceId){
        pushIOManager.setExternalDeviceTrackingID(deviceId);
    }

    @ReactMethod
    public void getExternalDeviceTrackingID(Callback callback){
        callback.invoke(null, pushIOManager.getExternalDeviceTrackingID());
    }

    @ReactMethod
    public void getAPIKey(Callback callback){
        callback.invoke(null, pushIOManager.getAPIKey());
    }

    @ReactMethod
    public void onGeoRegionEntered(String source, String zoneId, String zoneName, String geofenceId, String geofenceName,
                                   Double deviceSpeed, Double deviceBearing, ReadableMap extra){
        String area = extra.getString("area");
        String category = extra.getString("category");
        Map<String, String> deconstructedMap = new HashMap<>();
        deconstructedMap.put("area", area);
        deconstructedMap.put("category", category);
        PIOGeoRegion geoRegion = new PIOGeoRegion();
        geoRegion.setGeofenceId(geofenceId);
        geoRegion.setGeofenceName(geofenceName);
        geoRegion.setZoneId(zoneId);
        geoRegion.setSource(source);
        geoRegion.setZoneName(zoneName);
        geoRegion.setDeviceSpeed(deviceSpeed);
        geoRegion.setDeviceBearing(deviceBearing);
        geoRegion.setExtra(deconstructedMap);
        pushIOManager.onGeoRegionEntered
                (geoRegion, new PIORegionCompletionListener() {
                    @Override
                    public void onRegionReported(String s, PIORegionEventType pioRegionEventType, PIORegionException e) {
                        emitDeviceEvent("PIORegionCompletionListener", ""+s+"|"+pioRegionEventType+"|"+e);
                    }
                });
    }

    @ReactMethod
    public void onGeoRegionExited(String source, String zoneId, String zoneName, String geofenceId, String geofenceName,
                                  Double deviceSpeed, Double deviceBearing, ReadableMap extra){
        ReadableMapKeySetIterator iterator = extra.keySetIterator();
        String area = extra.getString("area");
        String category = extra.getString("category");
        Map<String, String> deconstructedMap = new HashMap<>();
        deconstructedMap.put("area", area);
        deconstructedMap.put("category", category);
        PIOGeoRegion geoRegion = new PIOGeoRegion();
        geoRegion.setGeofenceId(geofenceId);
        geoRegion.setGeofenceName(geofenceName);
        geoRegion.setZoneId(zoneId);
        geoRegion.setSource(source);
        geoRegion.setZoneName(zoneName);
        geoRegion.setDeviceSpeed(deviceSpeed);
        geoRegion.setDeviceBearing(deviceBearing);
        geoRegion.setExtra(deconstructedMap);
        pushIOManager.onGeoRegionExited
                (geoRegion, new PIORegionCompletionListener() {
                    @Override
                    public void onRegionReported(String s, PIORegionEventType pioRegionEventType, PIORegionException e) {
                        emitDeviceEvent("PIORegionCompletionListener", ""+s+"|"+pioRegionEventType+"|"+e);
                    }
                });
    }

    @ReactMethod
    public void onBeaconRegionEntered(String source, String zoneId, String zoneName, String beaconId, String beaconName,
                                      String beaconTag, String iBeaconUUID, String iBeaconMajor, String iBeaconMinor,
                                      String eddyStoneId1, String eddyStoneId2, String proximity, ReadableMap extra){
        ReadableMapKeySetIterator iterator = extra.keySetIterator();
        String area = extra.getString("area");
        String category = extra.getString("category");
        Map<String, String> deconstructedMap = new HashMap<>();
        deconstructedMap.put("area", area);
        deconstructedMap.put("category", category);
        PIOBeaconRegion beaconRegion = new PIOBeaconRegion();
        beaconRegion.setSource(source);
        beaconRegion.setZoneId(zoneId);
        beaconRegion.setZoneName(zoneName);
        beaconRegion.setBeaconTag(beaconTag);
        beaconRegion.setiBeaconUUID(iBeaconUUID);
        beaconRegion.setiBeaconMajor(iBeaconMajor);
        beaconRegion.setiBeaconMinor(iBeaconMinor);
        beaconRegion.setEddyStoneID1(eddyStoneId1);
        beaconRegion.setEddyStoneID2(eddyStoneId2);
        beaconRegion.setBeaconProximity(proximity);
        beaconRegion.setBeaconId(beaconId);
        beaconRegion.setBeaconName(beaconName);
        beaconRegion.setExtra(deconstructedMap);
        pushIOManager.onBeaconRegionEntered
                (beaconRegion, new PIORegionCompletionListener() {
                    @Override
                    public void onRegionReported(String s, PIORegionEventType pioRegionEventType, PIORegionException e) {
                        emitDeviceEvent("PIORegionCompletionListener", ""+s+"|"+pioRegionEventType+"|"+e);
                    }
                });
    }

    @ReactMethod
    public void onBeaconRegionExited(String source, String zoneId, String zoneName, String beaconId, String beaconName,
                                     String beaconTag, String iBeaconUUID, String iBeaconMajor, String iBeaconMinor,
                                     String eddyStoneId1, String eddyStoneId2, String proximity, ReadableMap extra){
        ReadableMapKeySetIterator iterator = extra.keySetIterator();
        String area = extra.getString("area");
        String category = extra.getString("category");
        Map<String, String> deconstructedMap = new HashMap<>();
        deconstructedMap.put("area", area);
        deconstructedMap.put("category", category);
        PIOBeaconRegion beaconRegion = new PIOBeaconRegion();
        beaconRegion.setSource(source);
        beaconRegion.setZoneId(zoneId);
        beaconRegion.setZoneName(zoneName);
        beaconRegion.setBeaconTag(beaconTag);
        beaconRegion.setiBeaconUUID(iBeaconUUID);
        beaconRegion.setiBeaconMajor(iBeaconMajor);
        beaconRegion.setiBeaconMinor(iBeaconMinor);
        beaconRegion.setEddyStoneID1(eddyStoneId1);
        beaconRegion.setEddyStoneID2(eddyStoneId2);
        beaconRegion.setBeaconProximity(proximity);
        beaconRegion.setBeaconId(beaconId);
        beaconRegion.setBeaconName(beaconName);
        beaconRegion.setExtra(deconstructedMap);
        pushIOManager.onBeaconRegionExited
                (beaconRegion, new PIORegionCompletionListener() {
                    @Override
                    public void onRegionReported(String s, PIORegionEventType pioRegionEventType, PIORegionException e) {
                        emitDeviceEvent("PIORegionCompletionListener", ""+s+"|"+pioRegionEventType+"|"+e);
                    }
                });
    }

    @ReactMethod
    public void setInAppFetchEnabled(boolean inAppFetchEnabled){
        pushIOManager.setInAppFetchEnabled(inAppFetchEnabled);
    }

    @Override
    public void onHostResume() {

    }

    @Override
    public void onHostPause() {

    }

    @Override
    public void onHostDestroy() {
        reactContext.unregisterReceiver(mHeadsetPlugReceiver);
    }


    private class MessageReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (getReactApplicationContext().hasActiveCatalystInstance()) {
                Log.d(TAG, "Received new message");

                RemoteMessage message = intent.getParcelableExtra("message");
                WritableMap messageMap = MessagingSerializer.parseRemoteMessage(message);

                Utils.sendEvent(getReactApplicationContext(), "messaging_message_received", messageMap);
            }
        }
    }

    private class RefreshTokenReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (getReactApplicationContext().hasActiveCatalystInstance()) {
                Log.d(TAG, "Received new messaging token.");
                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        String token = null;
                        String senderId = FirebaseApp.getInstance().getOptions().getGcmSenderId();

                        try {
                            token = FirebaseInstanceId
                                    .getInstance()
                                    .getToken(senderId, FirebaseMessaging.INSTANCE_ID_SCOPE);
                        } catch (IOException e) {
                            Log.d(TAG, "onNewToken error", e);
                        }

                        if (token != null) {
                            Log.d(TAG, "Sending new messaging token event.");
                            Utils.sendEvent(getReactApplicationContext(), "messaging_token_refreshed", token);
                        }
                    }
                });

                thread.start();
            }
        }
    }
}
