package com.kochava.reactlibrary;

//
//  KochavaTracker (ReactNative)
//
//  Copyright (c) 2018 - 2023 Kochava, Inc. All rights reserved.
//

import android.util.Log;

import com.facebook.react.bridge.Callback;
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.modules.core.RCTNativeAppEventEmitter;
import com.kochava.core.json.internal.JsonArray;
import com.kochava.core.json.internal.JsonObject;
import com.kochava.core.json.internal.JsonObjectApi;
import com.kochava.core.json.internal.JsonElement;
import com.kochava.core.json.internal.JsonElementApi;
import com.kochava.core.util.internal.ObjectUtil;
import com.kochava.core.util.internal.TextUtil;
import com.kochava.tracker.Tracker;
import com.kochava.tracker.attribution.InstallAttributionApi;
import com.kochava.tracker.attribution.RetrievedInstallAttributionListener;
import com.kochava.tracker.deeplinks.DeeplinkApi;
import com.kochava.tracker.deeplinks.ProcessedDeeplinkListener;
import com.kochava.tracker.engagement.Engagement;
import com.kochava.tracker.events.Event;
import com.kochava.tracker.events.EventApi;
import com.kochava.tracker.events.Events;
import com.kochava.tracker.log.LogLevel;

/**
 * Kochava Tracker Plugin
 */
public final class RNKochavaTrackerModule extends ReactContextBaseJavaModule {
    private final static String LOGTAG = "KVA/Tracker";
    private final ReactApplicationContext reactContext;

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

    /**
     * Returns the name of the plugin that matches up in the JS layer.
     */
    @Override
    public final String getName() {
        return "RNKochavaTracker";
    }

    // void executeAdvancedInstruction(string name, string value)
    @ReactMethod
    public final void executeAdvancedInstruction(final String name, final String value) {
        Tracker.getInstance().executeAdvancedInstruction(name, value);
    }

    // void setLogLevel(LogLevel logLevel)
    @ReactMethod
    public final void setLogLevel(final String logLevel) {
        Tracker.getInstance().setLogLevel(LogLevel.fromString(logLevel));
    }

    // void setSleep(bool sleep)
    @ReactMethod
    public final void setSleep(final boolean sleep) {
        Tracker.getInstance().setSleep(sleep);
    }

    // void setAppLimitAdTracking(bool appLimitAdTracking)
    @ReactMethod
    public final void setAppLimitAdTracking(final boolean appLimitAdTracking) {
        Tracker.getInstance().setAppLimitAdTracking(appLimitAdTracking);
    }

    // void registerCustomDeviceIdentifier(string name, string value)
    @ReactMethod
    public final void registerCustomDeviceIdentifier(final String name, final String value) {
        Tracker.getInstance().registerCustomDeviceIdentifier(name, value);
    }

    // void registerCustomStringValue(string name, string value)
    @ReactMethod
    public final void registerCustomStringValue(final String name, final String value) {
        Tracker.getInstance().registerCustomStringValue(name, value);
    }

    // void registerCustomBoolValue(string name, bool value)
    @ReactMethod
    public final void registerCustomBoolValue(final String name, final Boolean value) {
        Tracker.getInstance().registerCustomBoolValue(name, value);
    }

    // void registerCustomNumberValue(string name, number value)
    @ReactMethod
    public final void registerCustomNumberValue(final String name, final Double value) {
        Tracker.getInstance().registerCustomNumberValue(name, value);
    }

    // void registerIdentityLink(string name, string value)
    @ReactMethod
    public final void registerIdentityLink(final String name, final String value) {
        Tracker.getInstance().registerIdentityLink(name, value);
    }

    // void enableAndroidInstantApps(string instantAppGuid)
    @ReactMethod
    public final void enableAndroidInstantApps(final String instantAppGuid) {
        Tracker.getInstance().enableInstantApps(instantAppGuid);
    }

    // void enableIosAppClips(string identifier)
    @ReactMethod
    public final void enableIosAppClips(final String identifier) {
        Log.w(LOGTAG, "enableIosAppClips API is not available on this platform.");
    }

    // void enableIosAtt()
    @ReactMethod
    public final void enableIosAtt() {
        Log.w(LOGTAG, "enableIosAtt API is not available on this platform.");
    }

    // void setIosAttAuthorizationWaitTime(double waitTime)
    @ReactMethod
    public final void setIosAttAuthorizationWaitTime(final double waitTime) {
        Log.w(LOGTAG, "setIosAttAuthorizationWaitTime API is not available on this platform.");
    }

    // void setIosAttAuthorizationAutoRequest(bool autoRequest)
    @ReactMethod
    public final void setIosAttAuthorizationAutoRequest(final boolean autoRequest) {
        Log.w(LOGTAG, "setIosAttAuthorizationAutoRequest API is not available on this platform.");
    }

    // void registerPrivacyProfile(string name, string[] keys)
    @ReactMethod
    public final void registerPrivacyProfile(final String name, final String keysSerialized) {
        Tracker.getInstance().registerPrivacyProfile(name, ObjectUtil.jsonArrayToStringArray(JsonArray.buildWithString(keysSerialized, true)));
    }

    // void setPrivacyProfileEnabled(string name, bool enabled)
    @ReactMethod
    public final void setPrivacyProfileEnabled(final String name, final boolean enabled) {
        Tracker.getInstance().setPrivacyProfileEnabled(name, enabled);
    }

    // void setInitCompletedListener(bool setListener)
    @ReactMethod
    public final void setInitCompletedListener(final boolean setListener) {
        if(setListener) {
            Tracker.getInstance().setCompletedInitListener(init -> {
                reactContext.getJSModule(RCTNativeAppEventEmitter.class).emit("KochavaTrackerInitCompleted", init.toJson().toString());
            });
        } else {
            Tracker.getInstance().setCompletedInitListener(null);
        }
    }

    // void setIntelligentConsentGranted(bool granted)
    @ReactMethod
    public final void setIntelligentConsentGranted(final boolean granted) {
        Tracker.getInstance().setIntelligentConsentGranted(granted);
    }

    // bool getStarted()
    @ReactMethod
    public final void getStarted(final Promise promise) {
        if(promise == null) {
            return;
        }
        promise.resolve(Tracker.getInstance().isStarted());
    }

    // void start(string androidAppGuid, string iosAppGuid, string partnerName)
    @ReactMethod
    public final void start(final String androidAppGuid, final String iosAppGuid, final String partnerName) {
        if (!TextUtil.isNullOrBlank(androidAppGuid)) {
            Tracker.getInstance().startWithAppGuid(reactContext.getApplicationContext(), androidAppGuid);
        } else if (!TextUtil.isNullOrBlank(partnerName)) {
            Tracker.getInstance().startWithPartnerName(reactContext.getApplicationContext(), partnerName);
        } else {
            // Allow the native to log the error of no app guid.
            Tracker.getInstance().startWithAppGuid(reactContext.getApplicationContext(), "");
        }
    }

    // void shutdown(bool deleteData)
    @ReactMethod
    public final void shutdown(final boolean deleteData) {
        Tracker.getInstance().shutdown(reactContext.getApplicationContext(), deleteData);
    }

    // string getDeviceId()
    @ReactMethod
    public final void getDeviceId(final Promise promise) {
        if(promise == null) {
            return;
        }
        promise.resolve(Tracker.getInstance().getDeviceId());
    }

    // InstallAttribution getInstallAttribution()
    @ReactMethod
    public final void getInstallAttribution(final Promise promise) {
        if(promise == null) {
            return;
        }
        promise.resolve(Tracker.getInstance().getInstallAttribution().toJson().toString());
    }

    // void retrieveInstallAttribution(Callback<InstallAttribution> callback)
    @ReactMethod
    public final void retrieveInstallAttribution(final Promise promise) {
        if(promise == null) {
            return;
        }
        Tracker.getInstance().retrieveInstallAttribution(installAttribution -> {
            promise.resolve(installAttribution.toJson().toString());
        });
    }

    // void processDeeplink(string path, Callback<Deeplink> callback)
    @ReactMethod
    public final void processDeeplink(final String path, final Promise promise) {
        if(promise == null) {
            return;
        }
        Tracker.getInstance().processDeeplink(path, deeplink -> {
            promise.resolve(deeplink.toJson().toString());
        });
    }

    // void processDeeplinkWithOverrideTimeout(string path, double timeout, Callback<Deeplink> callback)
    @ReactMethod
    public final void processDeeplinkWithOverrideTimeout(final String path, final double timeout, final Promise promise) {
        if(promise == null) {
            return;
        }
        Tracker.getInstance().processDeeplink(path, timeout, deeplink -> {
            promise.resolve(deeplink.toJson().toString());
        });
    }

    // void registerPushToken(string token)
    @ReactMethod
    public final void registerPushToken(final String token) {
        Engagement.getInstance().registerPushToken(token);
    }

    // void setPushEnabled(bool enabled)
    @ReactMethod
    public final void setPushEnabled(final boolean enabled) {
        Engagement.getInstance().setPushEnabled(enabled);
    }

    // void registerDefaultEventStringParameter(string name, string value)
    @ReactMethod
    public final void registerDefaultEventStringParameter(final String name, final String value) {
        Events.getInstance().registerDefaultStringParameter(name, value);
    }

    // void registerDefaultEventBoolParameter(string name, bool value)
    @ReactMethod
    public final void registerDefaultEventBoolParameter(final String name, final Boolean value) {
        Events.getInstance().registerDefaultBoolParameter(name, value);
    }

    // void registerDefaultEventNumberParameter(string name, number value)
    @ReactMethod
    public final void registerDefaultEventNumberParameter(final String name, final Double value) {
        Events.getInstance().registerDefaultNumberParameter(name, value);
    }

    // void registerDefaultEventUserId(string value)
    @ReactMethod
    public final void registerDefaultEventUserId(final String value) {
        Events.getInstance().registerDefaultUserId(value);
    }

    // void sendEvent(string name)
    @ReactMethod
    public final void sendEvent(final String name) {
        Events.getInstance().send(name);
    }

    // void sendEventWithString(string name, string data)
    @ReactMethod
    public final void sendEventWithString(final String name, final String data) {
        Events.getInstance().sendWithString(name, data);
    }

    // void sendEventWithDictionary(string name, object data)
    @ReactMethod
    public final void sendEventWithDictionary(final String name, final String dataSerialized) {
        Events.getInstance().sendWithDictionary(name, JsonObject.buildWithString(dataSerialized, true).toJSONObject());
    }

    // void sendEventWithEvent(Event event)
    @ReactMethod
    public final void sendEventWithEvent(final String eventSerialized) {
        final JsonObjectApi eventInfo = JsonObject.buildWithString(eventSerialized, true);
        final String eventName = eventInfo.getString("name", "");
        final JsonObjectApi eventData = eventInfo.getJsonObject("data", true);
        final String androidGooglePlayReceiptData = eventInfo.getString("androidGooglePlayReceiptData", "");
        final String androidGooglePlayReceiptSignature = eventInfo.getString("androidGooglePlayReceiptSignature", "");
        final EventApi event = Event.buildWithEventName(eventName);
        event.mergeCustomDictionary(eventData.toJSONObject());
        if(!TextUtil.isNullOrBlank(androidGooglePlayReceiptData) && !TextUtil.isNullOrBlank(androidGooglePlayReceiptSignature)) {
            event.setGooglePlayReceipt(androidGooglePlayReceiptData, androidGooglePlayReceiptSignature);
        }
        event.send();
    }

}
