package com.reactnativefacetec;

import static java.util.UUID.randomUUID;

import android.content.Intent;
import android.app.Activity;
import android.util.Log;

import androidx.annotation.NonNull;

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.ActivityEventListener;
import com.facebook.react.bridge.BaseActivityEventListener;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.module.annotations.ReactModule;
import com.facetec.sdk.FaceTecSDK;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;

import Processors.AuthenticateProcessor;
import Processors.Config;
import Processors.LivenessCheckProcessor;
import Processors.NetworkingHelpers;
import Processors.PhotoIDMatchProcessor;
import Processors.Processor;
import Processors.ThemeHelpers;
import okhttp3.Call;
import okhttp3.Callback;

@ReactModule(name = FacetecModule.NAME)
public class FacetecModule extends ReactContextBaseJavaModule {
  public static final String NAME = "Facetec";
  public Processor latestProcessor;
  String latestExternalDatabaseRefID = "";
  public String DeviceKeyIdentifier = "";
  public String apiUrl = "";
  public ReadableMap messages;
  public boolean logo = true;
  private Promise photoPromise;
  private JSONObject result;
  private String tipo;
  private String url;
  private String token;

  private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener() {
    @Override
    public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
      super.onActivityResult(activity, requestCode, resultCode, data);

      try {
        photoPromise.resolve(result.toString());
      } catch (Exception e) {
        Log.d("debu", "catch");
        Log.d("debu", e.getMessage());
        photoPromise.resolve(null);
      }

      photoPromise = null;

      if (latestProcessor == null) {
        return;
      }

      // At this point, you have already handled all results in your Processor code.
      if (latestProcessor.isSuccess()) {
        // Reset the enrollment identifier.
        latestExternalDatabaseRefID = "";
      }
    }
  };

  public FacetecModule(ReactApplicationContext reactContext) {
    super(reactContext);
    reactContext.addActivityEventListener(mActivityEventListener);
  }

  @Override
  @NonNull
  public String getName() {
    return NAME;
  }


  @ReactMethod
  public void init(String DeviceKey, ReadableMap colors, ReadableMap messages, String apiUrl, boolean logo, Promise promise) {
    Log.d("INICIPU", "INICIPU");
    this.DeviceKeyIdentifier = DeviceKey;
    this.messages = messages;
    this.apiUrl = apiUrl;
    //Config.initializeFaceTecSDKFromAutogeneratedConfig(DeviceKey, promise, getReactApplicationContext());

    Config.initializeFaceTecSDKFromAutogeneratedConfig(DeviceKey, getReactApplicationContext(), success -> {
      if(success) {
        ThemeHelpers.setAppTheme(getReactApplicationContext(), "Config Wizard Theme", colors, logo);

        promise.resolve(true);
      } else {
        Log.d("INICIPU", "NO COMPLETION");
      }
    });
  }

  @ReactMethod
  public void liveness() {
    getSessionToken(new SessionTokenCallback() {
      @Override
      public void onSessionTokenReceived(String sessionToken) {
        latestProcessor = new LivenessCheckProcessor(sessionToken, getCurrentActivity());
      }
    });
  }

  @ReactMethod
  public void photoMatch(Promise promise) {
    Log.d("INICIPU", "PHOTOMATCH");
    String DeviceKeyIdentifier = this.DeviceKeyIdentifier;
    String apiUrl = this.apiUrl;
    ReadableMap messages = this.messages;

    getSessionToken(new SessionTokenCallback() {
      @Override
      public void onSessionTokenReceived(String sessionToken) {
        latestExternalDatabaseRefID = "ADELANTAR-" + randomUUID();
        photoPromise = promise;
        latestProcessor = new PhotoIDMatchProcessor(sessionToken, getCurrentActivity(), FacetecModule.this, DeviceKeyIdentifier, messages, apiUrl);
      }
    });
  }

  @ReactMethod
  public void authenticate(String externalID,Promise promise) {
    String DeviceKeyIdentifier = this.DeviceKeyIdentifier;

    getSessionToken(new SessionTokenCallback() {
      @Override
      public void onSessionTokenReceived(String sessionToken) {
        latestExternalDatabaseRefID = externalID;
        photoPromise = promise;
        latestProcessor = new AuthenticateProcessor(sessionToken, getCurrentActivity(), FacetecModule.this, DeviceKeyIdentifier);
      }
    });
  }

  public String getTipo() {
    return tipo;
  }

  public void setTipo(String tipo) {
    this.tipo = tipo;
  }

  public String getUrl() {
    return url;
  }

  public void setUrl(String url) {
    this.url = url;
  }

  public String getToken() {
    return token;
  }

  public void setToken(String token) {
    this.token = token;
  }

  interface SessionTokenCallback {
    void onSessionTokenReceived(String sessionToken);
  }

  public void getSessionToken(final SessionTokenCallback sessionTokenCallback) {
    // Do the network call and handle result
    okhttp3.Request request = new okhttp3.Request.Builder()
      .header("X-Device-Key", DeviceKeyIdentifier)
      .header("User-Agent", FaceTecSDK.createFaceTecAPIUserAgentString(""))
      .url(Config.BaseURL + "/session-token")
      .get()
      .build();

    NetworkingHelpers.getApiClient().newCall(request).enqueue(new Callback() {
      @Override
      public void onFailure(Call call, IOException e) {
        e.printStackTrace();
        Log.d("FaceTecSDKSampleApp", "Exception raised while attempting HTTPS call.");

        // If this comes from HTTPS cancel call, don't set the sub code to NETWORK_ERROR.
        if (!e.getMessage().equals(NetworkingHelpers.OK_HTTP_RESPONSE_CANCELED)) {

        }
      }

      @Override
      public void onResponse(Call call, okhttp3.Response response) throws IOException {
        String responseString = response.body().string();
        response.body().close();
        try {
          JSONObject responseJSON = new JSONObject(responseString);
          if (responseJSON.has("sessionToken")) {
            sessionTokenCallback.onSessionTokenReceived(responseJSON.getString("sessionToken"));
          } else {

          }
        } catch (JSONException e) {
          e.printStackTrace();
          Log.d("FaceTecSDKSampleApp", "Exception raised while attempting to parse JSON result.");

        }
      }
    });
  }

  public String getLatestExternalDatabaseRefID() {
    return latestExternalDatabaseRefID;
  }

  public void setResult(JSONObject result) {
    this.result = result;
  }

}
