package com.nursa.appsflyer;

import android.util.Log;

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

import androidx.annotation.NonNull;

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

import com.appsflyer.AppsFlyerLib;
import com.appsflyer.attribution.AppsFlyerRequestListener;
import com.appsflyer.deeplink.DeepLink;
import com.appsflyer.deeplink.DeepLinkResult;
import com.getcapacitor.JSObject;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
import com.getcapacitor.annotation.CapacitorPlugin;
import com.getcapacitor.annotation.Permission;

import com.segment.analytics.Analytics;
import com.segment.analytics.Properties;
import com.segment.analytics.Traits;

import org.json.JSONException;
import org.json.JSONObject;


@CapacitorPlugin(name = "Appsflyer", permissions = {
        @Permission(strings = {
                Manifest.permission.INTERNET,
                Manifest.permission.ACCESS_NETWORK_STATE,
                Manifest.permission.ACCESS_WIFI_STATE
        })
})
public class AppsflyerPlugin extends Plugin {
    private Appsflyer implementation = new Appsflyer();

    private static final String PLUGIN_TAG = "SegmentAppsFlyerPlugin";
    private boolean initialized = false;
    private Analytics analytics;


    @PluginMethod
    public void echo(PluginCall call) {
        String value = call.getString("value");

        JSObject ret = new JSObject();
        ret.put("value", implementation.echo(value));
        call.resolve(ret);
    }

    @Override
    protected void handleOnNewIntent(Intent intent) {
        super.handleOnNewIntent(intent);
        if (intent != null) {
            getActivity().setIntent(intent);
        }
    }

    @Override
    public void load() {
        Log.i("Load", "Load");
        AppsflyerIntegration.conversionListener = new AppsflyerIntegration.ExternalAppsFlyerConversionListener() {
            @Override
            public void onConversionDataSuccess(Map<String, Object> conversionData) {
                JSObject res = new JSObject();
                res.put("callbackName", "onConversionDataSuccess");
                JSObject data = new JSObject();
                for (String attrName : conversionData.keySet()) {
                    data.put(attrName, conversionData.get((attrName)));
                }
                res.put("data", data);
                notifyListeners("conversion_callback", res);
            }

            @Override
            public void onConversionDataFail(String status) {
                JSObject res = new JSObject();
                res.put("callbackName", "onConversionDataFail");
                res.put("status", status);
                notifyListeners("conversion_callback", res);
            }

            @Override
            public void onAppOpenAttribution(Map<String, String> attributionData) {
                JSObject res = new JSObject();
                res.put("callbackName", "onAppOpenAttribution");
                JSObject data = new JSObject();
                for (String attrName : attributionData.keySet()) {
                    data.put(attrName, attributionData.get((attrName)));
                }
                res.put("data", data);
                notifyListeners("oaoa_callback", res);
            }

            @Override
            public void onAttributionFailure(String status) {
                JSObject res = new JSObject();
                res.put("callbackName", "onAttributionFailure");
                res.put("status", status);
                notifyListeners("oaoa_callback", res);
            }
        };

        AppsflyerIntegration.deepLinkListener = new AppsflyerIntegration.ExternalDeepLinkListener() {
            @Override
            public void onDeepLinking(@NonNull DeepLinkResult deepLinkResult) {
                Log.i("Load", "Deep link");
                JSObject res = new JSObject();
                DeepLinkResult.Status status = deepLinkResult.getStatus();
                DeepLinkResult.Error error = deepLinkResult.getError();
                DeepLink deepLink = deepLinkResult.getDeepLink();
                switch (status) {
                    case NOT_FOUND:
                        res.put("status", "NOT_FOUND");
                    case ERROR:
                        res.put("status", "ERROR");
                    case FOUND:
                        res.put("status", "FOUND");
                }
                if (error != null) {
                    res.put("error", error.toString());
                }
                if (deepLink != null) {
                    try {
                        res.put("deepLink", JSObject.fromJSONObject(new JSONObject((deepLink.toString()))));
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
                notifyListeners("udl_callback", res);
            }
        };
    }

    @PluginMethod()
    public void initialize(PluginCall call) {
        Log.i("Load", "Initialize");
        if (initialized) {
            call.reject("Segment is already initialized");
            return;
        }
        String writeKey = call.getString("writeKey");
        if (writeKey == null) {
            call.reject("Write key not provided");
            return;
        }
        Boolean debug = call.getBoolean("isDebug", false);

        Context context = this.getContext();
        this.getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Analytics.Builder builder = new Analytics.Builder(context, writeKey)
                        .use(AppsflyerIntegration.FACTORY)
                        .logLevel(debug ? Analytics.LogLevel.DEBUG : Analytics.LogLevel.INFO)
                        .trackApplicationLifecycleEvents()
                        .trackDeepLinks();
                analytics = builder.build();
            }
        });
        analytics.onIntegrationReady(AppsflyerIntegration.FACTORY.key(), new Analytics.Callback() {
            @Override
            public void onReady(Object instance) {
                AppsFlyerLib.getInstance().start(context, null, new AppsFlyerRequestListener() {
                    @Override
                    public void onSuccess() {
                        initialized = true;
                        call.resolve();
                    }

                    @Override
                    public void onError(int i, @NonNull String s) {
                        call.reject("Appsflyer failed to initialize. Error code: " + i + "\n" + s);
                    }
                });
            }
        });
    }

    @PluginMethod()
    public void identify(PluginCall call) {
        Log.i("Load", "Identify");
        if (!initialized) {
            call.reject("Segment is not initialized");
            return;
        }
        String userId = call.getString("userId");
        if (userId == null) {
            call.reject("User ID is required for 'identify' but not supplied");
            return;
        }
        JSObject traits = call.getObject("traits");

        this.analytics.identify(userId, makeTraitsFromMap(makeMapFromJSON(traits)), null);
        call.resolve();
    }

    @PluginMethod()
    public void track(PluginCall call) {
        Log.i("Load", "Track");
        if (!initialized) {
            call.reject("Segment is not initialized");
            return;
        }
        String eventName = call.getString("eventName");
        JSObject eventValue = call.getObject("properties");

        this.analytics.track(
                eventName,
                makePropertiesFromMap(makeMapFromJSON(eventValue)));
        call.resolve();
    }

    @PluginMethod()
    public void trackPage(PluginCall call) {
        Log.i("Load", "Track page");
        if (!initialized) {
            call.reject("Segment is not initialized");
            return;
        }
        String eventName = call.getString("eventName");
        JSObject eventValue = call.getObject("properties");

        this.analytics.screen(
                eventName,
                makePropertiesFromMap(makeMapFromJSON(eventValue)));
        call.resolve();
    }

    private Map<String, Object> makeMapFromJSON(JSObject obj) {
        Iterator<String> keys = obj.keys();
        Map<String, Object> map = new HashMap<String, Object>();
        while (keys.hasNext()) {
            String key = keys.next();
            try {
                Object value = obj.get(key);
                map.put(key, value);
            } catch (JSONException e) {
                Log.d(PLUGIN_TAG, "could not get value for key " + key);
            }
        }
        return map;
    }

    private Traits makeTraitsFromMap(Map<String, Object> map) {
        Traits traits = new Traits();
        traits.putAll(map);
        return traits;
    }

    private Properties makePropertiesFromMap(Map<String, Object> map) {
        Properties properties = new Properties();
        properties.putAll(map);
        return properties;
    }
}
