package com.qianmi.hardwarekit.bluetooth;


import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

/**
 * 蓝牙设备发现
 * Created by xiayinglin on 2017/4/5.
 */
public class BluetoothDeviceFinder {


    public static final String BONDED = "Bluetooth.device.bonded";
    public static final String DISCOVERY_OVER = "Bluetooth.discovery.over";
    public static final String DISCOUNT = "Bluetooth.discount";
    public static final String OFF = "Bluetooth.off";
    public static final String FOUNDED = "Bluetooth.device.founded";

    private ReactApplicationContext reactContext;

    //系统蓝牙adapter数据
    private BluetoothAdapter mBluetoothAdapter = null;

    private BroadcastReceiver mFindBlueToothReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                if (!TextUtils.isEmpty(device.getName())) {
                    Log.d(BluetoothDeviceFinder.class.getSimpleName(), "ACTION_FOUND -> name: " + device.getName() + " address: " + device.getAddress());
                    BluetoothDeviceFinder.this.event(FOUNDED, BluetoothDeviceFinder.this.device(device));
                }

            } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
                int connectState = device.getBondState();
                Log.d(BluetoothDeviceFinder.class.getSimpleName(), "ACTION_BOND_STATE_CHANGED -> name: " + device.getName() + " address: " + device.getAddress());
                switch (connectState) {
                    case BluetoothDevice.BOND_NONE:
                        // 配对
//                        try {
//                            Method createBondMethod = BluetoothDevice.class.getMethod("createBond");
//                            createBondMethod.invoke(device);
//                        } catch (Exception e) {
//                            e.printStackTrace();
//                        }
//                        break;
                        // 已配对
                    case BluetoothDevice.BOND_BONDED:
                        BluetoothDeviceFinder.this.event(BONDED, BluetoothDeviceFinder.this.device(device));
                        break;
                }
            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
                BluetoothDeviceFinder.this.event(DISCOVERY_OVER, null);
            } else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action) || BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED.equals(action)) {
                //设备断开
                BluetoothDeviceFinder.this.event(DISCOUNT, BluetoothDeviceFinder.this.device(device));
            } else if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
                BluetoothDeviceFinder.this.event(BONDED, BluetoothDeviceFinder.this.device(device));
            } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
                int blueState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
                if (BluetoothAdapter.STATE_OFF == blueState) {
                    //设备断开
                    BluetoothDeviceFinder.this.event(OFF, null);
                }
            }
        }
    };


    private BluetoothDeviceFinder() {
    }


    public static BluetoothDeviceFinder me() {
        return new BluetoothDeviceFinder();
    }


    public BluetoothDeviceFinder from(ReactApplicationContext context) {
        this.reactContext = context;
        inReceiver();

        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (null != mBluetoothAdapter && mBluetoothAdapter.isDiscovering()) {
            mBluetoothAdapter.cancelDiscovery();
        }
        return this;
    }

    /**
     * 设备绑定
     *
     * @param address
     * @return
     */
    boolean bonded(String address) {
        boolean success = true;
        BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
        if (device.getBondState() == BluetoothDevice.BOND_NONE) {// 未绑定
            try {
                Method createBondMethod = BluetoothDevice.class.getMethod("createBond");
                success = (Boolean) createBondMethod.invoke(device);
            } catch (Exception e) {
                success = false;
                e.printStackTrace();
            }
        }
        Log.d(getClass().getSimpleName(), "bluetooth address:" + address + " bonded .");
        return success;
    }

    boolean removeBond(String address) {
        boolean success = true;
        BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
        if (device.getBondState() == BluetoothDevice.BOND_BONDED) {// 未绑定
            try {
                Method createBondMethod = BluetoothDevice.class.getMethod("removeBond");
                success = (Boolean) createBondMethod.invoke(device);
            } catch (Exception e) {
                success = false;
                e.printStackTrace();
            }
        }
        Log.d(getClass().getSimpleName(), "bluetooth address:" + address + " bonded .");
        return success;
    }


    /**
     * 设备查询
     *
     * @return
     */
    boolean discovery() {
        if (null == mBluetoothAdapter) {
            return false;
        }
        if (mBluetoothAdapter.isDiscovering()) {
            mBluetoothAdapter.cancelDiscovery();
        }
        return mBluetoothAdapter.startDiscovery();
    }


    boolean cancelDiscovery() {
        return null != mBluetoothAdapter && mBluetoothAdapter.isDiscovering() && mBluetoothAdapter.cancelDiscovery();
    }

    /**
     * 已经完成配对的产品
     *
     * @return
     */
    Set<BluetoothDevice> paired() {
        return null != mBluetoothAdapter ? mBluetoothAdapter.getBondedDevices() : new HashSet<BluetoothDevice>();
    }


    void destroy() {
        // Make sure we're not doing discovery anymore
        if (null != mBluetoothAdapter) {
            mBluetoothAdapter.cancelDiscovery();
        }
        unReceiver();
    }


    protected void inReceiver() {
        //注册蓝牙数据变化广播
        IntentFilter iff = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        iff.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        iff.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        iff.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
        iff.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
        iff.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
        iff.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        iff.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
        this.reactContext.registerReceiver(mFindBlueToothReceiver, iff);
    }


    protected void unReceiver() {
        try {
            if (null != mFindBlueToothReceiver) {
                this.reactContext.unregisterReceiver(mFindBlueToothReceiver);
            }
        } catch (Exception e) {
            Log.e(getClass().getSimpleName(), e.toString());
        }

    }


    protected WritableMap device(BluetoothDevice d) {
        WritableMap device = Arguments.createMap();
        device.putString("name", d.getName());
        device.putString("address", d.getAddress());
        int state = BluetoothDevice.BOND_BONDED == d.getBondState() ? 1 : (BluetoothDevice.BOND_NONE == d.getBondState() ? -1 : 0);
        device.putString("bondState", String.valueOf(state));
        return device;
    }

    protected void event(String eventName, @Nullable WritableMap params) {
        if (null != this.reactContext) {
            if (null == params) {
                params = Arguments.createMap();
            }
            Log.d(BluetoothDeviceFinder.class.getSimpleName(), "event -> name: " + eventName + " writableMap: " + params.toString());
            this.reactContext
                    .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                    .emit(eventName, params);
        }
    }
}