package com.reactnativesharereceiver;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;

import androidx.annotation.NonNull;

import com.facebook.react.bridge.Arguments;
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.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.module.annotations.ReactModule;

import java.util.ArrayList;

@ReactModule(name = ShareReceiverModule.NAME)
public class ShareReceiverModule extends ReactContextBaseJavaModule {
    public static final String NAME = "ShareReceiver";
    public static final String ACTIVITY_ERROR_CODE = "Activity error";
    public static final String INTENT_ERROR_CODE = "Intent error";
    public static final String TYPE_KEY = "type";
    public static final String DATA_KEY = "data";

    public ShareReceiverModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    @NonNull
    public String getName() {
        return NAME;
    }

    @ReactMethod
    public void dismiss(String error) {
        // optional error parameter is not supported on Android
        Activity activity = getCurrentActivity();
        if (activity != null) {
            activity.finish();
        }
    }

    @ReactMethod
    public void getSharedData(Promise promise) {
        // get activity which receives shared data from other apps
        Activity activity = getCurrentActivity();
        if (activity == null) {
            promise.reject(ACTIVITY_ERROR_CODE, "No activity available");
            return;
        }

        Intent intent = activity.getIntent();
        if (intent == null) {
            promise.reject(INTENT_ERROR_CODE, "No intent received");
            return;
        }

        // WritableArray appears as array in JavaScript
        WritableArray items = Arguments.createArray();

        String action = intent.getAction();
        if (Intent.ACTION_SEND.equals(action)) {
            extractIntent(intent, false, items);
        } else if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
            extractIntent(intent, true, items);
        } else {
            promise.reject(INTENT_ERROR_CODE, "Wrong intent received: " + action);
        }
        promise.resolve(items);
    }

    /**
     * Extracts shared data from intent and stores it into WritableMap.
     */
    private void extractIntent(Intent intent, boolean multiple, WritableArray items) {
        // Read MIME type from intent.
        // When multiple items are shared, MIME type is common for all items.
        // It can be for example "images/*" when PNG and JPEG images were shared or "*/*" when PDF
        // and image were shared. Intent filters in AndroidManifest.xml define which types can be
        // received here.
        String type = intent.getType();
        if (intent.hasExtra(Intent.EXTRA_TEXT)) {
            items.pushMap(createDataItem(type, intent.getStringExtra(Intent.EXTRA_TEXT)));
        } else if (intent.hasExtra(Intent.EXTRA_STREAM)) {
            if (multiple) {
                ArrayList<Uri> uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
                if (uris != null) {
                    for (Uri uri : uris) {
                        items.pushMap(createDataItem(type, uri.toString()));
                    }
                }
            } else {
                Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
                items.pushMap(createDataItem(type, uri.toString()));
            }
        }
    }

    /**
     * Returns a simple ReadableMap with type and data keys.
     */
    private ReadableMap createDataItem(String type, String value) {
        WritableMap item = Arguments.createMap();
        if (type != null) {
            item.putString(TYPE_KEY, type);
        }
        item.putString(DATA_KEY, value);
        return item;
    }
}
