package com.seonreactnativemobilewrapper;

import androidx.annotation.NonNull;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.module.annotations.ReactModule;

import java.util.UUID;

import io.seon.androidsdk.dto.SeonGeolocationConfig;
import io.seon.androidsdk.dto.SeonGeolocationConfigBuilder;
import io.seon.androidsdk.exception.BehaviouralMonitoringException;
import io.seon.androidsdk.exception.SeonException;
import io.seon.androidsdk.service.Seon;
import io.seon.androidsdk.service.SeonBuilder;
import io.seon.androidsdk.service.SeonCallbackWithGeo;
import com.seonreactnativemobilewrapper.NativeSeonReactNativeMobileWrapperSpec;

@ReactModule(name = SeonReactNativeMobileWrapperModule.NAME)
public class SeonReactNativeMobileWrapperModule extends NativeSeonReactNativeMobileWrapperSpec {
    public static final String NAME = "SeonReactNativeMobileWrapperSpec";
    // private final ReactApplicationContext reactContext;
    private Seon m_seon;
    private SeonGeolocationConfig mGeoConfig;

    public SeonReactNativeMobileWrapperModule(ReactApplicationContext reactContext) {
        super(reactContext);
        String sessionID = UUID.randomUUID().toString();
        m_seon = new SeonBuilder()
            .withContext(reactContext.getApplicationContext())
            .withSessionId(sessionID)
            .build();
        // Initialize default geolocation config
        mGeoConfig = new SeonGeolocationConfigBuilder().build();
    }

    @Override
    @NonNull
    public String getName() {
        return NAME;
    }

    @Override
    public void setSessionId(String sessionId, Promise promise) {
        try {
            m_seon.setSessionId(sessionId);
            promise.resolve(null);
        } catch (Exception e) {
            promise.reject("setSessionId", e);
        }
    }

    @Override
    public void setLoggingEnabled(boolean enabled, Promise promise) {
        try {
            m_seon.setLoggingEnabled(enabled);
            promise.resolve(null);
        } catch (Exception e) {
            promise.reject("setLoggingEnabled", e);
        }
    }

    @Override
    public void getFingerprintBase64(Promise seonCallback) {
        if (mGeoConfig != null && mGeoConfig.isGeolocationEnabled()) {
            try {
                m_seon.getFingerprintBase64(new SeonCallbackWithGeo() {
                    @Override
                    public void onComplete(String response) {
                        seonCallback.resolve(response);
                    }

                    @Override
                    public void onCompleteWithGeoFailure(String response, int geoStatusCode) {
                        seonCallback.reject("SEON_GEO_FAILURE_CODE:" + String.valueOf(geoStatusCode), 
                            "SEON_GEO_FAILURE_CODE: " + String.valueOf(geoStatusCode) + " RESPONSE:" + response);
                    }
                });
            } catch (Exception e) {
                seonCallback.reject("SEON_ERROR", e);
            }
        } else {
            try {
                m_seon.getFingerprintBase64(seonCallback::resolve);
            } catch (Exception e) {
                seonCallback.reject("SEON_ERROR", e);
            }
        }
    }

    @Override
    public void startBehaviourMonitoring(Promise promise) {
        try {
            m_seon.startBehaviourMonitoring();
            promise.resolve(null);
        } catch (Exception e) {
            promise.reject("BEHAVIOUR_ERROR", e);
        }
    }

    @Override
    public void stopBehaviourMonitoring(Promise promise) {
        try {
            m_seon.stopBehaviourMonitoring(fp -> {
                promise.resolve(fp);
            });
        } catch (BehaviouralMonitoringException e) {
            promise.reject("BEHAVIOUR_ERROR", e);
        } catch (SeonException e) {
            promise.reject("BEHAVIOUR_ERROR", e);
        }
    }

    @Override
    public void setGeolocationEnabled(boolean enabled, Promise promise) {
        m_seon.setGeolocationEnabled(enabled);
        promise.resolve(true);
    }

    @Override
    public void setGeoLocationConfig(ReadableMap config, Promise promise) {
        SeonGeolocationConfigBuilder configBuilder = new SeonGeolocationConfigBuilder();

        if (config.hasKey("geolocationEnabled")) {
            configBuilder.withGeolocationEnabled(config.getBoolean("geolocationEnabled"));
        }
        if (config.hasKey("prefetchEnabled")) {
            configBuilder.withPrefetchEnabled(config.getBoolean("prefetchEnabled"));
        }
        if (config.hasKey("geolocationServiceTimeoutMs")) {
            configBuilder.withGeolocationServiceTimeoutMs(config.getInt("geolocationServiceTimeoutMs"));
        }
        if (config.hasKey("maxGeoLocationCacheAgeSec")) {
            configBuilder.withMaxGeoLocationCacheAgeSec(config.getInt("maxGeoLocationCacheAgeSec"));
        }

        SeonGeolocationConfig seonGeolocationConfig = configBuilder.build();
        m_seon.setGeoLocationConfig(seonGeolocationConfig);
        mGeoConfig = seonGeolocationConfig;
        promise.resolve(true);
    }
}
