/*
    Scanbot SDK ReactNative Module
    Copyright (c) 2017 doo GmbH. All rights reserved.
*/
package io.scanbot.sdk.reactnative;

import android.app.Application;

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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import io.scanbot.sdk.sdk_native_wrapper.SBNWOperations;
import io.scanbot.sdk.sdk_native_wrapper.SBNWReadyToUseUi;
import kotlin.NotImplementedError;

public class ScanbotSDKReactNative extends ReactContextBaseJavaModule {
    private static SBNWReadyToUseUi readyToUseUi;

    private final ExecutorService threadPool;

    public ScanbotSDKReactNative(final ReactApplicationContext reactContext) {
        super(reactContext);

        this.threadPool = Executors.newCachedThreadPool();
    }

    private ExecutorService getThreadPool() {
        return this.threadPool;
    }

    private static String getOptionValue(final ReadableMap options, final String optionName, final String defaultValue) {
        return options.hasKey(optionName) ? options.getString(optionName) : defaultValue;
    }

    private static boolean getOptionValue(final ReadableMap options, final String optionName, final boolean defaultValue) {
        return options.hasKey(optionName) ? options.getBoolean(optionName) : defaultValue;
    }

    private static int getOptionValue(final ReadableMap options, final String optionName, final int defaultValue) {
        return options.hasKey(optionName) ? options.getInt(optionName) : defaultValue;
    }

    private static boolean checkRejectSDKInitialization(final Promise promise) {
        if (!ScanbotSDKHelper.isSdkInitialized()) {
            ResponseUtils.errorMessageJson("Scanbot SDK is not initialized. Please call the initializeSDK() method first.", promise);
            return false;
        }
        return true;
    }

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

    public static SBNWReadyToUseUi getReadyToUseUi() {
        if (readyToUseUi == null) {
            readyToUseUi = new SBNWReadyToUseUi();
        }
        return readyToUseUi;
    }

    @ReactMethod
    public void initializeSDK(final ReadableMap options, final Promise promise) {
        Application application = (Application) getReactApplicationContext().getApplicationContext();
        ScanbotSDKHelper.initializeSDK(options, application, promise);
    }

    @ReactMethod
    public void getLicenseInfo(final Promise promise) {
        SBNWOperations.INSTANCE.getLicenseInfo(new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void detectDocument(final String imageFileUri, final Promise promise) {
        Map<String, Object> map = new HashMap<>();
        map.put("imageFileUri", imageFileUri);

        SBNWOperations.INSTANCE.detectDocumentOnImage(map, new ResultProxyDelegate(promise));
    }


    @ReactMethod
    public void estimateBlur(final ReadableMap configuration, final Promise promise) {
        SBNWOperations.INSTANCE.estimateBlur(configuration.toHashMap(), new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void applyImageFilter(final String imageFileUri, final String filterType, final Promise promise) {
        SBNWOperations.INSTANCE.applyImageFilter(imageFileUri, filterType, new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void getOCRConfigs(final Promise promise) {
        SBNWOperations.INSTANCE.getOCRConfigs(new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void performOCR(final ReadableArray imageFileUris, final ReadableArray languages, final ReadableMap options, final Promise promise) {
        Map<String, Object> map = new HashMap<>();

        List<Object> imageFileUriList = new ArrayList<>(imageFileUris.toArrayList());
        map.put("imageFileUris", imageFileUriList);

        List<Object> languageList = new ArrayList<>(languages.toArrayList());
        map.put("languages", languageList);

        final String outputFormat = getOptionValue(options, "outputFormat", "PLAIN_TEXT");
        map.put("outputFormat", outputFormat);

        SBNWOperations.INSTANCE.performOCR(map, new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void createPDF(final ReadableArray imageFileUris, final String pageSize, final Promise promise) {
        List<String> imageFileUriList = new ArrayList<>();
        for (Object uri : imageFileUris.toArrayList()) {
            imageFileUriList.add((String) uri);
        }

        SBNWOperations.INSTANCE.createPDF(imageFileUriList, pageSize, new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void writeTIFF(final ReadableArray imageFileUris, final ReadableMap options, final Promise promise) {
        Map<String, Object> map = new HashMap<>();
        map.put("imageFileUris", imageFileUris.toArrayList());
        map.putAll(options.toHashMap());

        SBNWOperations.INSTANCE.createTIFF(map, new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void extractPagesFromPdf(final ReadableMap options, final Promise promise) {
        SBNWOperations.INSTANCE.extractPagesFromPdf(options.toHashMap(), new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void extractImagesFromPdf(final ReadableMap options, final Promise promise) {
        SBNWOperations.INSTANCE.extractImagesFromPdf(options.toHashMap(), new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void rotateImage(final String imageFileUri, final Double degrees, final Promise promise) {
        Map<String, Object> map = new HashMap<>();
        map.put("imageFileUri", imageFileUri);
        map.put("degrees", degrees);

        SBNWOperations.INSTANCE.rotateImage(map, new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void createPage(final String imageUri, final Promise promise) {
        SBNWOperations.INSTANCE.createPage(imageUri, new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void detectDocumentOnPage(final ReadableMap pageMap, final Promise promise) {
        SBNWOperations.INSTANCE.detectDocumentOnPage(pageMap.toHashMap(), new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void detectBarcodesOnImages(final ReadableMap options, final Promise promise) {
        SBNWOperations.INSTANCE.detectBarcodesOnImages(options.toHashMap(), new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void detectBarcodesOnImage(final ReadableMap options, final Promise promise) {
        SBNWOperations.INSTANCE.detectBarcodesOnImage(options.toHashMap(), new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void applyImageFilterOnPage(final ReadableMap pageMap, final String filterType, final Promise promise) {
        SBNWOperations.INSTANCE.applyImageFilterOnPage(pageMap.toHashMap(), filterType, new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void rotatePage(final ReadableMap pageMap, final int times, final Promise promise) {
        SBNWOperations.INSTANCE.rotatePage(pageMap.toHashMap(), times, new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void getFilteredDocumentPreviewUri(final ReadableMap pageMap, final String filterName, final Promise promise) {
        SBNWOperations.INSTANCE.getFilteredDocumentPreviewUri(pageMap.toHashMap(), filterName, new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void removePage(final ReadableMap pageMap, final Promise promise) {
        SBNWOperations.INSTANCE.removePage(pageMap.toHashMap(), new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void setDocumentImage(final ReadableMap pageMap, final String imageUri, final Promise promise) {
        Map<String, Object> map = new HashMap<>();

        map.put("page", pageMap.toHashMap());
        map.put("imageFileUri", imageUri);

        SBNWOperations.INSTANCE.setDocumentImage(map, new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void cleanup(final Promise promise) {
        SBNWOperations.INSTANCE.cleanup(new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void recognizeMrz(final String imageFileUri, final Promise promise) {
        Map<String, String> map = new HashMap<>();
        map.put("imageFileUri", imageFileUri);

        SBNWOperations.INSTANCE.recognizeMrz(map, new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void refreshImageUris(final ReadableMap map, final Promise promise) {
        SBNWOperations.INSTANCE.refreshImageUris(map.toHashMap(), new ResultProxyDelegate(promise));
    }

    @ReactMethod
    public void getImageData(final String imageFileUri, final Promise promise) {
        Map<String, String> map = new HashMap<>();
        map.put("imageFileUri", imageFileUri);

        SBNWOperations.INSTANCE.getImageData(map, new ResultProxyDelegate(promise));
    }
}
