package com.shareable;

import android.app.Activity;
import android.content.Intent;
import android.content.IntentSender;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;

import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.LifecycleEventListener;
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.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResult;
import com.google.android.gms.location.LocationSettingsStatusCodes;


import static android.app.Activity.RESULT_OK;


public class ShareableModule extends ReactContextBaseJavaModule implements LifecycleEventListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<LocationSettingsResult>, ActivityEventListener {
    private static String module = "shareable";
    private ShareableHotspot hotspot;
    private ShareableWifi wifi;
    private ShareableBluetooth bluetooth;

    private static final String LOCATION_INTERVAL_DURATION_PARAMS_KEY = "interval";
    private static final String LOCATION_FAST_INTERVAL_DURATION_PARAMS_KEY = "fastInterval";
    private static final int REQUEST_CHECK_SETTINGS = 100;
    private static final int DEFAULT_INTERVAL_DURATION = 10000;
    private static final int DEFAULT_FAST_INTERVAL_DURATION = DEFAULT_INTERVAL_DURATION / 2 ;
    private static final String TAG = ShareableModule.class.getSimpleName();
    private static final String ERR_USER_DENIED_CODE = "ERR00";
    private static final String ERR_SETTINGS_CHANGE_UNAVAILABLE_CODE = "ERR01";
    private static final String ERR_FAILED_OPEN_DIALOG_CODE = "ERR02";

    private GoogleApiClient googleApiClient;
    private LocationRequest locationRequest;
    private Promise promise;



    public ShareableModule(ReactApplicationContext reactContext) {
        super(reactContext);
        reactContext.addLifecycleEventListener(this);
        reactContext.addActivityEventListener(this);
        hotspot = new ShareableHotspot(reactContext);
        wifi = new ShareableWifi(reactContext);
        bluetooth = new ShareableBluetooth(reactContext);
    }



    @Override
    public void onHostResume() {

    }

    @Override
    public void onHostPause() {

    }

    @Override
    public void onHostDestroy() {
        hotspot.onDestroy();
        bluetooth.onDestroy();

    }

    @Override
    public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_CHECK_SETTINGS && promise != null) {
            if (resultCode == RESULT_OK ) {
                promise.resolve("enabled");
            } else {
                promise.reject(ERR_USER_DENIED_CODE, new LocationException("denied"));
            }
            this.promise = null;
        }
    }

    @Override
    public void onNewIntent(Intent intent) {

    }



    @Override
    public void onConnected(@Nullable Bundle bundle) {
        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
                .addLocationRequest(locationRequest);
        builder.setAlwaysShow(true);
        PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
        result.setResultCallback(this);
    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

    }

    @Override
    public void onResult(@NonNull LocationSettingsResult locationSettingsResult) {
        final Status status = locationSettingsResult.getStatus();
        switch (status.getStatusCode()) {
            case LocationSettingsStatusCodes.SUCCESS:
                if (promise != null) promise.resolve("already-enabled");
                this.promise = null;
                break;
            case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                try {
                    status.startResolutionForResult(getCurrentActivity(), REQUEST_CHECK_SETTINGS);
                } catch (IntentSender.SendIntentException exception) {
                    Log.e(TAG, "Failed to show dialog", exception);
                    if (promise != null) promise.reject(ERR_FAILED_OPEN_DIALOG_CODE, new LocationException("Failed to show dialog", exception));
                    this.promise = null;
                }
                break;
            case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                if (promise != null) promise.reject(ERR_SETTINGS_CHANGE_UNAVAILABLE_CODE, new LocationException("Settings change unavailable"));
                this.promise = null;
                break;
        }
    }

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

    /*
    * Hotspot module for react native
    * */
    @ReactMethod
    public void setHTPermission() {
        hotspot.setPermissions();
    }

    @ReactMethod
    public void isHTEnabled(Callback enabled, Callback disabled) {
        if(hotspot.isEnabled())
            enabled.invoke();
        else
            disabled.invoke();
    }
    @ReactMethod
    public void htEnable(ReadableMap info, Promise promise) {
        hotspot.enable(info, promise);
    }

    @ReactMethod
    public void htDisable(Promise promise) {
        hotspot.disable(promise);
    }

    @ReactMethod
    public void htRestart(ReadableMap info , Promise promise) {
        hotspot.restart(info, promise);
    }

    /*@ReactMethod
    public void getHTIP(Callback ip) {
        ip.invoke(hotspot.getIPAddress());
    }*/
    /* ***************************** end hotspot module ********************************* */

    /*
     * Wifi module for react native
     * */

    @ReactMethod
    public void isWifiEnabled(Callback enabled, Callback disabled) {
        if(wifi.isEnabled())
            enabled.invoke();
        else
            disabled.invoke();
    }

    @ReactMethod
    public void wifiEnable(Promise promise) {
        wifi.enable(promise);
    }

    @ReactMethod
    public void wifiDisable(Promise promise) {
        wifi.disable(promise);
    }

    @ReactMethod
    public void getAllWifi(Promise promise) {
        wifi.getAllWifi(promise);
    }

    @ReactMethod
    public void getSpecificWifi(ReadableMap data, Promise promise) {
        wifi.getSpecificWifi(data.getString("ssid"), promise);
    }

    /*@ReactMethod
    public void getWifiIP(Callback ip) {
        ip.invoke(wifi.getIP());
    }*/

    @ReactMethod
    public void wifiConnect(ReadableMap data, Promise promise) {
        wifi.connect(data.getString("ssid"), data.getString("password"), promise);
    }

    @ReactMethod
    public void wifiDisconnect(Callback success, Callback error) {
        if(wifi.disconnect())
            success.invoke();
        else
            error.invoke();
    }

    @ReactMethod
    public void rescanWifi(Promise promise) {
        wifi.rescanWifi(promise);
    }

    @ReactMethod
    public void rescanSpecificWifi(ReadableMap data, Promise promise) {
        wifi.rescanWifi(data.getString("ssid") ,promise);
    }

    @ReactMethod
    public void getServerAddress(Callback ip) {
        String serverIP = wifi.getServerAddress();
        ip.invoke(serverIP);
    }

    @ReactMethod
    public void setLocationOn(ReadableMap params, Promise promise) {
        if (getCurrentActivity() == null || params == null || promise == null) return;

        this.promise = promise;

        googleApiClient = new GoogleApiClient.Builder(getCurrentActivity())
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this).build();
        googleApiClient.connect();

        locationRequest = LocationRequest.create();
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        locationRequest.setInterval(params.hasKey(LOCATION_INTERVAL_DURATION_PARAMS_KEY) ? params.getInt(LOCATION_INTERVAL_DURATION_PARAMS_KEY) : DEFAULT_INTERVAL_DURATION);
        locationRequest.setFastestInterval(params.hasKey(LOCATION_FAST_INTERVAL_DURATION_PARAMS_KEY) ? params.getInt(LOCATION_FAST_INTERVAL_DURATION_PARAMS_KEY) : DEFAULT_FAST_INTERVAL_DURATION);
    }

    /* ***************************** end wifi module ********************************* */

    /*
     * Bluetooth module for react native (due to the limitation of 8 & 9 android api)
     * */

    @ReactMethod
    public void isBleEnabled(Callback enabled, Callback disabled) {
        if(bluetooth.isEnabled())
            enabled.invoke();
        else
            disabled.invoke();
    }

    @ReactMethod
    public void isBleSupported(Callback supported, Callback error){
        if(bluetooth.isBleSupported())
            supported.invoke();
        else
            error.invoke();
    }

    @ReactMethod
    public void isBeaconSupported(Callback supported, Callback error){
        if(bluetooth.isBeaconSupported())
            supported.invoke();
        else
            error.invoke();
    }

    @ReactMethod
    public void bleEnable(Promise promise) {
        bluetooth.enable(promise);
    }

    @ReactMethod
    public void bleDisable(Promise promise) {
        bluetooth.disable(promise);
    }

    @ReactMethod
    public void bleAdvertise(ReadableMap data ,Promise promise) {
        String message = data.getString("message");
        bluetooth.advertise(message, promise);
    }

    @ReactMethod
    public void bleStopAdvertise(Callback success) {
        bluetooth.stopAdvertise(success);
    }

    @ReactMethod
    public void bleFindBeacon(Promise promise) {
        bluetooth.findBeacons(promise);
    }




}
