package com.shareable;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
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.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.shareable.beacon.Advertise;
import com.shareable.beacon.BeaconStates;
import com.shareable.beacon.Beacons;
import com.shareable.beacon.Receiver;

import org.altbeacon.beacon.BeaconTransmitter;

public class ShareableBluetooth {
    private BluetoothAdapter mBluetoothAdapter = null;
    private ReactApplicationContext mContext;
    private BluetoothStates states = null;
    private Advertise driver;
    private Receiver passenger;
    /*private BluetoothDiscover discover = null;
    private String deviceName;
    private BTServer server;
    private BTClient client;
    private Intent bluetoothService;*/


    /*interface BluetoothDrop {
        void onBluetoothDown();
    }*/

    /*interface BluetoothConneted {
        void onConnected();
        void onError(String error);
        void onConnectionLost();
        void onMessage(String message);
    }*/

    public ShareableBluetooth(ReactApplicationContext context) {
        final BluetoothManager bluetoothManager =
                (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
        this.mBluetoothAdapter = bluetoothManager.getAdapter();
        this.mContext = context;
    }


    public void onDestroy() {
        /*if(server != null)
            server.stop();
        if(client != null)
            client.stop();
        if(bluetoothService != null)
            mContext.stopService(bluetoothService);*/
    }

    /*public void onBluetoothConnected(BluetoothConneted callback) {
        this.connectedCb = callback;
    }*/

    public boolean isEnabled() {
        return mBluetoothAdapter.isEnabled();
    }

    public boolean isBleSupported() {
        if(!this.mContext.getApplicationContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE))
            return false;
        else
            return true;
    }

    public boolean isBeaconSupported() {
        int returnCode = BeaconTransmitter.checkTransmissionSupported(this.mContext);
        switch(returnCode) {
            case BeaconTransmitter.SUPPORTED:
                return true;
            default:
                return false;
        }
    }

    /*public void enable(String blename, String message, Promise enable) {

        IntentFilter bluetoothFilter = new IntentFilter();

        states = new BluetoothStates(blename, message, enable, null);

        bluetoothFilter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
        bluetoothFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);

        mContext.registerReceiver(states, bluetoothFilter);

        mBluetoothAdapter.enable();
    }*/

    public void enable(Promise enable) {

        IntentFilter bluetoothFilter = new IntentFilter();

        states = new BluetoothStates( enable, null);

        bluetoothFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);

        mContext.registerReceiver(states, bluetoothFilter);

        mBluetoothAdapter.enable();
    }
    // change ble name if it already opened
    /*public void change(String blename, String message ,Promise promise) {

        IntentFilter bluetoothFilter = new IntentFilter();

        states = new BluetoothStates(blename, null ,null, null);

        deviceName = mBluetoothAdapter.getName();

        if(!mBluetoothAdapter.setName(blename)) {
            promise.reject("Error", "Unable to change name");
            return;
        }

        initialize(message);

        bluetoothFilter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
        bluetoothFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);

        mContext.registerReceiver(states, bluetoothFilter);

        promise.resolve("Bluetooth Changed");
    }*/


    public void disable(Promise disable) {
        /*if(deviceName != null)
            mBluetoothAdapter.setName(deviceName);*/

        states = new BluetoothStates( null, disable);

        IntentFilter bluetoothFilter = new IntentFilter();

        bluetoothFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);

        mContext.registerReceiver(states, bluetoothFilter);

        mBluetoothAdapter.disable();
    }

    public void advertise(String message, final Promise promise) {
        driver = new Advertise(mContext);

        driver.onStart(message, new BeaconStates() {
            @Override
            public void onAdvertised() {
                promise.resolve("Beacon advertised");
            }

            @Override
            public void onFailure() {
                promise.reject("Error", "Unable to advertise a beacon");
            }
        });

    }

    public void stopAdvertise(Callback success) {
        driver.onStop();
        success.invoke();
    }

    public void findBeacons(Promise promise) {
        passenger = new Receiver(mContext, mHandler, promise);

        passenger.onStart();
    }


    /*public boolean discoverable() {
        if (mBluetoothAdapter.getScanMode() !=
                mBluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
            Method method;
            try {
                method = mBluetoothAdapter.getClass().getMethod("setScanMode", int.class, int.class);
                method.invoke(mBluetoothAdapter,mBluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, 0);

                return true;
            }
            catch (Exception e){
                e.printStackTrace();
                return false;
            }
        }
        return false;
    }*/

    /*public void discover(String blenme, Promise promise) {
        if(mBluetoothAdapter.isDiscovering())
            mBluetoothAdapter.cancelDiscovery();

        IntentFilter bluetoothDiscover = new IntentFilter();
        bluetoothDiscover.addAction(BluetoothDevice.ACTION_FOUND);
        bluetoothDiscover.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        discover = new BluetoothDiscover(blenme, promise);

        mContext.registerReceiver(discover, bluetoothDiscover);

        mBluetoothAdapter.startDiscovery();
    }*/

    /*public void connect(String mac) {
        client = new BTClient(mHandler);

        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(mac);

        client.connect(device);
    }*/

    /*private void initialize(String message) {
        // this service listening if the app goes to close in order to change ble name to the old one
        bluetoothService = new Intent(mContext, BluetoothService.class);
        bluetoothService.putExtra("name", deviceName);
        mContext.startService(bluetoothService);


        server = new BTServer(mHandler, message);
        server.start();
    }*/

    /*public void onBluetoothDrop(BluetoothDrop callback) {
        this.callback = callback;
    }*/


    /*public boolean disconnect() {
        return client.disconnect();
    }*/

    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what) {
                case Constants.ON_DECODEBYTE_SUCCESS:
                    Bundle value = msg.getData();
                    String message = value.getString("value");
                    WritableMap data = Arguments.createMap();
                    data.putString("message", message);
                    Log.i("ble", message);
                    mContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onBeaconFound", data);
                    // disable ble scan after message sent
                    passenger.onStop();
                    break;
                case Constants.ON_DECODEBYTE_ERROR:
                    mContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onError", null);
                    break;
            }
        }
    };



    class BluetoothStates extends BroadcastReceiver {
        private Promise enable;
        private Promise disable;

        public BluetoothStates(Promise enable, Promise disable) {
            this.enable = enable;
            this.disable = disable;
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
                final int bluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
                switch (bluetoothState) {
                    case BluetoothAdapter.STATE_ON:
                        /*if(this.bluname != null) {
                            deviceName = mBluetoothAdapter.getName();
                            mBluetoothAdapter.setName(this.bluname);

                            initialize(message);

                            this.enable.resolve("Bluetooth Enabled");
                        } else {
                            // passenger's bluetooth opened
                            this.enable.resolve("Bluetooth Enabled");
                        }*/
                        if(this.enable != null) {
                            enable.resolve("Bluetooth enabled");
                            context.unregisterReceiver(states);
                        }

                        break;
                        //
                    case BluetoothAdapter.STATE_OFF:
                        /*if(this.disable != null) {
                            mContext.unregisterReceiver(states);
                            if (deviceName != null) {
                                mContext.stopService(new Intent(context, BluetoothService.class));
                                server.stop();
                            } else {
                                if(client != null)
                                    client.stop();
                            }
                            this.disable.resolve("Bluetooth Disabled");
                        }

                        else {
                            // user turned off his bluetooth from device

                            mContext.unregisterReceiver(states);

                            if(server != null)
                                server.stop();
                            if(client != null)
                                client.stop();
                            if(bluetoothService != null)
                                mContext.stopService(bluetoothService);
                        }*/
                        if(this.disable != null) {
                            disable.resolve("Bluetooth Disabled");
                            context.unregisterReceiver(states);
                        }

                        break;
                }
            }
        }
    }

}
