// RNFraudProtectionModule.java

package com.microsoft.fraudprotection.reactlibrary;

import android.util.Log;

import androidx.annotation.NonNull;

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.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
import com.microsoft.fraudprotection.androidsdk.FraudProtection;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.Iterator;

public class RNFraudProtectionModule extends ReactContextBaseJavaModule {

    private final ReactApplicationContext reactContext;

    public RNFraudProtectionModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
    }

    @NonNull
    @Override
    public String getName() {
        return "RNFraudProtection";
    }

    @ReactMethod
    public void start(String instanceId, String baseUrl) {
        FraudProtection.start(reactContext, instanceId, baseUrl);
    }

    @ReactMethod
    public void stop() {
        FraudProtection.stop();
    }

    @ReactMethod
    public void send(String pageId) {
        FraudProtection.send(pageId);
    }

    @ReactMethod
    public void sendWithCallback(String pageId, Callback callback) {
        FraudProtection.send(pageId, (data, error) -> {
            callback.invoke(error, convertJsonToMap(data));
        });
    }

    @ReactMethod
    public void getSessionId(Callback callback) {
        callback.invoke(FraudProtection.getSessionId());
    }

    @ReactMethod
    public void getAttributes(Callback callback) {
        callback.invoke(convertJsonToMap(FraudProtection.getAttributes()));
    }

    private static WritableMap convertJsonToMap(JSONObject jsonObject) {
        if (jsonObject == null || jsonObject.length() == 0) {
            return null;
        }

        WritableMap map = new WritableNativeMap();
        try {
            Iterator<String> iterator = jsonObject.keys();
            while (iterator.hasNext()) {
                String key = iterator.next();
                Object value = jsonObject.get(key);
                if (value instanceof JSONObject) {
                    map.putMap(key, convertJsonToMap((JSONObject) value));
                } else if (value instanceof JSONArray) {
                    map.putArray(key, 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());
                }
            }
        } catch (Exception e) {
            Log.e(RNFraudProtectionModule.class.getSimpleName(), e.toString());
        }
        return map;
    }

    private static 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;
    }
}
