package io.scanbot.sdk.reactnative.components.barcodecameraview;

import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;

import com.facebook.react.ReactRootView;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.annotations.ReactProp;

import java.util.Map;

import io.scanbot.sdk.reactnative.JSONUtils;
import io.scanbot.sdk.reactnative.ObjectMapper;
import io.scanbot.sdk.reactnative.R;
import io.scanbot.sdk.reactnative.components.EventEmitter;
import io.scanbot.sdk.reactnative.components.common.ScanbotComponentFrameLayout;
import io.scanbot.sdk.reactnative.components.common.ScanbotComponentRootView;
import kotlin.NotImplementedError;

public class ScanbotBarcodeCameraViewManager extends ViewGroupManager<ReactRootView>  {

    public static final String REACT_CLASS = "ScanbotBarcodeCameraView";

    private final ReactApplicationContext mCallerContext;
    private ScanbotComponentRootView viewGroup;
    private ScanbotBarcodeCameraViewFragment cameraViewFragment;
    private ScanbotBarcodeCameraViewConfiguration cameraViewConfiguration = new ScanbotBarcodeCameraViewConfiguration();

    public ScanbotBarcodeCameraViewManager(ReactApplicationContext context) {
        mCallerContext = context;
    }

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

    @ReactProp(name = "configuration")
    public void setConfiguration(FrameLayout frameLayout, ReadableMap configuration) {
        cameraViewConfiguration = new ScanbotBarcodeCameraViewConfiguration();

        try {
            ObjectMapper.map(configuration, cameraViewConfiguration);
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (configuration.hasKey("barcodeFormats")) {
            cameraViewConfiguration.barcodeFormats = JSONUtils.extractBarcodeFormats(configuration);
        }

        if (configuration.hasKey("acceptedDocumentFormats")) {
            cameraViewConfiguration.acceptedDocumentFormats = JSONUtils.extractBarcodeDocumentFormats(configuration);
        }

        if (configuration.hasKey("cameraZoomFactor")) {
            float value = (float) configuration.getDouble("cameraZoomFactor");
            if (value != -1) {
                cameraViewConfiguration.setCameraZoomFactor(value);
            }
        }

        if (configuration.hasKey("flashEnabled")) {
            cameraViewConfiguration.setFlashEnabled(configuration.getBoolean("flashEnabled"));
        }

        cameraViewConfiguration.additionalConfiguration = JSONUtils.extractBarcodeScannerAdditionalConfig(configuration);
        cameraViewConfiguration.engineMode = JSONUtils.extractEngineMode(configuration);

        if (cameraViewFragment != null) {
            cameraViewFragment.updateWithConfiguration(cameraViewConfiguration);
        }
    }

    @Nullable
    @Override
    public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
        return EventEmitter.getMapForNativeEvents(new EventEmitter.NativeEvent[] {
            EventEmitter.NativeEvent.BARCODE_SCANNER_RESULT,
            EventEmitter.NativeEvent.REQUEST_COMPONENT_RELOAD
        });
    }

    @NonNull
    @Override
    protected ReactRootView createViewInstance(@NonNull final ThemedReactContext reactContext) {

        // Retrieve Current Activity
        final Activity activity = reactContext.getCurrentActivity();
        assert activity != null;

        // Inflate Layout
        viewGroup = (ScanbotComponentRootView) LayoutInflater
                .from(activity)
                .inflate(R.layout.component_barcode_camera_view, null, false);

        // Add Camera View Fragment
        cameraViewFragment = new ScanbotBarcodeCameraViewFragment();
        cameraViewFragment.instantiate(reactContext, viewGroup);
        final AppCompatActivity fragmentActivity = (AppCompatActivity) activity;
        final FragmentManager fragmentManager = fragmentActivity.getSupportFragmentManager();

        final ScanbotComponentFrameLayout fragmentLayout = viewGroup.findViewById(R.id.fragment_container_view);
        fragmentLayout.setZ(-1.0f);
        fragmentLayout.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));

        // Configure Camera View fragment with configuration parameters
        cameraViewFragment.updateWithConfiguration(cameraViewConfiguration);
        viewGroup.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
            @Override
            public void onViewAttachedToWindow(View v) {
                if (cameraViewFragment.isAdded()) {
                    return;
                }
                reactContext.runOnUiQueueThread(new Runnable() {
                    @Override
                    public void run() {
                        fragmentManager
                                .beginTransaction()
                                .add(R.id.fragment_container_view, cameraViewFragment)
                                .commit();

                        viewGroup.post(viewGroup.measureAndLayout);

                        viewGroup.addOneShotChildRemovedListener(new ScanbotComponentRootView.IOnChildRemovedListener() {
                            @Override
                            public void onChildRemoved(View child) {
                                new EventEmitter(mCallerContext, viewGroup)
                                        .emitEvent(
                                                EventEmitter.NativeEvent.REQUEST_COMPONENT_RELOAD,
                                                new WritableNativeMap());
                            }
                        });
                    }
                });
            }

            @Override
            public void onViewDetachedFromWindow(View v) {

            }
        });

        return viewGroup;
    }

}
