package com.reactnativerfidble

import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanFilter
import android.bluetooth.le.ScanResult
import android.bluetooth.le.ScanSettings
import android.content.Intent
import com.facebook.react.bridge.ReactApplicationContext
import com.reactnativerfidble.adapters.RfidBleAdapter
import com.reactnativerfidble.generic.RfidBleGenericReader
import java.lang.Error

open class RfidBleScanner(
    private val reactContext: ReactApplicationContext
) : RfidBleEventEmitter(reactContext) {
    private val bluetoothManager = reactContext.getSystemService(BluetoothManager::class.java)
    private val bluetoothAdapter = bluetoothManager?.adapter
    private val bluetoothScanner = bluetoothAdapter?.bluetoothLeScanner

    private var scanning = false
    val scannedReadersResults = mutableListOf<ScanResult>()

    private val leScanCallback = object : ScanCallback() {
        override fun onScanResult(callbackType: Int, result: ScanResult?) {
            super.onScanResult(callbackType, result)

            result?.let { scanResult ->
                val foundScanResult = scannedReadersResults.find {
                    it.device.address == scanResult.device.address
                }

                if (foundScanResult == null) {
                    scannedReadersResults.add(scanResult)

                    scanResult.device.let { device ->
                        emitBleReaderEvent(
                            RfidEvent.READER_RECEIVED,
                            RfidBleGenericReader(device.name, device.address)
                        )
                    }
                }
            }
        }
    }

    val isBluetoothEnabled: Boolean
        get() = bluetoothAdapter != null && bluetoothAdapter.isEnabled

    fun requestEnabled() {
        if (bluetoothAdapter == null) {
            throw Error("BLE unsupported")
        }

        if (!bluetoothAdapter.isEnabled) {
            reactContext.currentActivity?.let {
                val enableBleIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)

                it.startActivityForResult(enableBleIntent, RfidBleRequestCode.ENABLE_BLUETOOTH.code)
            }
        }
    }

    fun startScan() {
        if (scanning) {
            return
        }

        bluetoothScanner?.let {
            val filters = mutableListOf<ScanFilter>()

            for (supportedAdapter in RfidBleAdapter.SUPPORTED_ADAPTERS) {
                val scanFilterBuilder = ScanFilter.Builder()

                if (supportedAdapter.address != null) {
                    scanFilterBuilder.setDeviceAddress(supportedAdapter.address)
                } else {
                    for (serviceUuid in supportedAdapter.serviceUuids) {
                        scanFilterBuilder.setServiceUuid(serviceUuid)
                    }
                }

                val filter = scanFilterBuilder.build()
                filters.add(filter)
            }

            // Clear previously scanned readers results
            scannedReadersResults.clear()

            it.startScan(filters, ScanSettings.Builder().build(), leScanCallback)

            scanning = true

            emitBleEvent(RfidEvent.START_SCANNING)
        }
    }

    fun stopScan() {
        if (!scanning) {
            return
        }

        bluetoothScanner?.let {
            it.stopScan(leScanCallback)
            scanning = false

            emitBleEvent(RfidEvent.STOP_SCANNING)
        }
    }
}