package com.gnurt;

import android.Manifest;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.app.ActivityCompat;
import android.text.TextUtils;
import android.util.Log;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import javax.annotation.Nullable;

public class VoiceManagerModule extends ReactContextBaseJavaModule {
    private final ReactApplicationContext reactContext;
    private Handler mHandle;
    private String txt;
    private Callback callback;
    private Promise promise;
    private static final int REQUEST_RECORD_AUDIO_PERMISSION = 1;
    public VoiceManagerModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
        mHandle = new Handler(reactContext.getMainLooper());
    }

    @Override
    public String getName() {
        return "VoiceManager";
    }


    private SpeechService mSpeechService;

    private VoiceRecorder mVoiceRecorder;
    private final VoiceRecorder.Callback mVoiceCallback = new VoiceRecorder.Callback() {

        @Override
        public void onVoiceStart() {
            if (mSpeechService != null) {
                mSpeechService.startRecognizing(mVoiceRecorder.getSampleRate());
            }
        }

        @Override
        public void onVoice(byte[] data, int size) {
            if (mSpeechService != null) {
                mSpeechService.recognize(data, size);
            }
        }

        @Override
        public void onVoiceEnd() {
            if (mSpeechService != null) {
                mSpeechService.finishRecognizing();
            }
        }

    };


    private final ServiceConnection mServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder binder) {
            mSpeechService = SpeechService.from(binder);
            mSpeechService.addListener(mSpeechServiceListener);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mSpeechService = null;
        }

    };


    private void startVoiceRecorder() {
        if (mVoiceRecorder != null) {
            mVoiceRecorder.stop();
        }
        mVoiceRecorder = new VoiceRecorder(mVoiceCallback);
        mVoiceRecorder.start();
    }

    private void stopVoiceRecorder() {
        if (mVoiceRecorder != null) {
            mVoiceRecorder.stop();
            mVoiceRecorder = null;
        }
    }


    @ReactMethod
    public void onResult(final Promise promise) {
        try {
            promise.resolve(txt);
        } catch (Exception e) {
            promise.reject(e);
        }
    }

    private final SpeechService.Listener mSpeechServiceListener =
            new SpeechService.Listener() {
                @Override
                public void onSpeechRecognized(final String text, final boolean isFinal) {
                    Log.d("TAG", "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>>>>>>");

                    if (isFinal) {
                        mVoiceRecorder.dismiss();
                    }
                    if (!TextUtils.isEmpty(text)) {
                        if (!TextUtils.isEmpty(text)) {
                            mHandle.post(new Runnable() {
                                @Override
                                public void run() {
                                    if(isFinal){
                                        WritableMap params = Arguments.createMap();
                                        params.putString("value", text);
                                        params.putBoolean("isFinal", isFinal);
                                        sendEvent(getReactApplicationContext(), "onResult", params);
                                    }

                                }
                            });
                        }
                    }

                }
            };


    @ReactMethod
    public void startSpeech() {
        getReactApplicationContext().bindService(new Intent(getReactApplicationContext(), SpeechService.class), mServiceConnection, Context.BIND_AUTO_CREATE);
        // Start listening to voices
        if (isPermissionGranted()) {
            startVoiceRecorder();
        } else {
            ActivityCompat.requestPermissions(getCurrentActivity(), new String[]{Manifest.permission.RECORD_AUDIO},
                    REQUEST_RECORD_AUDIO_PERMISSION);
        }
    }

    private boolean isPermissionGranted() {
        String permission = Manifest.permission.RECORD_AUDIO;
        int res = getReactApplicationContext().checkCallingOrSelfPermission(permission);
        return res == PackageManager.PERMISSION_GRANTED;
    }


    @ReactMethod
    public void stopSpeech(final com.facebook.react.bridge.Callback callback) {
        Log.d("TAG", "==================>STOP");

        mHandle.post(new Runnable() {
            @Override
            public void run() {
                try {
                    stopVoiceRecorder();

                    // Stop Cloud Speech API
                    mSpeechService.removeListener(mSpeechServiceListener);
                    getReactApplicationContext().unbindService(mServiceConnection);
                    mSpeechService = null;
                    callback.invoke(false);
                } catch (Exception e) {
                    callback.invoke(e.getMessage());
                }
            }
        });
    }


    private void sendEvent(ReactContext reactContext,
                           String eventName,
                           @Nullable WritableMap params) {
        reactContext
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit(eventName, params);
    }


}
