package com.phlx.anchor_collect_flutter;

import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;


import com.phlx.anchor_collect_flutter.ble.BleManagers;
import com.phlx.anchor_collect_flutter.ble.Configs;
import com.phlx.anchor_collect_flutter.ble.OnBleSearchListener;
import com.uhf.linkage.Linkage;
import com.uhf.structures.InventoryData;
import com.uhf.structures.InventoryParams;
import com.uhf.structures.OnBluetoothListener;
import com.uhf.structures.OnInventoryListener;
import com.uhf.structures.Rfid_Value;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.wandersnail.ble.Connection;
import cn.wandersnail.ble.ConnectionState;
import cn.wandersnail.ble.Device;
import cn.wandersnail.ble.EasyBLE;
import cn.wandersnail.ble.EventObserver;
import cn.wandersnail.ble.Request;
import cn.wandersnail.ble.RequestBuilder;
import cn.wandersnail.ble.RequestBuilderFactory;
import cn.wandersnail.ble.RequestType;
import cn.wandersnail.ble.callback.MtuChangeCallback;
import cn.wandersnail.ble.callback.NotificationChangeCallback;
import cn.wandersnail.commons.observer.Observe;
import cn.wandersnail.commons.poster.RunOn;
import cn.wandersnail.commons.poster.Tag;
import cn.wandersnail.commons.poster.ThreadMode;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;

/**
 * rfid插件
 */
public class RfidPlugin implements FlutterPlugin, MethodChannel.MethodCallHandler, OnBleSearchListener, OnInventoryListener, EventObserver {

    private MethodChannel _methodChannel;
    private static Linkage link;

    private Handler handler;
    private BleManagers bleManagers;

    private ConnectManger connectManger;

    private Context mContext;

    private List<Device> mList;

    private Map<String, String> map;
    private List<InventoryData> dataList;
    private Device device;

    private boolean isFirst = true;

    // 事件派发对象
    private EventChannel.EventSink _eventSink;

    private EventChannel.StreamHandler _streamHandler = new EventChannel.StreamHandler() {
        @Override
        public void onListen(Object arguments, EventChannel.EventSink events) {
            _eventSink = events;
        }

        @Override
        public void onCancel(Object arguments) {
            _eventSink = null;
        }
    };

    @Override
    public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {

        getLinkage().setOnInventoryListener(this);
        mContext = binding.getApplicationContext();
        bleManagers = BleManagers.from(mContext);
        connectManger = ConnectManger.from(getLinkage());
        EasyBLE.getInstance().registerObserver(this);
        mList = new ArrayList<>();
        dataList = new ArrayList<>();
        map = new HashMap<>();
        _methodChannel = new MethodChannel(binding.getBinaryMessenger(), "flutter_rfid_plugin");
        _methodChannel.setMethodCallHandler(this);
        EventChannel channel = new EventChannel(binding.getBinaryMessenger(), "flutter_rfid_plugin/event");
        channel.setStreamHandler(_streamHandler);
        handler = new Handler(Looper.getMainLooper());
    }

    @Override
    public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
        _methodChannel.setMethodCallHandler(null);
    }

    public void getVersion() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                String rm70xxVersion = connectManger.getRm70xxVersion();
                Log.e("lei", "getVersion: " + rm70xxVersion);

                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        Map<String, String> rm70xx_version = new HashMap<>();
                        rm70xx_version.put("key", "get_version");
                        rm70xx_version.put("get_version_status", ConnectManger.isSucc?"0":"-1");
                        rm70xx_version.put("value_RM70XX_VERSION", ConnectManger.RM70XX_VERSION);
                        rm70xx_version.put("value_RM70XX_SERIAL_VERSION", ConnectManger.RM70XX_SERIAL_VERSION);
                        rm70xx_version.put("value_VERSION", ConnectManger.VERSION);
                        rm70xx_version.put("value_SERIAL_VERSION", ConnectManger.SERIAL_VERSION);
                        _eventSink.success(rm70xx_version);
                    }
                });
            }
        }).start();
    }

    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {

        if (call.method.equals("init_rfid")) {
            initModule();
        } else if (call.method.equals("scan_device")) {
            if (mList.size() > 0) {
                mList.clear();
            }
            bleManagers.searchBleDevices(this);
        } else if (call.method.equals("scan_stop")) {
            bleManagers.cancelBLESearch();
        } else if (call.method.equals("connect_device")) {
            //需要一个名字的参数
            for (int i = 0; i < mList.size(); i++) {
                if (mList.get(i).getName().equals(call.argument("name"))) {
                    device = mList.get(i);
                    bleManagers.connectBleDevice(device);
                }
            }
        } else if (call.method.equals("disconnect_device")) {
            bleManagers.disConnectBLE(device);
        } else if (call.method.equals("start_inventory")) {
//            getLinkage().setOnInventoryListener(this);
            isFirst = false;
//            InventoryParams inventoryParams = new InventoryParams();
//            inventoryParams.address = 0;
//            inventoryParams.inventoryArea = 1;
//            inventoryParams.len = 6;
//            getLinkage().Radio_SetInventoryParams(inventoryParams);
            //TODO 无效果，加延时
            getLinkage().startInventory(1, 0);
            map.clear();
            dataList.clear();
        } else if (call.method.equals("stop_inventory")) {
            getLinkage().stopInventory();
        }

    }

    private void initModule() {
        getLinkage().setRFModuleType(2);
        /**设置设备连接方式为蓝牙连接*/
        getLinkage().setRFConnectMode(2);
    }

    public static Linkage getLinkage() {
        if (link == null) {
            link = new Linkage();
            link.initRFID();
        }
        return link;
    }


    @Override
    public void getInventoryData(InventoryData inventoryData) {
        Log.e("why:inventoryData:", inventoryData.toString());
        if (inventoryData == null) return;
        Map<String, String> result = new HashMap<>();
        String epc = TextUtil.byteToHexString(inventoryData.getEPC_Data(), inventoryData.getEpcLength()).substring(1);
        String tid = TextUtil.byteToHexString(inventoryData.getData(), inventoryData.getDataLength());
        String tag = epc + tid;
        Log.e("why:tag:", tag);
        if (!map.containsKey(tag)) {
            map.put(tag, epc);
            dataList.add(inventoryData);
        }
        if (!isFirst) {
            Log.e("why:isFirst:", isFirst+"");
            getLinkage().stopInventory();
            isFirst = true;
            handler.post(new Runnable() {
                @Override
                public void run() {
                    Log.e("why:", "getInventoryData:"+TextUtil.byteToHexString(dataList.get(0).getEPC_Data(), dataList.get(0).getEpcLength()));
                    result.put("key", "InventoryData");
                    result.put("value", TextUtil.byteToHexString(dataList.get(0).getEPC_Data(), dataList.get(0).getEpcLength()));
                    _eventSink.success(result);
                }
            });
        }
    }

    @Override
    public void onStartDiscovery() {

    }

    @Override
    public void onBleDeviceFound(Device device) {
        Log.e("lei", "onBleDeviceFound: " + device.toString());
        if (!mList.contains(device) && !TextUtils.isEmpty(device.getName())) {
            mList.add(device);
            Map<String, String> BleDevices = new HashMap<>();
            BleDevices.put("key", "Device");
            BleDevices.put("value", device.getName());
            _eventSink.success(BleDevices);
        }

    }

    @Override
    public void onBleError(String e) {

    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Tag("onConnectionStateChanged")
    @Observe
    @RunOn(ThreadMode.MAIN)
    @Override
    public void onConnectionStateChanged(@NonNull Device device) {
        ConnectionState connectionState = device.getConnectionState();
        if (connectionState == ConnectionState.SCANNING_FOR_RECONNECTION) {
        } else if (connectionState == ConnectionState.DISCONNECTED) {
            Map<String, String> BleDevices = new HashMap<>();
            BleDevices.put("key", "DISCONNECTED");
            _eventSink.success(BleDevices);
        } else if (connectionState == ConnectionState.CONNECTING) {
        } else if (connectionState == ConnectionState.CONNECTED) {
            //TODO
        } else if (connectionState == ConnectionState.SERVICE_DISCOVERING) {
        } else if (connectionState == ConnectionState.SERVICE_DISCOVERED) {
            List<BluetoothGattService> services = bleManagers.getConnection().getGatt().getServices();
            for (BluetoothGattService service : services) {
                if (!service.getUuid().toString().contains("0000180")) {
                    Configs.uuid_service = service.getUuid();
                    List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
                    Log.e("uuid_service", Configs.uuid_service.toString());
                    for (BluetoothGattCharacteristic characteristic : characteristics) {
                        String characteristicType = getCharacteristicType(characteristic);
                        if (characteristicType.contains("WRITE")) {
                            Configs.uuid_write = characteristic.getUuid();
                            Log.e("uuid_write", Configs.uuid_write.toString());
                        }
                        if (characteristicType.contains("NOTIFY")) {
                            Configs.uuid_notify = characteristic.getUuid();
                            Log.e("uuid_notify", Configs.uuid_notify.toString());
                        }
                        if (characteristicType.contains("INDICATE")) {
                            Configs.uuid_indicate = characteristic.getUuid();
                            Log.e("uuid_indicate", Configs.uuid_indicate.toString());
                        }
                    }
                }
            }
            //设置MTU
            Connection connection = EasyBLE.getInstance().getConnection(device);
            RequestBuilder<MtuChangeCallback> builder = new RequestBuilderFactory().getChangeMtuBuilder(512);
            Request request = builder.setCallback(new MtuChangeCallback() {
                @Override
                public void onMtuChanged(@NonNull Request request, int mtu) {
                    Log.e("EasyBLE", "MTU修改成功，新值：" + mtu);
                    setNotification();
                }

                @Override
                public void onRequestFailed(@NonNull Request request, int failType, int gattStatus, @Nullable Object value) {

                }
            }).build();
            connection.execute(request);
        }
    }


    private String getCharacteristicType(BluetoothGattCharacteristic characteristic) {
        StringBuilder sb = new StringBuilder();
        int[] properties = new int[]{BluetoothGattCharacteristic.PROPERTY_WRITE, BluetoothGattCharacteristic.PROPERTY_INDICATE, BluetoothGattCharacteristic.PROPERTY_NOTIFY, BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE, BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE};
        String[] propertyStrs = new String[]{"WRITE", "INDICATE", "NOTIFY", "READ", "SIGNED_WRITE", "WRITE_NO_RESPONSE"};
        for (int i = 0; i < properties.length; i++) {
            int property = properties[i];
            if ((characteristic.getProperties() & property) != 0) {
                if (sb.length() != 0) {
                    sb.append(", ");
                }
                sb.append(propertyStrs[i]);
            }
        }
        return sb.toString();
    }

    private void setNotification() {
        boolean isEnabled = bleManagers.getConnection().isNotificationOrIndicationEnabled(Configs.uuid_service, Configs.uuid_notify);

        RequestBuilder<NotificationChangeCallback> builder = new RequestBuilderFactory().getSetNotificationBuilder(Configs.uuid_service, Configs.uuid_notify, !isEnabled);
        builder.build().execute(bleManagers.getConnection());
    }


    @Observe
    @Override
    public void onNotificationChanged(@NonNull Request request, boolean isEnabled) {
        if (request.getType() == RequestType.SET_NOTIFICATION) {
            if (isEnabled) {
                bleManagers.startBleService();
                try {
                    Thread.sleep(1000);
                    getVersion();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            } else {
            }
        } else {
            if (isEnabled) {
                bleManagers.startBleService();
            } else {
            }
        }
    }


}
