package com.withpersona.sdk2.reactnative;

import static com.withpersona.sdk2.reactnative.InquiryUtils.inquiryEventToMap;

import android.app.Activity;
import android.content.Intent;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.OptIn;

import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.withpersona.sdk2.inquiry.ExperimentalInlineApi;
import com.withpersona.sdk2.inquiry.ExperimentalInquiryApi;
import com.withpersona.sdk2.inquiry.Inquiry;
import com.withpersona.sdk2.inquiry.InquiryResponse;
import com.withpersona.sdk2.inquiry.OnInquiryEventListener;
import com.withpersona.sdk2.inquiry.inline_inquiry.InquiryEvent;

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

public class PersonaInquiryModule2 extends ReactContextBaseJavaModule
    implements ActivityEventListener {

  private static final int PERSONA_INQUIRY_REQUEST_CODE = 31416;
  private static final String DISABLE_PRESENTATION_ANIMATION = "disablePresentationAnimation";

  private boolean disablePresentationAnimation = false;

  private final ReactApplicationContext reactContext;

  public PersonaInquiryModule2(ReactApplicationContext reactContext) {
    super(reactContext);
    this.reactContext = reactContext;
    reactContext.addActivityEventListener(this);
    registerOnInquiryEventListener();
  }

  @Override
  public void onNewIntent(@NonNull Intent intent) {
    // Do nothing
  }

  @Override
  public void onActivityResult(
    @NonNull final Activity activity,
    final int requestCode,
    final int resultCode,
    @Nullable Intent data) {
    if (this.disablePresentationAnimation) {
      getCurrentActivity().overridePendingTransition(0, 0);
    }

    if (requestCode == PERSONA_INQUIRY_REQUEST_CODE) {
      InquiryResponse response = Inquiry.onActivityResult(data);

      new InquiryResultEmitter(reactContext).emitResponse(response);
    }
  }

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

  /**
   * Launch an Inquiry Flow. In order for ease of implementation, this will
   * not behave defensively and will assume that proper arguments are sent over
   * the React Native bridge.
   */
  @ReactMethod
  @SuppressWarnings("unused") // react uses this
  public void startInquiry(
      ReadableMap options
  ) {
    Activity currentActivity = reactContext.getCurrentActivity();
    Inquiry inquiry = InquiryUtils.newInquiryFromMap(options);

    this.disablePresentationAnimation = options.hasKey(DISABLE_PRESENTATION_ANIMATION) ? options.getBoolean(DISABLE_PRESENTATION_ANIMATION) : false;

    if (currentActivity != null && inquiry != null) {
      inquiry.start(currentActivity, PERSONA_INQUIRY_REQUEST_CODE);
      if (this.disablePresentationAnimation) {
        currentActivity.overridePendingTransition(0, 0);
      }
    }
  }

  @Override
  public Map<String, Object> getConstants() {
    final Map<String, Object> constants = new HashMap<>();
    constants.put("INQUIRY_SDK_VERSION", com.withpersona.sdk2.inquiry.BuildConfig.INQUIRY_SDK_VERSION);
    return constants;
  }

  @OptIn(markerClass = ExperimentalInquiryApi.class)
  private void registerOnInquiryEventListener() {
    Inquiry.Companion.setOnEventListener(new OnInquiryEventListener() {
      @OptIn(markerClass = ExperimentalInlineApi.class)
      @Override
      public void onEvent(@NonNull InquiryEvent inquiryEvent) {
        DeviceEventManagerModule.RCTDeviceEventEmitter jsModule = getJsModule();

        if (jsModule == null) {
          return;
        }

        ReadableMap map = inquiryEventToMap(inquiryEvent);
        
        if (map != null) {
          WritableMap params = Arguments.createMap();
          params.putMap("event", map);
          jsModule.emit("onEvent", params);
        }
      }
    });
  }

  @Nullable
  private DeviceEventManagerModule.RCTDeviceEventEmitter getJsModule() {
    try {
      return this.reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class);
    } catch (Exception e) {
      return null;
    }
  }
}
