package com.weightscalebridge

import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.module.annotations.ReactModule
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.bluetooth.le.*
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.os.CountDownTimer
import androidx.core.content.ContextCompat
import com.facebook.react.bridge.*
import com.facebook.react.modules.core.DeviceEventManagerModule
import kotlin.math.abs

class WeightScaleModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {

    override fun getName(): String = "WeightScale"

    private var bluetoothAdapter: BluetoothAdapter? = null
    private var scanner: BluetoothLeScanner? = null
    private var isScanning = false
    private var timer: CountDownTimer? = null

    private var candidateKg: Double = Double.NaN
    private var stableSince: Long = 0L

    private val STABLE_WINDOW_MS = 4000L
    private val WEIGHT_TOL = 0.1
    private val MIN_VALID_KG = 5.0
    private val MAX_VALID_KG = 250.0
    private val MEASURE_WINDOW_MS = 20000L // 20 seconds timeout
    private val TARGET_MAC = "34:5C:F3:40:2C:D8" // Your scale MAC

    private fun sendEvent(eventName: String, params: WritableMap) {
        reactApplicationContext
            .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
            .emit(eventName, params)
    }

    @ReactMethod
    fun startMeasuring() {
        if (isScanning) return

        val bluetoothManager = reactApplicationContext.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
        bluetoothAdapter = bluetoothManager.adapter

        if (bluetoothAdapter == null || !bluetoothAdapter!!.isEnabled) {
            val params = Arguments.createMap().apply {
                putString("message", "Bluetooth is not enabled. Please turn it on in settings.")
            }
            sendEvent("onScaleError", params)
            return
        }

        if (!hasRequiredPermissions()) {
            val params = Arguments.createMap().apply {
                putString("message", "Required permissions not granted.")
            }
            sendEvent("onScaleError", params)
            return
        }

        scanner = bluetoothAdapter!!.bluetoothLeScanner

        // Reset stability tracking
        candidateKg = Double.NaN
        stableSince = 0L
        isScanning = true

        // Send initial status
        sendEvent("onStatusChange", Arguments.createMap().apply { putString("status", "scanning") })

        // Use filter for your specific scale MAC (more efficient)
        val scanFilter = ScanFilter.Builder()
            .setDeviceAddress(TARGET_MAC)
            .build()
        val scanFilters = listOf(scanFilter)

        val scanSettings = ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
            .build()

        try {
            scanner!!.startScan(scanFilters, scanSettings, scanCallback)
        } catch (e: Exception) {
            val params = Arguments.createMap().apply { putString("message", e.message ?: "Scan start failed") }
            sendEvent("onScaleError", params)
            stopMeasuring()
            return
        }

        // 20-second timeout
        timer = object : CountDownTimer(MEASURE_WINDOW_MS, 1000) {
            override fun onTick(millisUntilFinished: Long) {
                // Optional: send remaining seconds if needed
            }

            override fun onFinish() {
                stopMeasuring()
                sendEvent("onStatusChange", Arguments.createMap().apply { putString("status", "timeout") })
            }
        }.start()
    }

    @ReactMethod
    fun stopMeasuring() {
        if (!isScanning) return

        try {
            scanner?.stopScan(scanCallback)
        } catch (e: Exception) {
            // Ignore
        }
        timer?.cancel()
        timer = null
        isScanning = false

        sendEvent("onStatusChange", Arguments.createMap().apply { putString("status", "stopped") })
    }

    private val scanCallback = object : ScanCallback() {
        override fun onScanResult(callbackType: Int, result: ScanResult?) {
            result ?: return
            val scanRecord = result.scanRecord ?: return
            val manufacturerData = scanRecord.manufacturerSpecificData

            if (manufacturerData != null && manufacturerData.size() > 0) {
                for (i in 0 until manufacturerData.size()) {
                    val data = manufacturerData.valueAt(i) ?: continue
                    if (data.size >= 2) {
                        val tenths = ((data[0].toInt() and 0xFF) shl 8) or (data[1].toInt() and 0xFF)
                        val kg = tenths / 10.0
                        if (kg in MIN_VALID_KG..MAX_VALID_KG) {
                            processWeight(kg)
                        }
                    }
                }
            }
        }

        override fun onScanFailed(errorCode: Int) {
            val params = Arguments.createMap().apply {
                putString("message", "Scan failed with code: $errorCode")
            }
            sendEvent("onScaleError", params)
            stopMeasuring()
        }
    }

    private fun processWeight(kg: Double) {
        // Send live weight update
        val liveParams = Arguments.createMap().apply { putDouble("weight", kg) }
        sendEvent("onLiveWeight", liveParams)

        // Update status to measuring
        sendEvent("onStatusChange", Arguments.createMap().apply { putString("status", "measuring") })

        val now = System.currentTimeMillis()

        // Stability detection
        if (candidateKg.isNaN() || abs(kg - candidateKg) > WEIGHT_TOL) {
            candidateKg = kg
            stableSince = now
        } else if (now - stableSince >= STABLE_WINDOW_MS) {
            // Stable weight achieved
            val stableParams = Arguments.createMap().apply { putDouble("weight", candidateKg) }
            sendEvent("onStableWeight", stableParams)
            sendEvent("onStatusChange", Arguments.createMap().apply { putString("status", "stable") })
            stopMeasuring()
        }
    }

    private fun hasRequiredPermissions(): Boolean {
        val perms = mutableListOf<String>()
        perms.add(android.Manifest.permission.ACCESS_FINE_LOCATION)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            perms.add(android.Manifest.permission.BLUETOOTH_SCAN)
            perms.add(android.Manifest.permission.BLUETOOTH_CONNECT)
        }

        return perms.all {
            ContextCompat.checkSelfPermission(reactApplicationContext, it) == PackageManager.PERMISSION_GRANTED
        }
    }

    override fun onCatalystInstanceDestroy() {
        super.onCatalystInstanceDestroy()
        stopMeasuring() // Cleanup when RN instance destroys
    }
}