import {
	formatNullCharacter,
	stringToArrayBuffer,
	arrayBufferToString,
	ab2hex,
	byteLength,
	generateUUID
} from './util.js'

// 标签写入的类型
export const WRITE_TYPE_ENUM = {
	T: 'T',
	U: 'U'
};
export const WRITE_TYPE_TEXT_ENUM = {
	T: '文本',
	U: '网址',
};
export const NFC_STATUS_ENUM = {
	INIT: 'INIT', // 初始化NFC
	INIT_OK: 'INIT_OK', // 初始化NFC成功
	INIT_ERROR: 'INIT_ERROR', // 初始化NFC失败
	READ_START: 'READ_START', // 读取开始
	READING: 'READING', // 正在读取
	READ_SUCCESS: 'READ_SUCCESS', // 读取成功
	READ_FAIL: 'READ_FAIL', // 读取失败
	WRITE_START: 'WRITE_START', // 写入开始
	WRITING: 'WRITING', // 正在写入
	WRITE_SUCCESS: 'WRITE_SUCCESS', // 写入成功
	WRITE_FAIL: 'WRITE_FAIL', // 写入失败
	DEVICE_NO_NFC: 'DEVICE_NO_NFC', // 设备不支持NFC
	DEVICE_NFC_NOT_ENABLE: 'DEVICE_NFC_NOT_ENABLE', // 设备未开启NFC
	TIMEOUT_ERROR: 'TIMEOUT_ERROR', // 超时提示
	TOAST: 'TOAST', // toast提示
};

const ERR_CODE_ENUM = {
	13000: '本设备不支持NFC',
	13001: '系统NFC开关未打开',
	13010: '未知错误',
	13019: '用户未授权',
	13021: '已经开始NFC扫描',
	13018: '尝试在未开始NFC扫描时停止NFC扫描',
	13022: '标签已经连接',
	13023: '尝试在未连接标签时断开连接',
	13013: '未扫描到NFC标签',
	13014: '无效的标签技术',
	13015: '从标签上获取对应技术失败',
	13024: '当前标签技术不支持该功能',
	13017: '相关读写操作失败',
	13016: '连接失败',
}

class NFCTool {

	static NFCAdapter = null; // NFC适配器对象
	static NFCType = null; // NFC标签
	nfcState = false; // nfc开启状态
	isConnect = false; // 开启连接
	noNFC = false; // 是否有NFC功能
	callBack = null;
	readFuc = null;
	writeFuc = null;

	timeOut = 60 * 1000;
	maxLength = 120;

	// 写入NFC的相关数据
	readyWrite = false; // 开启写
	writeTimer = null;
	writeParams = {
		id: '', // 将要写入ID
		text: '', // 写入的字符
		type: '', // 写入的类型
	};

	nfcTagId = ''; // nfc唯一标识
	// 读取NFC的相关数据
	readyRead = false; // 开启读
	readTimer = null;
	readParams = {
		id: '', // 读取ID
		text: '', // 读取的字符
		type: '', // 读取的类型
	};

	constructor(NFCToolCallBack, data) {
		this.callBack = NFCToolCallBack;
		this.timeOut = data?.timeOutNum ? Number(data?.timeOutNum) : 60 * 1000;
		// this.startDiscovery();
	}


	/**
	 * 开始监听
	 */
	startDiscovery(data) {
		console.log(data, uni.getSystemInfoSync().platform)
		if (uni.getSystemInfoSync().platform !== "android") {
			return
		}
		let _this = this;
		_this.readyWrite = data?.readyWrite ? data?.readyWrite : false;
		_this.callBack({
			status: NFC_STATUS_ENUM.INIT,
			tip: '初始化NFC'
		})
		// try {
		if (!_this.nfcState) {
			let adapter = wx.getNFCAdapter();
			console.log(adapter)
			if (adapter == null) {
				_this.callBack({
					status: NFC_STATUS_ENUM.DEVICE_NO_NFC,
					tip: '设备不支持NFC或未开启NFC'
				})
				_this.noNFC = true;
				return;
			}
			_this.NFCAdapter = adapter;
			_this.nfcState = true;
			_this.NFCAdapter.startDiscovery({
				success(res) {
					_this.callBack({
						status: NFC_STATUS_ENUM.INIT_OK,
						tip: 'NFC读取功能已开启',
					});
					// 绑定监听 NFC Tag 读取
					_this.readFuc = _this.readDiscoverHandler.bind(_this);
					_this.NFCAdapter.onDiscovered(_this.readFuc);
					if (_this.readyWrite) {
						// 绑定监听 NFC Tag 写入
						_this.writeTimer = setTimeout(() => {
							if (_this.readyWrite && !_this.isConnect) {
								_this.callBack({
									status: NFC_STATUS_ENUM.TIMEOUT_ERROR,
									tip: 'NFC读取超时，请重试...'
								})
								_this.readyRead = false;
								_this.stopDiscovery();
							}
							clearTimeout(_this.writeTimer);
						}, _this.timeOut);
						_this.writeFuc = _this.writeDiscoverHandler.bind(_this);
						_this.NFCAdapter.onDiscovered(_this.writeFuc);
					}
					// }
				},
				fail(err) {
					let errCodeTips = err?.errCode ? ERR_CODE_ENUM[Number(err?.errCode)] : '';
					_this.callBack({
						status: NFC_STATUS_ENUM.INIT_ERROR,
						tip: '请检查NFC功能是否正常',
						data: errCodeTips
					});
					_this.noNFC = true;
				}
			})
		}
		// } catch (e) {
		// 	_this.callBack({
		// 		status: NFC_STATUS_ENUM.INIT_ERROR,
		// 		tip: '请检查NFC功能是否正常'
		// 	})
		// 	_this.noNFC = true;
		// }
	}


	/**
	 * 读取NFC标签
	 */
	readData() {
		let _this = this;
		if (_this.nfcState) {
			if (_this.noNFC) {
				_this.callBack({
					status: NFC_STATUS_ENUM.READ_FAIL,
					tip: '请检查设备是否支持并开启 NFC 功能！',
					data: ''
				})
				return;
			}
			_this.readTimer = setTimeout(() => {
				if (_this.readyRead) {
					_this.callBack({
						status: NFC_STATUS_ENUM.TIMEOUT_ERROR,
						tip: 'NFC读取超时，请重试...'
					})
					_this.readyRead = false;
				}
				clearTimeout(_this.readTimer);
			}, _this.timeOut);
			_this.callBack({
				status: NFC_STATUS_ENUM.READ_START,
				tip: '请将设备靠近NFC识别区'
			})
			// 更改读状态
			_this.readyRead = true;
		}
	}

	/**
	 * 监听 NFC Tag 读取
	 * @param id ArrayBuffer
	 * @param techs Array tech 数组，用于匹配NFC卡片具体可以使用什么标准（NfcA等实例）处理
	 * @param messages
	 */
	async readDiscoverHandler({
		id,
		techs,
		messages
	}) {
		let _this = this;
		try {
			if (_this.readyRead && _this.nfcState) {
				_this.callBack({
					status: NFC_STATUS_ENUM.READING,
					tip: '识别NFC标签中'
				})
				let adapter = _this.NFCAdapter;
				await _this.readTag(id);
				if (techs.includes(adapter.tech.nfcA)) {
					let nfcA = adapter.getNfcA();
					_this.NFCType = nfcA;
					if (messages) {
						let cordsArray = messages[0].records;
						cordsArray.forEach(item => {
							_this.readParams = {
								id: arrayBufferToString(item.id), // 读取ID
								text: arrayBufferToString(item.payload), // 读取的字符
								type: arrayBufferToString(item.type), // 读取的类型
							}
							_this.callBack({
								status: NFC_STATUS_ENUM.READ_SUCCESS,
								tip: '读取成功',
								data: {
									..._this.readParams,
									nfcTagId: _this.nfcTagId,
								}
							})
						})
					} else {
						_this.callBack({
							status: NFC_STATUS_ENUM.READ_SUCCESS,
							tip: '读取成功',
							data: {
								..._this.readParams,
								nfcTagId: _this.nfcTagId,
							}
						})
					}
					_this.readyRead = false;
				}
			}
		} catch (e) {
			_this.callBack({
				status: NFC_STATUS_ENUM.READ_FAIL,
				tip: '读取失败'
			})
		}
	}

	/**
	 * 写入NFC标签
	 * @param {Object} data 写入的数据
	 */
	writeTag(data) {
		let _this = this;
		if (_this.nfcState) {
			if (data) {
				_this.callBack({
					status: NFC_STATUS_ENUM.WRITE_START,
					tip: '请将设备靠近NFC识别区'
				})

				_this.writeParams = {
					id: data.id,
					text: data.positionName, // 写入的字符
					type: WRITE_TYPE_ENUM.T, // 写入的类型
				};
				if (byteLength(JSON.stringify(_this.writeParams)) > _this.maxLength) {
					_this.callBack({
						status: NFC_STATUS_ENUM.WRITE_FAIL,
						tip: '数据超过NFC容量大小，请重试'
					});
					_this.stopDiscovery();
					return;
				}
				if (_this.isConnect) {
					_this.writeNdefMessage()
				} else {
					// TODO 报错 NFC断开连接
				}
			} else {
				_this.callBack({
					status: NFC_STATUS_ENUM.WRITE_FAIL,
					tip: '写入数据不可为空，请重试'
				})
			}
		}
	}

	/**
	 * 监听 NFC Tag 写入
	 * @param id ArrayBuffer
	 * @param techs Array tech 数组，用于匹配NFC卡片具体可以使用什么标准（NfcA等实例）处理
	 * @param messages
	 */
	async writeDiscoverHandler({
		id,
		techs,
		messages
	}) {
		let _this = this;
		if (_this.nfcState) {
			_this.callBack({
				status: NFC_STATUS_ENUM.READING,
				tip: '识别NFC标签中'
			})
			let adapter = _this.NFCAdapter;
			await _this.readTag(id);
			let nDef = adapter.getNdef();
			_this.NFCType = nDef;
			if (_this.isConnect) {
				_this.onCloseConnect();
			}
			_this.onConnect();
		}
	}

	/**
	 * 读取 NFC 标签 返回的 id
	 * @param {Object} id
	 */
	readTag(id) {
		let aid = parseInt(ab2hex(id), 16);
		// 使用 new Uint8Array处理返回一个数组
		const data = new Uint8Array(id);
		let tagId = ""
		data.forEach(e => {
			// 因为我们的卡号是16位制的，所以这里选择转换成16位数字
			let item = e.toString(16)
			if (item.length == 1) {
				item = '0' + item
			}
			// 因为我们需要的是大写，所以要转
			item = item.toUpperCase()
			tagId = item + tagId
		})
		// 最终结果
		/* 这里获取的tagId就是我们读取出的UID码了 */
		this.nfcTagId = tagId;
	}

	/**
	 * 设备连接操作 写入操作
	 */
	onConnect() {
		let _this = this;
		if (!_this.isConnect) {
			_this.NFCType.connect({
				success: function(cRes) {
					_this.isConnect = true;
					_this.callBack({
						status: NFC_STATUS_ENUM.WRITING,
						tip: '已连接，请勿移开设备',
						data: {
							isConnect: true,
						}
					})
					// _this.writeNdefMessage()
				},
				fail: function(err) {
					let errCodeTips = err?.errCode ? ERR_CODE_ENUM[Number(err?.errCode)] : '';
					_this.callBack({
						status: NFC_STATUS_ENUM.WRITE_FAIL,
						tip: '设备连接错误',
						data: {
							nfcTagId: _this.nfcTagId,
							errCodeTips
						}
					});
					_this.stopDiscovery();
				}

			});
		}
	}

	/**
	 * NFC写入操作
	 */
	writeNdefMessage() {
		let _this = this;
		// let idBuffer = stringToArrayBuffer(''); // 写入的字符
		let idBuffer = stringToArrayBuffer((_this.writeParams.id).toString()); // 写入的字符
		let textBuffer = stringToArrayBuffer(_this.writeParams.text); // 写入的字符
		let typeBuffer = stringToArrayBuffer(_this.writeParams.type); // 写入的类型
		const records = [{
			id: idBuffer,
			payload: textBuffer,
			type: typeBuffer,
			tnf: 2
		}];
		_this.NFCType.writeNdefMessage({
			records: records,
			success: function(tRes) {
				_this.callBack({
					status: NFC_STATUS_ENUM.WRITE_SUCCESS,
					tip: '写入成功',
					data: {
						..._this.writeParams,
						nfcTagId: _this.nfcTagId,
						isConnect: false
					}
				})
			},
			fail: function(err) {
				let errCodeTips = err?.errCode ? ERR_CODE_ENUM[Number(err?.errCode)] : '';
				_this.callBack({
					status: NFC_STATUS_ENUM.WRITE_FAIL,
					tip: '数据写入失败',
					data: {
						nfcTagId: _this.nfcTagId,
						errCodeTips,
						isConnect: false
					}
				})
			},
			complete: res => {
				_this.writeParams = {
					id: '',
					text: '', // 写入的字符
					type: '', // 写入的类型
				};
				_this.readyWrite = false;
				_this.onCloseConnect();
				_this.stopDiscovery();
			}
		})
	}

	onCloseConnect() {
		let _this = this;
		_this.isConnect = false;
		if (_this.NFCType) {
			_this.NFCType.close({
				success: function(cRes) {},
				fail: function(err) {
					let errCodeTips = err?.errCode ? ERR_CODE_ENUM[Number(err?.errCode)] : '';
				},
				complete: res => {}
			});
		}
	}

	/**
	 * 设置超时时间
	 */
	onSetTimeout() {

	}

	/**
	 * @param {Object} data格式化NFC数据
	 */
	formatNFC(data) {
		// 这里可以添加数据格式化的逻辑
		return 'Formatted data: ' + data;
	}

	changeNFCState() {
		let _this = this;
		_this.nfcState = !_this.nfcState;
	}
	/**
	 * 停止监听贴卡
	 */
	stopDiscovery() {
		let _this = this;
		if (_this.NFCType) {
			_this.isConnect && _this.onCloseConnect();
			_this.NFCType = null;
		}
		if (_this.NFCAdapter) {
			_this.NFCAdapter.offDiscovered(_this.readFuc);
			_this.NFCAdapter.offDiscovered(_this.writeFuc);
			_this.NFCAdapter.stopDiscovery();
			_this.NFCAdapter = null;
			_this.nfcState = false;
		}
		if (_this.readTimer) {
			clearTimeout(_this.readTimer);
		}
		if (_this.writeTimer) {
			clearTimeout(_this.writeTimer);
		}
	}
}
export default NFCTool;