
package com.masteratul.exceptionhandler;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

import com.google.gson.Gson;
import com.masteratul.ErrorVO;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class ReactNativeExceptionHandlerModule extends ReactContextBaseJavaModule {

  private ReactApplicationContext reactContext;
    private Activity activity;
    private static Class errorIntentTargetClass = DefaultErrorScreen.class;
    private static NativeExceptionHandlerIfc nativeExceptionHandler;
    private Callback callbackHolder;
    private String screenName;

    public ReactNativeExceptionHandlerModule(ReactApplicationContext reactContext) {
    super(reactContext);
    this.reactContext = reactContext;
  }

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

  @ReactMethod
  public void setHandlerforNativeException(final String url,final String devJson) {

    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
      final String screen = screenName;
      @Override
      public void uncaughtException(Thread thread, Throwable throwable) {
        Log.e("sendNativeException", url);
        final String stackTraceString = Log.getStackTraceString(throwable);
        activity = getCurrentActivity();

        ErrorVO error = new ErrorVO();
        ErrorVO.Error e = new ErrorVO.Error();
        e.setMessage(stackTraceString);
        error.setCrashAt(new Date().toInstant().toString());
        error.setAppVersion((String)getBuildConfigValue(activity, "VERSION_NAME"));
        error.setAppId((String)getBuildConfigValue(activity, "APPLICATION_ID"));
        error.setEnv((String)getBuildConfigValue(activity, "BUILD_TYPE"));
        error.setError(e);
        error.setScreenName(screen);
        ErrorVO.DeviceInfo dev=new Gson().fromJson(devJson,ErrorVO.DeviceInfo.class);
        error.setDeviceInfo(dev);
        String json=new Gson().toJson(error);
        Log.e("json",json);
        final RequestBody requestBody = RequestBody.create(MediaType.get("application/json"), json);
        Request builder = new Request.Builder()
          .url(url)
          .post(requestBody)
          .build();
        new OkHttpClient()
          .newBuilder()
          .connectTimeout(3, TimeUnit.SECONDS)
          .build()
          .newCall(builder)
          .enqueue(new okhttp3.Callback() {
              @Override
              public void onFailure(Call call, IOException e) {
                  Log.e("sendNativeException", "onFailure");
                  Intent i = new Intent();
                  i.setClass(activity, errorIntentTargetClass);
                  i.putExtra("stack_trace_string",stackTraceString);
                  i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

                  activity.startActivity(i);
                  activity.finish();

                  System.exit(0);
              }
              @Override
              public void onResponse(Call call, Response response) throws IOException {
                  Log.e("sendNativeException", "onResponse");

                  Intent i = new Intent();
                  i.setClass(activity, errorIntentTargetClass);
                  i.putExtra("stack_trace_string",stackTraceString);
                  i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

                  activity.startActivity(i);
                  activity.finish();

                  System.exit(0);
              }
          });
          }
        });
  }

  public static void replaceErrorScreenActivityClass(Class errorScreenActivityClass){
    errorIntentTargetClass = errorScreenActivityClass;
  }

  public static void setNativeExceptionHandler(NativeExceptionHandlerIfc nativeExceptionHandler) {
    ReactNativeExceptionHandlerModule.nativeExceptionHandler = nativeExceptionHandler;
  }

  public static Object getBuildConfigValue(Context context, String fieldName) {
    try {
      Class<?> clazz = Class.forName(context.getPackageName() + ".BuildConfig");
      Field field = clazz.getField(fieldName);
      return field.get(null);
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    } catch (NoSuchFieldException e) {
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    }
    return null;
  }

  @ReactMethod
  public void setScreenName(final String screenName,) {
    this.screenName = screenName;
  }
}
