package com.reactnativerfidble.adapters

import android.bluetooth.*
import com.facebook.react.bridge.ReactApplicationContext
import com.reactnativerfidble.generic.RfidBleGenericEpcReply
import com.reactnativerfidble.generic.RfidBleGenericReader
import com.reactnativerfidble.normalizeEPCH301
import com.reactnativerfidble.toHexString
import java.util.*

class RfidBleH301Adapter(
    private val reactContext: ReactApplicationContext
) : RfidBleAdapter(reactContext) {
    companion object {
        private const val GATT_TARGET_NOTIFICATION_CHARACTERISTIC =
            "0000ffe1-0000-1000-8000-00805f9b34fb"

        private const val GATT_TARGET_NOTIFICATION_DESCRIPTOR =
            "00002902-0000-1000-8000-00805f9b34fb"
    }

    private val bluetoothAdapter =
        reactContext.getSystemService(BluetoothManager::class.java)?.adapter

    private var activeGatt: BluetoothGatt? = null
    private var activeDevice: BluetoothDevice? = null

    private val gattCallback = object : BluetoothGattCallback() {
        override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
            when (newState) {
                BluetoothProfile.STATE_CONNECTED -> {
                    emitBleReaderEvent(
                        RfidEvent.READER_CONNECTED,
                        RfidBleGenericReader(activeDevice!!.name, activeDevice!!.address)
                    )

                    activeGatt?.discoverServices()
                }

                BluetoothProfile.STATE_DISCONNECTED -> {
                    emitBleReaderEvent(
                        RfidEvent.READER_DISCONNECTED,
                        RfidBleGenericReader(activeDevice!!.name, activeDevice!!.address)
                    )

                    // TODO: Something else to-do?
                    activeGatt = null
                    activeDevice = null
                }
            }
        }

        override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
            if (status != BluetoothGatt.GATT_SUCCESS) {
                return
            }

            for (gattService in gatt!!.services) {
                for (gattCharacteristic in gattService.characteristics) {
                    if (gattCharacteristic.uuid.toString() == GATT_TARGET_NOTIFICATION_CHARACTERISTIC) {
                        activeGatt?.setCharacteristicNotification(gattCharacteristic, true)

                        val gattDescriptor = gattCharacteristic.getDescriptor(
                            UUID.fromString(
                                GATT_TARGET_NOTIFICATION_DESCRIPTOR
                            )
                        )

                        gattDescriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
                        activeGatt?.writeDescriptor(gattDescriptor)
                    }
                }
            }
        }

        override fun onCharacteristicChanged(
            gatt: BluetoothGatt?,
            characteristic: BluetoothGattCharacteristic?
        ) {
            characteristic?.value?.let {
                if (it.isNotEmpty()) {
                    val listEpcReplies = listOf(it.normalizeEPCH301().toHexString())

                    emitBleEpcReplies(
                        "H301",
                        listEpcReplies,
                        fun(reply: String) = RfidBleGenericEpcReply(reply)
                    )
                }
            }
        }
    }

    override fun connectToReader(readerAddress: String) {
        bluetoothAdapter?.let {
            activeDevice = it.getRemoteDevice(readerAddress)
            activeGatt = activeDevice!!.connectGatt(reactContext, false, gattCallback)
        }
    }

    override fun disconnect() {
        activeGatt?.close()
        activeGatt = null
        activeDevice = null
    }
}