package app.alan.reactmodule;

import android.Manifest;
import android.os.Build;
import android.util.Log;
import android.app.Activity;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
import com.alan.alansdk.Alan;
import com.alan.alansdk.AlanCallback;
import com.alan.alansdk.AlanConfig;
import com.alan.alansdk.AlanState;
import com.alan.alansdk.button.AlanButton;
import com.alan.alansdk.events.EventCommand;
import com.alan.alansdk.qr.BarcodeEvent;
import com.facebook.react.bridge.Callback;
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.ReadableMapKeySetIterator;
import com.facebook.react.bridge.ReadableNativeMap;
import com.facebook.react.bridge.ReadableType;

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

import android.os.Handler;
import android.os.Looper;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

public class AlanManager extends ReactContextBaseJavaModule {

    private final static String REACT_CLASS = "AlanManager";

    public static AlanManager INSTANCE;

    public static final Integer REQUEST_CODE_AUDIO_PERMISSIONS = 9009;

    static AlanButton alanButton;

    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void onBarcodeEvent(BarcodeEvent event) {
      final Handler handler = new Handler(Looper.getMainLooper());
      handler.postDelayed(new Runnable() {
        @Override
        public void run() {
          registerCallbacks();
        }
      }, 100);
    }

    public AlanManager(ReactApplicationContext reactContext) {
        super(reactContext);
        INSTANCE = this;
        EventBus.getDefault().register(this);
    }

    public void createButton(ReactApplicationContext mCallerContext) {
        final Activity activity = getCurrentActivity();
        if (activity == null) {
            return;
        }
        ViewGroup rootView = activity.findViewById(android.R.id.content);

        Alan.PLATFORM_SUFFIX = "react-native";
        Alan.PLATFORM_VERSION_SUFFIX = "2.9.0";
        Alan.QR_EVENT_BUS_ENABLED = true;

        if (alanButton != null) {
            removeButton();
        }

        alanButton = new AlanButton(activity, null);
        LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        params.gravity = Gravity.END|Gravity.BOTTOM;
        alanButton.setLayoutParams(params);
        alanButton.hideButton();
        alanButton.hideHintPanel();
        rootView.addView(alanButton, 0);

        registerCallbacks();
    }

    public void removeButton() {
        final Activity activity = getCurrentActivity();
        if (activity != null) {
            ViewGroup rootView = activity.findViewById(android.R.id.content);
            if (alanButton != null) {
                rootView.removeView(alanButton);
            }
        }
        if (alanButton != null) {
            alanButton.deactivate();
            alanButton.getSDK().stop();
            alanButton.getSDK().clearCallbacks();
            alanButton = null;
        }
    }

    public void registerCallbacks() {
        if (alanButton == null) {
            return;
        }
        alanButton.registerCallback(new AlanCallback() {
            @Override
            public void onCommandReceived(EventCommand eventCommand) {
                AlanEventEmitter.INSTANCE.onConnected(eventCommand.getData());
            }

            @Override
            public void onCommand(EventCommand eventCommand) {
                AlanEventEmitter.INSTANCE.onCommand(eventCommand.getData());
            }

            @Override
            public void onEvent(String payload) {
                AlanEventEmitter.INSTANCE.onEvent(payload);
            }

            @Override
            public void onButtonState(AlanState alanState) {
                String state = alanState.name();
                if (state == "ONLINE") {
                    alanButton.updateButtonVisibility();
                }
                AlanEventEmitter.INSTANCE.onButtonState(state);
            }
        });
    }

    public void requestAudioPermissions() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Activity activity = getCurrentActivity();
            if (activity != null) {
                activity.requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, REQUEST_CODE_AUDIO_PERMISSIONS);
            }
        }
    }

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

    @ReactMethod
    public void getVersion(Callback callback) {
        if (alanButton == null) {
            callback.invoke("--");
            return;
        }
        String version = alanButton.getSDK().getVersion();
        callback.invoke(version);
    }

    @ReactMethod
    public void showButton() {
        if (alanButton == null) {
            return;
        }
        final Handler handler = new Handler(Looper.getMainLooper());
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                alanButton.showButton();
            }
        }, 10);
    }


    @ReactMethod
    public void hideButton() {
        if (alanButton == null) {
            return;
        }
        final Handler handler = new Handler(Looper.getMainLooper());
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                alanButton.hideButton();
            }
        }, 10);
    }

    @ReactMethod
    public void activate() {
        if (alanButton == null) {
            return;
        }
        final Handler handler = new Handler(Looper.getMainLooper());
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                alanButton.activate();
            }
        }, 10);
    }

    @ReactMethod
    public void deactivate() {
        if (alanButton == null) {
            return;
        }
        final Handler handler = new Handler(Looper.getMainLooper());
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                alanButton.deactivate();
            }
        }, 10);
    }

    @ReactMethod
    public void callProjectApi(String method, ReadableMap data, Callback callback) {
        if (alanButton == null) {
            callback.invoke("No button available");
            return;
        }
        try {
            String dataString = JsonConverter.reactToJSON(data).toString();
            alanButton.callProjectApi(method, dataString, (methodName, response, error) -> {
                if (error != null && !error.isEmpty()) {
                    Log.i("AlanResponse", methodName + " failed with: " + error);
                    callback.invoke(error, null);
                } else {
                    Log.i("AlanResponse", methodName + " response is: " + response);
                    callback.invoke(null, response);
                }
            });
        } catch (Exception e) {
            Log.e(REACT_CLASS, "[CallProjectAPI]" + e.getMessage());
        }
    }

    @ReactMethod
    public void setVisualState(ReadableMap data) {
        if (alanButton == null) {
            return;
        }
        try {
            String dataString = JsonConverter.reactToJSON(data).toString();
            alanButton.setVisualState(dataString);
        } catch (Exception e) {
            Log.e(REACT_CLASS, "[setVisualState]" + e.getMessage());
        }
    }

    @ReactMethod
    public void sendText(String data) {
        if (alanButton == null) {
            return;
        }
        alanButton.sendText(data);
    }

    @ReactMethod
    public void playText(String data) {
        if (alanButton == null) {
            return;
        }
        alanButton.playText(data);
    }

    @ReactMethod
    public void playCommand(ReadableMap data) {
        if (alanButton == null) {
            return;
        }
        try {
            String dataString = JsonConverter.reactToJSON(data).toString();
            alanButton.playCommand(dataString, (methodName, response, error) -> {
                if (error != null && !error.isEmpty()) {
                    Log.i("AlanResponse", methodName + " failed with: " + error);
                } else {
                    Log.i("AlanResponse", methodName + " response is: " + response);
                }
            });
        } catch (Exception e) {
            Log.e(REACT_CLASS, e.getMessage());
        }
    }

    @ReactMethod
    public void isActive(Callback callback) {
        if (alanButton == null) {
            return;
        }
        boolean isActive = alanButton.isActive();
        callback.invoke(null, isActive);
    }

    @ReactMethod
    public void setWakewordEnabled(boolean enabled) {
        if (alanButton == null) {
            return;
        }
        alanButton.setWakewordEnabled(enabled);
    }

    @ReactMethod
    public void getWakewordEnabled(Callback callback) {
        if (alanButton == null) {
            return;
        }
        boolean enabled = alanButton.getWakewordEnabled();
        callback.invoke(null, enabled);
    }

}
