const common = require('./common.js');
const app = getApp();
const bluetoothDevices = {
    ZX16D: require('./bluetooth/ZX16D.js'),
    FMBMS: require('./bluetooth/FMBMS.js'),
    LFBMS: require('./bluetooth/LFBMS.js'),
    JYBMS: require('./bluetooth/LFBMS.js'),
    BLFM: require('./bluetooth/BLFM.js'),
    ZXBT: require('./bluetooth/ZXBT.js'),
    NBAEP: require('./bluetooth/ZX16D.js'),
    TESTBT: require('./bluetooth/ZXBT_JL.js')
};
function initBluetooth() {
    uni.onBluetoothAdapterStateChange((res) => {
        console.log(res);
        Object.keys(app.globalData.adapterStateChangeFunc).forEach((n) => app.globalData.adapterStateChangeFunc[n](res));
    });
    uni.onBLEConnectionStateChange((res) => {
        console.log(res);
        if (app.globalData.connectionState[res.deviceId]) {
            app.globalData.connectionState[res.deviceId].connected = res.connected;
            const device = app.globalData.connectionState[res.deviceId].device;
            if (app.globalData.connectionStateChangeFunc[device.mac_id]) {
                Object.keys(app.globalData.connectionStateChangeFunc[device.mac_id]).forEach((p) => app.globalData.connectionStateChangeFunc[device.mac_id][p](res));
            }
        }
    });
    uni.onBLECharacteristicValueChange((res) => {
        console.log(res);
        if (app.globalData.connectionState[res.deviceId]) {
            const device = app.globalData.connectionState[res.deviceId].device;
            if (
                res.serviceId.toUpperCase() == bluetoothDevices[device.device_type].readServiceID.toUpperCase() &&
                res.characteristicId.toUpperCase() == bluetoothDevices[device.device_type].readID.toUpperCase()
            ) {
                var data = bluetoothDevices[device.device_type].readData(device, res.value, app.globalData.connectionState[res.deviceId].data);
                if (data) {
                    app.globalData.connectionState[res.deviceId].data = data;
                    if (app.globalData.characteristicStateChangeFunc[device.mac_id]) {
                        Object.keys(app.globalData.characteristicStateChangeFunc[device.mac_id]).forEach((p) =>
                            app.globalData.characteristicStateChangeFunc[device.mac_id][p](data)
                        );
                    }
                    console.log(app.globalData.connectionState[res.deviceId].data);
                }
            }
        }
    });
}
function onAdapterStateChange(name, callback) {
    app.globalData.adapterStateChangeFunc[name] = callback;
}
function offAdapterStateChange(name) {
    delete app.globalData.adapterStateChangeFunc[name];
}
function onConnectionStateChange(macid, name, callback) {
    if (!app.globalData.connectionStateChangeFunc[macid]) {
        app.globalData.connectionStateChangeFunc[macid] = {};
    }
    app.globalData.connectionStateChangeFunc[macid][name] = callback;
}
function offConnectionStateChange(macid, name) {
    if (app.globalData.connectionStateChangeFunc[macid]) {
        delete app.globalData.connectionStateChangeFunc[macid][name];
    }
}
function onCharacteristicStateChange(macid, name, callback) {
    if (!app.globalData.characteristicStateChangeFunc[macid]) {
        app.globalData.characteristicStateChangeFunc[macid] = {};
    }
    app.globalData.characteristicStateChangeFunc[macid][name] = callback;
}
function offCharacteristicStateChange(macid, name) {
    if (app.globalData.characteristicStateChangeFunc[macid]) {
        delete app.globalData.characteristicStateChangeFunc[macid][name];
    }
}
function getAdapterState(callback = () => {}, fail = () => {}) {
    uni.getBluetoothAdapterState({
        success: (res) => {
            callback(res);
        },
        fail: (res) => {
            console.log(res);
            fail(res);
        }
    });
}
function openBluetoothAdapter(callback = () => {}, fail = () => {}) {
    uni.openBluetoothAdapter({
        success: (res) => {
            callback(res);
        },
        fail: (res) => {
            console.log(res);
            fail(res);
        }
    });
}
function closeBluetoothAdapter(callback = () => {}, fail = () => {}) {
    uni.closeBluetoothAdapter({
        success: (res) => {
            app.globalData.adapterStateChangeFunc = {};
            app.globalData.connectionStateChangeFunc = {};
            app.globalData.characteristicStateChangeFunc = {};
            app.globalData.connectionState = {};
            callback(res);
        },
        fail: (res) => {
            console.log(res);
            fail(res);
        }
    });
}
function acceptDevice(device) {
    //console.log(bluetoothDevices[device.device_type].acceptDevice(device))
    return bluetoothDevices[device.device_type] && bluetoothDevices[device.device_type].acceptDevice(device) ? true : false;
}
function isSingleBT(device_type) {
    if (bluetoothDevices[device_type] && bluetoothDevices[device_type].isSingleBt) {
        return bluetoothDevices[device_type].isSingleBt();
    }
    return false;
}
function isSginleBtByMacid(macid) {
    const deviceId = Object.keys(app.globalData.connectionState).find((i) => app.globalData.connectionState[i].device.mac_id == macid);
    console.log(app.globalData.connectionState);
    if (deviceId == undefined) {
        return false;
    }
    return isSingleBT(app.globalData.connectionState[deviceId].device.device_type);
}
function haveBMSForBT(device_type) {
    if (bluetoothDevices[device_type] && bluetoothDevices[device_type].haveBms) {
        return bluetoothDevices[device_type].haveBms();
    }
    return false;
}
function findDevice(device, callback = () => {}, fail = () => {}) {
    var deviceId = '';
    if (!bluetoothDevices[device.device_type] || !bluetoothDevices[device.device_type].acceptDevice(device)) {
        return;
    }
    uni.startBluetoothDevicesDiscovery({
        success(res) {
            console.log(res);
            uni.getBluetoothDevices({
                success: (res) => {
                    console.log(res);
                    res.devices.forEach((data) => {
                        if (bluetoothDevices[device.device_type].isDevice(device, data)) {
                            uni.offBluetoothDeviceFound();
                            uni.stopBluetoothDevicesDiscovery();
                            deviceId = data.deviceId;
                            if (app.globalData.connectionState[deviceId]) {
                                app.globalData.connectionState[deviceId].device = device;
                            } else {
                                app.globalData.connectionState[deviceId] = {
                                    device: device,
                                    deviceId: deviceId,
                                    connected: false,
                                    data: {}
                                };
                            }
                            callback(deviceId);
                        }
                    });
                    setTimeout(function () {
                        if (!deviceId) {
                            uni.offBluetoothDeviceFound();
                            uni.stopBluetoothDevicesDiscovery();
                            fail();
                        }
                    }, 5000);
                },
                fail(res) {
                    uni.stopBluetoothDevicesDiscovery();
                    console.log(res);
                    fail(res);
                }
            });
            uni.onBluetoothDeviceFound((res) => {
                console.log(res);
                res.devices.forEach((data) => {
                    if (bluetoothDevices[device.device_type].isDevice(device, data)) {
                        uni.offBluetoothDeviceFound();
                        uni.stopBluetoothDevicesDiscovery();
                        deviceId = data.deviceId;
                        if (app.globalData.connectionState[deviceId]) {
                            app.globalData.connectionState[deviceId].device = device;
                        } else {
                            app.globalData.connectionState[deviceId] = {
                                device: device,
                                deviceId: deviceId,
                                connected: false,
                                data: {}
                            };
                        }
                        callback(deviceId);
                    }
                });
            });
        },
        fail(res) {
            console.log(res);
            fail(res);
        }
    });
}
function connectDevice(device, callback = () => {}, fail = () => {}) {
    if (!bluetoothDevices[device.device_type] || !bluetoothDevices[device.device_type].acceptDevice(device)) {
        return;
    }
    console.log(app.globalData.connectionState);
    const deviceId = Object.keys(app.globalData.connectionState).find((i) => app.globalData.connectionState[i].device.mac_id == device.mac_id);
    if (deviceId == undefined) {
        findDevice(
            device,
            (deviceId) => {
                connectDevice(device, callback, fail);
            },
            (res) => {
                fail(res);
            }
        );
        return;
    } else {
        if (app.globalData.connectionState[deviceId].connected) {
            callback();
            return;
        }
    }
    uni.createBLEConnection({
        deviceId: deviceId,
        success: (res) => {
            console.log(res);
            app.globalData.connectionState[deviceId] = {
                device: device,
                deviceId: deviceId,
                connected: true,
                data: {}
            };
            alterConnect(
                device,
                deviceId,
                (res) => {
                    console.log(res);
                    callback(res);
                },
                (res) => {
                    console.log(res);
                    closeDevice(deviceId);
                    fail(res);
                }
            );
        },
        fail(res) {
            console.log(res);
            if (res.errCode == -1) {
                closeDevice(
                    deviceId,
                    (res) => {
                        connectDevice(device, callback, fail);
                    },
                    (res) => {
                        fail(res);
                    }
                );
            } else {
                fail(res);
            }
        }
    });
}
function alterConnect(device, deviceId, callback = () => {}, fail = () => {}) {
    if (!bluetoothDevices[device.device_type] || !bluetoothDevices[device.device_type].acceptDevice(device)) {
        return;
    }
    uni.getBLEDeviceServices({
        deviceId: deviceId,
        success(res) {
            console.log(res);
            uni.getBLEDeviceCharacteristics({
                deviceId: deviceId,
                serviceId: bluetoothDevices[device.device_type].writeServiceID,
                success(res) {
                    console.log(res);
                    uni.getBLEDeviceCharacteristics({
                        deviceId: deviceId,
                        serviceId: bluetoothDevices[device.device_type].readServiceID,
                        success(res) {
                            console.log(res);
                            uni.notifyBLECharacteristicValueChange({
                                state: true,
                                deviceId: deviceId,
                                serviceId: bluetoothDevices[device.device_type].readServiceID,
                                characteristicId: bluetoothDevices[device.device_type].readID,
                                success(res) {
                                    console.log(res);
                                    if (bluetoothDevices[device.device_type].MTU) {
                                        uni.setBLEMTU({
                                            deviceId: deviceId,
                                            mtu: bluetoothDevices[device.device_type].MTU,
                                            success: (res) => {
                                                console.log('setBLEMTU success>>', res);
                                                if (bluetoothDevices[device.device_type].alterConnect) {
                                                    var data = bluetoothDevices[device.device_type].alterConnect(device, deviceId);
                                                    if (data) {
                                                        writeData(device, deviceId, data, callback, fail);
                                                    } else {
                                                        callback(res);
                                                    }
                                                } else {
                                                    callback(res);
                                                }
                                            },
                                            fail: (res) => {
                                                console.log('setBLEMTU fail>>', res);
                                            }
                                        });
                                    } else {
                                        if (bluetoothDevices[device.device_type].alterConnect) {
                                            var data = bluetoothDevices[device.device_type].alterConnect(device, deviceId);
                                            if (data) {
                                                writeData(device, deviceId, data, callback, fail);
                                            } else {
                                                callback(res);
                                            }
                                        } else {
                                            callback(res);
                                        }
                                    }
                                },
                                fail(res) {
                                    fail(res);
                                }
                            });
                        },
                        fail(res) {
                            fail(res);
                        }
                    });
                },
                fail(res) {
                    fail(res);
                }
            });
        },
        fail(res) {
            fail(res);
        }
    });
}
function closeDevice(macid, callback = () => {}, fail = () => {}) {
    const deviceId = Object.keys(app.globalData.connectionState).find((i) => app.globalData.connectionState[i].device.mac_id == macid);
    if (deviceId == undefined) {
        fail();
        return;
    } else {
        if (!app.globalData.connectionState[deviceId].connected) {
            callback();
            return;
        }
    }
    const device = app.globalData.connectionState[deviceId].device;
    uni.closeBLEConnection({
        deviceId: deviceId,
        success: (res) => {
            console.log(res);
            if (app.globalData.connectionState[deviceId]) {
                app.globalData.connectionState[deviceId].connected = false;
            }
            callback(res);
        },
        fail(res) {
            console.log(res);
            fail(res);
        }
    });
}
function bmsInfo(macid) {
    const deviceId = Object.keys(app.globalData.connectionState).find((i) => app.globalData.connectionState[i].device.mac_id == macid);
    if (deviceId == undefined) {
        return false;
    }
    const device = app.globalData.connectionState[deviceId].device;
    if (!bluetoothDevices[device.device_type].bmsInfo) {
        return false;
    }
    return bluetoothDevices[device.device_type].bmsInfo(device, deviceId, app.globalData.connectionState[deviceId].data);
}
function bmsSet(macid, name, vars, callback = () => {}, fail = () => {}) {
    const deviceId = Object.keys(app.globalData.connectionState).find((i) => app.globalData.connectionState[i].device.mac_id == macid);
    if (deviceId == undefined) {
        fail();
        return false;
    }
    const device = app.globalData.connectionState[deviceId].device;
    if (!bluetoothDevices[device.device_type].bmsSet) {
        fail();
        return false;
    }
    var data = bluetoothDevices[device.device_type].bmsSet(device, deviceId, name, vars);
    if (data) {
        writeData(device, deviceId, data, callback, fail);
        return true;
    }
    fail();
    return false;
}
function writeData(device, deviceId, data, callback = () => {}, fail = () => {}) {
    if (data.length == 0) {
        return;
    }
    const buffer = common.toArrayBuffer(data.shift());
    console.log(buffer);
    uni.writeBLECharacteristicValue({
        deviceId: deviceId,
        serviceId: bluetoothDevices[device.device_type].writeServiceID,
        characteristicId: bluetoothDevices[device.device_type].writeID,
        value: buffer,
        success(res) {
            console.log(res);
            if (data.length == 0) {
                callback(res);
            } else {
                setTimeout(() => {
                    writeData(device, deviceId, data, callback, fail);
                }, 500);
            }
        },
        fail(res) {
            console.log(res);
            fail(res);
        }
    });
}
function stateUpdate(macid, callback = () => {}, fail = () => {}) {
    const deviceId = Object.keys(app.globalData.connectionState).find((i) => app.globalData.connectionState[i].device.mac_id == macid);
    if (deviceId == undefined) {
        fail();
        return false;
    }
    const device = app.globalData.connectionState[deviceId].device;
    if (!bluetoothDevices[device.device_type].stateUpdate) {
        fail();
        return false;
    }
    var data = bluetoothDevices[device.device_type].stateUpdate(device, deviceId);
    if (data) {
        writeData(device, deviceId, data, callback, fail);
        return true;
    }
    fail();
    return false;
}
function turnOn(macid, callback = () => {}, fail = () => {}) {
    const deviceId = Object.keys(app.globalData.connectionState).find((i) => app.globalData.connectionState[i].device.mac_id == macid);
    if (deviceId == undefined) {
        fail();
        return false;
    }
    const device = app.globalData.connectionState[deviceId].device;
    if (!bluetoothDevices[device.device_type].turnOn) {
        fail();
        return false;
    }
    var data = bluetoothDevices[device.device_type].turnOn(device, deviceId);
    if (data) {
        writeData(device, deviceId, data, callback, fail);
        return true;
    }
    fail();
    return false;
}
function turnOff(macid, callback = () => {}, fail = () => {}) {
    const deviceId = Object.keys(app.globalData.connectionState).find((i) => app.globalData.connectionState[i].device.mac_id == macid);
    if (deviceId == undefined) {
        fail();
        return false;
    }
    const device = app.globalData.connectionState[deviceId].device;
    if (!bluetoothDevices[device.device_type].turnOff) {
        fail();
        return false;
    }
    var data = bluetoothDevices[device.device_type].turnOff(device, deviceId);
    if (data) {
        writeData(device, deviceId, data, callback, fail);
        return true;
    }
    fail();
    return false;
}
function bmsChargingMOS(macid, value, callback = () => {}, fail = () => {}) {
    const deviceId = Object.keys(app.globalData.connectionState).find((i) => app.globalData.connectionState[i].device.mac_id == macid);
    if (deviceId == undefined) {
        fail();
        return false;
    }
    const device = app.globalData.connectionState[deviceId].device;
    if (!bluetoothDevices[device.device_type].bmsChargingMOS) {
        fail();
        return false;
    }
    var data = bluetoothDevices[device.device_type].bmsChargingMOS(value - 0);
    if (data) {
        writeData(device, deviceId, data, callback, fail);
        return true;
    }
    fail();
    return false;
}
function bmsDischargeMOS(macid, value, callback = () => {}, fail = () => {}) {
    const deviceId = Object.keys(app.globalData.connectionState).find((i) => app.globalData.connectionState[i].device.mac_id == macid);
    if (deviceId == undefined) {
        fail();
        return false;
    }
    const device = app.globalData.connectionState[deviceId].device;
    if (!bluetoothDevices[device.device_type].bmsDischargeMOS) {
        fail();
        return false;
    }
    var data = bluetoothDevices[device.device_type].bmsDischargeMOS(value - 0);
    if (data) {
        writeData(device, deviceId, data, callback, fail);
        return true;
    }
    fail();
    return false;
}
function isConnected(macid) {
    const deviceId = Object.keys(app.globalData.connectionState).find((i) => app.globalData.connectionState[i].device.mac_id == macid);
    console.log(app.globalData.connectionState);
    if (deviceId == undefined) {
        return false;
    }
    return app.globalData.connectionState[deviceId].connected;
}
function getData(macid) {
    const deviceId = Object.keys(app.globalData.connectionState).find((i) => app.globalData.connectionState[i].device.mac_id == macid);
    if (deviceId == undefined) {
        return false;
    }
    return app.globalData.connectionState[deviceId].data;
}
function getConnectionState(macid) {
    const deviceId = Object.keys(app.globalData.connectionState).find((i) => app.globalData.connectionState[i].device.mac_id == macid);
    if (deviceId == undefined) {
        return false;
    }
    return app.globalData.connectionState[deviceId];
}
module.exports = {
    initBluetooth: initBluetooth,
    onAdapterStateChange: onAdapterStateChange,
    offAdapterStateChange: offAdapterStateChange,
    onConnectionStateChange: onConnectionStateChange,
    offConnectionStateChange: offConnectionStateChange,
    onCharacteristicStateChange: onCharacteristicStateChange,
    offCharacteristicStateChange: offCharacteristicStateChange,
    getAdapterState: getAdapterState,
    openBluetoothAdapter: openBluetoothAdapter,
    closeBluetoothAdapter: closeBluetoothAdapter,
    acceptDevice: acceptDevice,
    findDevice: findDevice,
    connectDevice: connectDevice,
    closeDevice: closeDevice,
    stateUpdate: stateUpdate,
    turnOn: turnOn,
    turnOff: turnOff,
    bmsInfo: bmsInfo,
    bmsSet: bmsSet,
    isConnected: isConnected,
    getData: getData,
    isSingleBT: isSingleBT,
    haveBMSForBT: haveBMSForBT,
    isSginleBtByMacid: isSginleBtByMacid,
    getConnectionState: getConnectionState,
    bmsChargingMOS: bmsChargingMOS,
    bmsDischargeMOS: bmsDischargeMOS
};
