package io.invertase.firebase.links;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.util.Log;

import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.LifecycleEventListener;
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.ReadableMap;

import com.google.firebase.appinvite.FirebaseAppInvite;
import com.google.firebase.dynamiclinks.DynamicLink;
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks;
import com.google.firebase.dynamiclinks.ShortDynamicLink;
import com.google.firebase.dynamiclinks.PendingDynamicLinkData;

import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.OnFailureListener;

import io.invertase.firebase.Utils;

public class RNFirebaseLinks extends ReactContextBaseJavaModule implements ActivityEventListener, LifecycleEventListener {
  private final static String TAG = RNFirebaseLinks.class.getCanonicalName();
  private String mInitialLink = null;
  private boolean mInitialLinkInitialized = false;

  public RNFirebaseLinks(ReactApplicationContext reactContext) {
    super(reactContext);
    getReactApplicationContext().addActivityEventListener(this);
    getReactApplicationContext().addLifecycleEventListener(this);
  }

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

  @ReactMethod
  public void createDynamicLink(final ReadableMap linkData, final Promise promise) {
    try {
      DynamicLink.Builder builder = getDynamicLinkBuilder(linkData);
      String link = builder.buildDynamicLink().getUri().toString();
      Log.d(TAG, "created dynamic link: " + link);
      promise.resolve(link);
    } catch (Exception ex) {
      Log.e(TAG, "create dynamic link failure " + ex.getMessage());
      promise.reject("links/failure", ex.getMessage(), ex);
    }
  }

  @ReactMethod
  public void createShortDynamicLink(final ReadableMap linkData, final String type, final Promise promise) {
    try {
      DynamicLink.Builder builder = getDynamicLinkBuilder(linkData);
      Task<ShortDynamicLink> shortLinkTask;
      if ("SHORT".equals(type)) {
        shortLinkTask = builder.buildShortDynamicLink(ShortDynamicLink.Suffix.SHORT);
      } else if ("UNGUESSABLE".equals(type)) {
        shortLinkTask = builder.buildShortDynamicLink(ShortDynamicLink.Suffix.UNGUESSABLE);
      } else {
        shortLinkTask = builder.buildShortDynamicLink();
      }

      shortLinkTask.addOnCompleteListener(new OnCompleteListener<ShortDynamicLink>() {
          @Override
          public void onComplete(@NonNull Task<ShortDynamicLink> task) {
        if (task.isSuccessful()) {
          String shortLink = task.getResult().getShortLink().toString();
          Log.d(TAG, "created short dynamic link: " + shortLink);
          promise.resolve(shortLink);
        } else {
          Log.e(TAG, "create short dynamic link failure " + task.getException().getMessage());
          promise.reject("links/failure", task.getException().getMessage(), task.getException());
        }
        }
      });
    } catch (Exception ex) {
      Log.e(TAG, "create short dynamic link failure " + ex.getMessage());
      promise.reject("links/failure", ex.getMessage(), ex);
    }
  }

  @ReactMethod
  public void getInitialLink(final Promise promise) {
    if (mInitialLinkInitialized) {
      promise.resolve(mInitialLink);
    } else {
      if (getCurrentActivity() != null) {
        FirebaseDynamicLinks.getInstance()
          .getDynamicLink(getCurrentActivity().getIntent())
          .addOnSuccessListener(new OnSuccessListener<PendingDynamicLinkData>() {
            @Override
            public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) {
              if (pendingDynamicLinkData != null
                && !isInvitation(pendingDynamicLinkData)) {

                mInitialLink = pendingDynamicLinkData.getLink().toString();
              }
              Log.d(TAG, "getInitialLink: link is: " + mInitialLink);
              mInitialLinkInitialized = true;
              promise.resolve(mInitialLink);
            }
          })
          .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
              Log.e(TAG, "getInitialLink: failed to resolve link", e);
              promise.reject("link/initial-link-error", e.getMessage(), e);
            }
          });
      } else {
        Log.d(TAG, "getInitialLink: activity is null");
        promise.resolve(null);
      }
    }
  }

  //////////////////////////////////////////////////////////////////////
  // Start ActivityEventListener methods
  //////////////////////////////////////////////////////////////////////
  @Override
  public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
    // Not required for this module
  }

  @Override
  public void onNewIntent(Intent intent) {
    FirebaseDynamicLinks.getInstance()
      .getDynamicLink(intent)
      .addOnSuccessListener(new OnSuccessListener<PendingDynamicLinkData>() {
        @Override
        public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) {
          if (pendingDynamicLinkData != null
            && !isInvitation(pendingDynamicLinkData)) {
            String link = pendingDynamicLinkData.getLink().toString();
            Utils.sendEvent(getReactApplicationContext(), "links_link_received", link);
          }
        }
      });
  }
  //////////////////////////////////////////////////////////////////////
  // End ActivityEventListener methods
  //////////////////////////////////////////////////////////////////////

  //////////////////////////////////////////////////////////////////////
  // Start LifecycleEventListener methods
  //////////////////////////////////////////////////////////////////////
  @Override
  public void onHostResume() {
    // Not required for this module
  }

  @Override
  public void onHostPause() {
    // Not required for this module
  }

  @Override
  public void onHostDestroy() {
    mInitialLink = null;
    mInitialLinkInitialized = false;
  }
  //////////////////////////////////////////////////////////////////////
  // End LifecycleEventListener methods
  //////////////////////////////////////////////////////////////////////

  // Looks at the internals of the link data to detect whether it's an invitation or not
  private boolean isInvitation(PendingDynamicLinkData pendingDynamicLinkData) {
    return FirebaseAppInvite.getInvitation(pendingDynamicLinkData) != null;
  }

  private DynamicLink.Builder getDynamicLinkBuilder(final ReadableMap linkData) {
    DynamicLink.Builder builder = FirebaseDynamicLinks.getInstance().createDynamicLink();
    try {
      builder.setLink(Uri.parse(linkData.getString("link")));
      builder.setDynamicLinkDomain(linkData.getString("dynamicLinkDomain"));
      setAnalyticsParameters(linkData.getMap("analytics"), builder);
      setAndroidParameters(linkData.getMap("android"), builder);
      setIosParameters(linkData.getMap("ios"), builder);
      setITunesParameters(linkData.getMap("itunes"), builder);
      setNavigationParameters(linkData.getMap("navigation"), builder);
      setSocialParameters(linkData.getMap("social"), builder);
    } catch (Exception e) {
      Log.e(TAG, "error while building parameters " + e.getMessage());
      throw e;
    }
    return builder;
  }

  private void setAnalyticsParameters(final ReadableMap analyticsData, final DynamicLink.Builder builder) {
    DynamicLink.GoogleAnalyticsParameters.Builder analyticsParameters = new DynamicLink.GoogleAnalyticsParameters.Builder();

    if (analyticsData.hasKey("campaign")) {
      analyticsParameters.setCampaign(analyticsData.getString("campaign"));
    }
    if (analyticsData.hasKey("content")) {
      analyticsParameters.setContent(analyticsData.getString("content"));
    }
    if (analyticsData.hasKey("medium")) {
      analyticsParameters.setMedium(analyticsData.getString("medium"));
    }
    if (analyticsData.hasKey("source")) {
      analyticsParameters.setSource(analyticsData.getString("source"));
    }
    if (analyticsData.hasKey("term")) {
      analyticsParameters.setTerm(analyticsData.getString("term"));
    }
    builder.setGoogleAnalyticsParameters(analyticsParameters.build());
  }

  private void setAndroidParameters(final ReadableMap androidData, final DynamicLink.Builder builder) {
    if (androidData.hasKey("packageName")) {
      DynamicLink.AndroidParameters.Builder androidParameters = new DynamicLink.AndroidParameters.Builder(androidData.getString("packageName"));

      if (androidData.hasKey("fallbackUrl")) {
        androidParameters.setFallbackUrl(Uri.parse(androidData.getString("fallbackUrl")));
      }
      if (androidData.hasKey("minimumVersion")) {
        androidParameters.setMinimumVersion(Integer.parseInt(androidData.getString("minimumVersion")));
      }
      builder.setAndroidParameters(androidParameters.build());
    }
  }

  private void setIosParameters(final ReadableMap iosData, final DynamicLink.Builder builder) {
    if (iosData.hasKey("bundleId")) {
      DynamicLink.IosParameters.Builder iosParameters =
        new DynamicLink.IosParameters.Builder(iosData.getString("bundleId"));

      if (iosData.hasKey("appStoreId")) {
        iosParameters.setAppStoreId(iosData.getString("appStoreId"));
      }
      if (iosData.hasKey("customScheme")) {
        iosParameters.setCustomScheme(iosData.getString("customScheme"));
      }
      if (iosData.hasKey("fallbackUrl")) {
        iosParameters.setFallbackUrl(Uri.parse(iosData.getString("fallbackUrl")));
      }
      if (iosData.hasKey("iPadBundleId")) {
        iosParameters.setIpadBundleId(iosData.getString("iPadBundleId"));
      }
      if (iosData.hasKey("iPadFallbackUrl")) {
        iosParameters.setIpadFallbackUrl(Uri.parse(iosData.getString("iPadFallbackUrl")));
      }
      if (iosData.hasKey("minimumVersion")) {
        iosParameters.setMinimumVersion(iosData.getString("minimumVersion"));
      }
      builder.setIosParameters(iosParameters.build());
    }
  }

  private void setITunesParameters(final ReadableMap itunesData, final DynamicLink.Builder builder) {
    DynamicLink.ItunesConnectAnalyticsParameters.Builder itunesParameters = new DynamicLink.ItunesConnectAnalyticsParameters.Builder();

    if (itunesData.hasKey("affiliateToken")) {
      itunesParameters.setAffiliateToken(itunesData.getString("affiliateToken"));
    }
    if (itunesData.hasKey("campaignToken")) {
      itunesParameters.setCampaignToken(itunesData.getString("campaignToken"));
    }
    if (itunesData.hasKey("providerToken")) {
      itunesParameters.setProviderToken(itunesData.getString("providerToken"));
    }
    builder.setItunesConnectAnalyticsParameters(itunesParameters.build());
  }

  private void setNavigationParameters(final ReadableMap navigationData, final DynamicLink.Builder builder) {
    DynamicLink.NavigationInfoParameters.Builder navigationParameters = new DynamicLink.NavigationInfoParameters.Builder();

    if (navigationData.hasKey("forcedRedirectEnabled")) {
      navigationParameters.setForcedRedirectEnabled(navigationData.getBoolean("forcedRedirectEnabled"));
    }
    builder.setNavigationInfoParameters(navigationParameters.build());
  }

  private void setSocialParameters(final ReadableMap socialData, final DynamicLink.Builder builder) {
    DynamicLink.SocialMetaTagParameters.Builder socialParameters = new DynamicLink.SocialMetaTagParameters.Builder();

    if (socialData.hasKey("descriptionText")) {
      socialParameters.setDescription(socialData.getString("descriptionText"));
    }
    if (socialData.hasKey("imageUrl")) {
      socialParameters.setImageUrl(Uri.parse(socialData.getString("imageUrl")));
    }
    if (socialData.hasKey("title")) {
      socialParameters.setTitle(socialData.getString("title"));
    }
    builder.setSocialMetaTagParameters(socialParameters.build());
  }
}
