package com.reactnativerfidble

import android.app.Activity
import android.content.Intent
import com.facebook.react.bridge.*
import com.reactnativerfidble.adapters.RfidBleAdapter
import java.lang.Error
import java.lang.Exception

class RfidBleModule(reactContext: ReactApplicationContext) :
    ReactContextBaseJavaModule(reactContext),
    ActivityEventListener {
    private val bleScanner: RfidBleScanner = RfidBleScanner(reactApplicationContext)

    private var activeAdapter: RfidBleAdapter? = null
    private var requestEnabledPromise: Promise? = null

    override fun getName(): String {
        return "RfidBle"
    }

    //region ActivityEventListener
    override fun onActivityResult(
        activity: Activity?,
        requestCode: Int,
        resultCode: Int,
        data: Intent?
    ) {
        if (requestCode == RfidBleRequestCode.ENABLE_BLUETOOTH.code) {
            requestEnabledPromise?.let {
                if (resultCode == Activity.RESULT_OK) {
                    it.resolve(null)
                } else {
                    it.reject(Exception("User did not enable Bluetooth"))
                }
            }

            requestEnabledPromise = null
        }
    }

    override fun onNewIntent(intent: Intent?) {
        TODO("Not yet implemented")
    }
    //endregion

    //region ReactNativeImplementation
    /**
     * Request enabled bluetooth
     */
    @ReactMethod
    fun requestEnabled(promise: Promise) {
        if (bleScanner.isBluetoothEnabled) {
            return promise.resolve(null)
        }

        requestEnabledPromise = promise

        try {
            bleScanner.requestEnabled()
        } catch (e: Throwable) {
            promise.reject(
                "ERROR_REQUESTING_ENABLED",
                "Error while requesting bluetooth enabled",
                e
            )
        }
    }

    /**
     * Scan for BLE readers
     */
    @ReactMethod
    fun startScan(promise: Promise) {
        try {
            bleScanner.startScan()
            promise.resolve(null)
        } catch (e: Throwable) {
            promise.reject(
                "ERROR_START_SCANNING",
                "Error scanning readers. Original error message: ${e.message}",
                e
            )
        }
    }

    /**
     * Stop BLE readers scanning
     */
    @ReactMethod
    fun stopScan(promise: Promise) {
        try {
            bleScanner.stopScan()
            promise.resolve(null)
        } catch (e: Throwable) {
            promise.reject("ERROR_STOP_SCANNING", "Error while stop scanning", e)
        }
    }

    /**
     * Connect to reader by given reader's address
     */
    @ReactMethod
    fun connectToReader(readerAddress: String, promise: Promise) {
        try {
            val foundScanResult = bleScanner.scannedReadersResults.find { scanResult ->
                scanResult.device.address == readerAddress
            } ?: throw Error("Scan result not found. Please start scan before connecting")

            val totalUuids = foundScanResult.device.uuids.size

            bleScanner.emitBleDebugEvent("Device Total Uuids: $totalUuids")
            bleScanner.emitBleDebugEvent(
                "Device First Uuid: ${
                    if (totalUuids > 1) foundScanResult.device.uuids[0].toString()
                    else "Unknown"
                }"
            )

            val adapter = RfidBleAdapter.getAdapterInstance(
                foundScanResult,
                reactApplicationContext
            )

            activeAdapter?.disconnect()

            adapter.connectToReader(readerAddress)
            activeAdapter = adapter

            promise.resolve(null)
        } catch (e: Throwable) {
            promise.reject(
                "CONNECTION_ERROR",
                "Error while connecting to reader. Reason: ${e.message}",
                e
            )
        }
    }

    /**
     * Disconnect from current connected reader
     */
    @ReactMethod
    fun disconnect(promise: Promise) {
        try {
            activeAdapter?.let {
                it.disconnect()
                activeAdapter = null

                promise.resolve(null)
            }
        } catch (e: Throwable) {
            promise.reject("ERROR_DISCONNECTING", "Error while disconnecting to reader", e)
        }
    }
    //endregion
}
