package com.weightscalebridge

import android.Manifest
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.bluetooth.le.BluetoothLeScanner
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanResult
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.pow
import kotlin.math.round

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

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

  override fun getName(): String = "WeightScaleBridge"

  init {
    val manager =
      reactContext.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
    bluetoothAdapter = manager.adapter
    scanner = bluetoothAdapter?.bluetoothLeScanner
  }

  private fun sendEvent(name: String, params: WritableMap?) {
    reactContext
      .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
      .emit(name, params)
  }

  @ReactMethod
  fun isBluetoothEnabled(promise: Promise) {
    try {
      val enabled = bluetoothAdapter?.isEnabled ?: false
      promise.resolve(enabled)
    } catch (e: Exception) {
      promise.reject("BLUETOOTH_CHECK_ERROR", e.message, e)
    }
  }

  @ReactMethod
  fun startScanning(promise: Promise) {
    try {
      if (!hasPermissions()) {
        promise.reject("PERMISSION", "Bluetooth permissions not granted")
        return
      }

      if (bluetoothAdapter?.isEnabled != true) {
        promise.reject("BLUETOOTH", "Bluetooth disabled")
        return
      }

      if (isScanning) {
        promise.resolve(true)
        return
      }

      isScanning = true
      currentWeight = 0.0

      scanner?.startScan(scanCallback)

      sendEvent(
        "onWeightScaleStatus",
        Arguments.createMap().apply { putString("status", "scanning") }
      )

      timer = object : CountDownTimer(20000, 1000) {
        override fun onTick(ms: Long) {}
        override fun onFinish() {
          stopScanning(null)
        }
      }.start()

      promise.resolve(true)
    } catch (e: Exception) {
      promise.reject("SCAN_ERROR", e.message, e)
    }
  }

  @ReactMethod
  fun stopScanning(promise: Promise?) {
    try {
      scanner?.stopScan(scanCallback)
    } catch (_: Exception) {}

    timer?.cancel()
    isScanning = false

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

    promise?.resolve(true)
  }

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

      if (data.size() == 0) return

      val raw = data.valueAt(0)
      if (raw.size < 2) return

      val weight = (((raw[0].toInt() and 0xff) shl 8) or
        (raw[1].toInt() and 0xff)) / 10.0

      currentWeight = weight

      sendEvent(
        "onWeightData",
        Arguments.createMap().apply {
          putDouble("weight", weight)
          putBoolean("isStable", true)
        }
      )

      sendEvent(
        "onWeightScaleStatus",
        Arguments.createMap().apply {
          putString("status", "complete")
          putString("message", "$weight kg")
        }
      )

      stopScanning(null)
    }

    override fun onScanFailed(errorCode: Int) {
      super.onScanFailed(errorCode)
      
      sendEvent(
        "onWeightScaleStatus",
        Arguments.createMap().apply {
          putString("status", "error")
          putString("message", "Scan failed with code: $errorCode")
        }
      )
      
      isScanning = false
    }
  }

  @ReactMethod
  fun calculateBMI(weight: Double, heightCm: Double, promise: Promise) {
    try {
      if (heightCm <= 0) {
        promise.reject("INVALID_HEIGHT", "Height must be greater than 0")
        return
      }
      
      val bmi = weight / (heightCm / 100).pow(2)
      promise.resolve(round(bmi * 10) / 10)
    } catch (e: Exception) {
      promise.reject("BMI_ERROR", e.message, e)
    }
  }

  private fun hasPermissions(): Boolean {
    val perms =
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
        arrayOf(
          Manifest.permission.BLUETOOTH_SCAN,
          Manifest.permission.BLUETOOTH_CONNECT
        )
      else
        arrayOf(
          Manifest.permission.ACCESS_FINE_LOCATION
        )

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