package com.mytatvarnsdk.activity

import android.Manifest
import android.app.AlertDialog
import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.Window
import androidx.activity.OnBackPressedCallback
import androidx.activity.enableEdgeToEdge
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toDrawable
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import cgmblelib.ble.gattcallback.ManageGattCallback
import cgmblelib.ble.scancallback.ManageScanCallback
import cgmblelib.custom.livedata.scan.PocDeviceAndRssi
import cgmblelib.database.entity.PocDevice
import cgmblelib.utils.SharedPreferencesLibraryUtil
import com.bumptech.glide.Glide
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.CatalystInstance
import com.facebook.react.bridge.WritableMap
import com.facebook.react.modules.core.DeviceEventManagerModule
import com.google.gson.Gson
import com.mytatvarnsdk.CgmTrackyLibModule
import com.mytatvarnsdk.R
import com.mytatvarnsdk.base.BaseBleActivity
import com.mytatvarnsdk.databinding.ActivityConnectSensorBinding
import com.mytatvarnsdk.databinding.ExitDialogBottomsheetBinding
import com.mytatvarnsdk.model.DeviceVerificationResponse
import com.mytatvarnsdk.myView.progress.ProgressManagement
import com.mytatvarnsdk.myView.progress.ProgressType
import com.mytatvarnsdk.network.AuthenticateSDKService
import com.mytatvarnsdk.utils.TATVA_ENVIRONMENT
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import org.json.JSONObject


class ConnectSensorActivity : BaseBleActivity() {
    private lateinit var binding: ActivityConnectSensorBinding
    public val REQUEST_QR: Int = 115
    private val CAMERA_REQUEST_CODE = 100
    var transmitterDeviceInfo: PocDeviceAndRssi? = null
    private var isForReconnect: Boolean = false
    private val reactContext = CgmTrackyLibModule.mReactContext

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityConnectSensorBinding.inflate(layoutInflater)
        setContentView(binding.root)

        enableEdgeToEdge()
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }
        initialize()
    }

    override fun setView(): Int {
        return R.layout.activity_connect_sensor
    }

    override fun onPermissionRequestSuccess() {
    }

    override fun initViews() {
    }

    private fun initialize() {
        transmitterDeviceInfo =
            intent.getSerializableExtra("transmitterDeviceInfo") as PocDeviceAndRssi?
        isForReconnect = intent.getBooleanExtra("IsForReconnect", false)

        sendDataToRN("", "cgm_connect_sensor_scan_landing")

        binding.commonButton.btnProceed.setOnClickListener {
            transmitterDeviceInfo?.let {
                QRActivity.startQR(
                    this, it.pocDevice
                )
            }
        }

        binding.toolbar.btnClose.setOnClickListener {
            openExitDialog()
        }

        binding.toolbar.btnWhatsapp.setOnClickListener {
            startActivity(
                Intent(this, HelpActivity::class.java).putExtra("ScreenName", "Sensor page")
            )
        }

        binding.toolbar.btnWatchDemo.setOnClickListener {
            sendDataToRN("", "cgm_watch_demo_clicked")

            startActivity(
                Intent(this, VideoActivity::class.java).putExtra("VideoId", if (isForReconnect) "n_pUrFoZ1wQ" else "r5Zemc4R044")
            )
        }

        val callback: OnBackPressedCallback = object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                openExitDialog()
            }
        }
        onBackPressedDispatcher.addCallback(this, callback)


        binding.tvPermission.setOnClickListener(View.OnClickListener { v: View? ->
            requestCameraPermission()
        })

        if (isCameraPermissionGranted(this)) {
            binding.commonButton.btnProceed.isEnabled = true
            binding.commonButton.btnProceed.alpha = 1f
            binding.tvPermission.text = "Press on Proceed button below to scan QR"
        } else {
            binding.commonButton.btnProceed.isEnabled = false
            binding.commonButton.btnProceed.alpha = 0.5f
            binding.clPermission.visibility = View.VISIBLE
        }
    }

    fun manageErrorState(showError: Boolean, errorStatus: String) {
        ProgressManagement.getInstance().dismissWait(this)
        if (showError) {
            binding.clFail.visibility = View.VISIBLE
            binding.clMain.visibility = View.GONE
            binding.commonButton.root.visibility = View.GONE

            Glide.with(this).asGif().load(R.drawable.warning).into(binding.ivGif)

            // Restore original text size (24sp) for non-validation API errors
            binding.tvFailTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 24f)
            binding.tvFailTitle.text = "Unable to detect sensor"
            binding.tvFailTitle.setTextColor(Color.parseColor("#101828"))

            binding.btnSupport.tvProceed.text = "Contact Support"
            binding.btnRetry.tvProceed.text = "Retry"

            binding.llWatchDemo.post {
                binding.llWatchDemo.setOnClickListener {
                    Log.d("CLICK", "Layout Clicked")
                    startActivity(
                        Intent(this, VideoActivity::class.java).putExtra("VideoId", "zRlFFdr-QD4")
                    )
                }
            }

            binding.btnSupport.btnProceed.setOnClickListener {
                startActivity(
                    Intent(this, HelpActivity::class.java).putExtra("ScreenName", "Sensor Screen")
                )
            }

            binding.btnRetry.btnProceed.setOnClickListener {
                sendDataToRN("", "cgm_retry_connect_sensor_clicked")

                transmitterDeviceInfo?.let {
                    QRActivity.startQR(
                        this, it.pocDevice
                    )
                }
            }

            if (errorStatus.isNotEmpty()) {
                val jsonObject = JSONObject()
                jsonObject.put("error_description", errorStatus)
                sendDataToRN(jsonObject.toString(), "cgm_sensor_connection_failed")

                binding.tvReason.visibility = View.VISIBLE
                binding.tvReason.text = "Reason - ${errorStatus}"
            } else {
                binding.tvReason.visibility = View.GONE
            }
        } else {
            binding.commonButton.root.visibility = View.VISIBLE
            binding.clFail.visibility = View.GONE
            binding.clMain.visibility = View.VISIBLE
        }
    }


    private fun requestCameraPermission() {
        if (hasPermissions(PermissionUtils.CAMERA_PERMISSION)) {
            onCameraPermissionGranted()
        } else {
            if (ActivityCompat.shouldShowRequestPermissionRationale(
                    this, Manifest.permission.CAMERA
                )
            ) {
                showPermissionRationale(
                    title = "Camera Permission Needed",
                    message = "We need access to your camera to proceed.",
                    onProceed = {
                        ActivityCompat.requestPermissions(
                            this, PermissionUtils.CAMERA_PERMISSION, CAMERA_REQUEST_CODE
                        )
                    })
            } else {
                ActivityCompat.requestPermissions(
                    this, PermissionUtils.CAMERA_PERMISSION, CAMERA_REQUEST_CODE
                )
            }
        }
    }

    private fun onCameraPermissionGranted() {
        binding.commonButton.btnProceed.isEnabled = true
        binding.commonButton.btnProceed.alpha = 1f
        binding.commonButton.btnProceed.performClick()
    }

    private fun showPermissionRationale(title: String, message: String, onProceed: () -> Unit) {
        AlertDialog.Builder(this).setTitle(title).setMessage(message)
            .setPositiveButton("OK") { _, _ -> onProceed() }.setNegativeButton("Cancel", null)
            .show()
    }

    private fun hasPermissions(permissions: Array<String>): Boolean {
        return permissions.all {
            ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED
        }
    }

    fun isCameraPermissionGranted(context: Context): Boolean {
        return ContextCompat.checkSelfPermission(
            context, Manifest.permission.CAMERA
        ) == PackageManager.PERMISSION_GRANTED
    }


    private fun openExitDialog() {
        val binding = ExitDialogBottomsheetBinding.inflate(layoutInflater)

        val dialog = Dialog(this)
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
        dialog.setContentView(binding.root)

        val window = dialog.window
        window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
        window?.setGravity(Gravity.BOTTOM)
        window?.setBackgroundDrawable(Color.TRANSPARENT.toDrawable())

        binding.btnExit.tvProceed.text = "Exit"

        binding.btnExit.root.setOnClickListener(View.OnClickListener { v: View? ->
            finish()
            dialog.dismiss()
        })

        binding.btnCancel.root.setOnClickListener(View.OnClickListener { v: View? ->
            dialog.dismiss()
        })

        binding.closeButton.setOnClickListener(View.OnClickListener { v: View? ->
            dialog.dismiss()
        })


        dialog.show()
    }

    override fun init() {
    }

    override fun onRequestPermissionsResult(
        requestCode: Int, permissions: Array<out String>, grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }

        when (requestCode) {
            CAMERA_REQUEST_CODE -> {
                if (allGranted) {
                    onCameraPermissionGranted()
                }
            }
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_QR && resultCode == RESULT_OK && data != null) {
            val device: PocDevice? = data.getParcelableExtra("device")
            if (device != null) {
                val lastConnectCgm = CgmTrackyLibModule.lastConnectCgm
                Log.d("ConnectSensor", "lastConnectCgm: $lastConnectCgm")

                if (lastConnectCgm.equals("Diasens", ignoreCase = true)) {
                    // Diasens user - validate sensor ID against API
                    validateDiasensSensor(device)
                } else {
                    // Non-Diasens user - proceed directly
                bind(device)
                }
            }
        }
    }

    private fun validateDiasensSensor(device: PocDevice) {
        try {
            // Get the scanned sensor ID from QR information
            val prefsHelper = SharedPreferencesLibraryUtil(this)
            val qrInformation = prefsHelper.qrInformation
            val scannedSensorId = qrInformation?.sensor ?: ""

            Log.d("ConnectSensor", "Validating Diasens sensor ID: $scannedSensorId")

            if (scannedSensorId.isEmpty()) {
                Log.e("ConnectSensor", "Scanned sensor ID is empty")
                manageErrorState(true, "Sensor is not mapped")
                return
            }

            // Show loading while validating
            ProgressManagement.getInstance()
                .showWait(this, ProgressType.PROGRESSDIALOG_CONNECT, null)

            val envType = CgmTrackyLibModule.env
            val token = CgmTrackyLibModule.userToken
            val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
            val authenticateSDKService = AuthenticateSDKService(scope = scope)

            authenticateSDKService.verifyDevice(
                environment = if (envType.lowercase() == "uat") TATVA_ENVIRONMENT.STAGE else TATVA_ENVIRONMENT.PROD,
                token = token,
                sensorId = scannedSensorId,
                responseListener = object : AuthenticateSDKService.ResponseListener {
                    override fun onResponseSuccess(response: String) {
                        try {
                            Log.d("ConnectSensor", "Device verification API response: $response")

                            val verificationResponse = Gson().fromJson(response, DeviceVerificationResponse::class.java)
                            val code = when (val rawCode = verificationResponse.code) {
                                is Number -> rawCode.toInt()
                                is String -> rawCode.toIntOrNull() ?: 0
                                else -> 0
                            }
                            val data = verificationResponse.data
                            val msg = verificationResponse.msg

                            runOnUiThread {
                                ProgressManagement.getInstance().dismissWait(this@ConnectSensorActivity)

                                if (code == 1 && data == true) {
                                    // Device verification successful - proceed with bind
                                    Log.d("ConnectSensor", "Device verification successful for sensor: $scannedSensorId")
                                    bind(device)
                                } else if (code == 1 && data == false) {
                                    // Device verification failed - show API msg in red (with fallback)
                                    Log.e("ConnectSensor", "Device verification failed: $msg")
                                    val errorMessage = if (msg.isNotEmpty()) msg else "This is not a Diasens CGM sensor. Please connect a Diasens sensor to continue."
                                    manageDeviceVerificationError(errorMessage)
                                } else {
                                    // code 0 or unexpected - show Try Again
                                    Log.e("ConnectSensor", "Device verification error, code: $code")
                                    manageErrorState(true, "Try Again")
                                }
                            }
                        } catch (e: Exception) {
                            Log.e("ConnectSensor", "Error parsing device verification response: ${e.message}")
                            runOnUiThread {
                                ProgressManagement.getInstance().dismissWait(this@ConnectSensorActivity)
                                manageErrorState(true, "Try Again")
                            }
                        }
                    }

                    override fun onResponseFail() {
                        Log.e("ConnectSensor", "Device verification API call failed")
                        runOnUiThread {
                            ProgressManagement.getInstance().dismissWait(this@ConnectSensorActivity)
                            manageErrorState(true, "Try Again")
                        }
                    }
                }
            )
        } catch (e: Exception) {
            Log.e("ConnectSensor", "Error validating diasens sensor: ${e.message}")
            ProgressManagement.getInstance().dismissWait(this)
            manageErrorState(true, "Try Again")
        }
    }

    private fun manageDeviceVerificationError(message: String) {
        ProgressManagement.getInstance().dismissWait(this)
        binding.clFail.visibility = View.VISIBLE
        binding.clMain.visibility = View.GONE
        binding.commonButton.root.visibility = View.GONE

        Glide.with(this).asGif().load(R.drawable.warning).into(binding.ivGif)

        binding.btnSupport.tvProceed.text = "Contact Support"
        binding.btnRetry.tvProceed.text = "Retry"

        binding.llWatchDemo.post {
            binding.llWatchDemo.setOnClickListener {
                startActivity(
                    Intent(this, VideoActivity::class.java).putExtra("VideoId", "zRlFFdr-QD4")
                )
            }
        }

        binding.btnSupport.btnProceed.setOnClickListener {
            startActivity(
                Intent(this, HelpActivity::class.java).putExtra("ScreenName", "Sensor Screen")
            )
        }

        binding.btnRetry.btnProceed.setOnClickListener {
            sendDataToRN("", "cgm_retry_connect_sensor_clicked")

            transmitterDeviceInfo?.let {
                QRActivity.startQR(this, it.pocDevice)
            }
        }

        // Replace "Unable to detect sensor" title with the error message in RED
        binding.tvFailTitle.text = message
        binding.tvFailTitle.setTextColor(Color.RED)
        // Set text size to 16sp (same as iOS) for validation API error message
        binding.tvFailTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16f)
        binding.tvFailInstructions.visibility = View.GONE
        binding.tvReason.visibility = View.GONE

        val jsonObject = JSONObject()
        jsonObject.put("error_description", message)
        sendDataToRN(jsonObject.toString(), "cgm_sensor_connection_failed")
    }

    private fun bind(device: PocDevice) {
        try {
            if (device.address != null) {
                ManageGattCallback.getInstance().ConnectViaAddress(device.address)
                ManageScanCallback.getInstance().stopLeScan()
                ProgressManagement.getInstance()
                    .showWait(this, ProgressType.PROGRESSDIALOG_CONNECT, null)
            }
        } catch (e: Exception) {
            Log.d("bind::-> ", "bind: ${e.message}")
        }
    }

    override fun onClick(p0: View?) {
    }

    override fun bindFail() {
        super.bindFail()
        manageErrorState(true, "Bind Fail")
    }

    override fun bindSuccess() {
        super.bindSuccess()
        ProgressManagement.getInstance().dismissWait(this)
        if (isForReconnect) {
            sendDataToRN("", "WARM_PERIOD_STARTED")
            startActivity(
                Intent(this, SensorConnectSuccessActivity::class.java).putExtra(
                    "IsForReconnect", true
                )
            )
        } else {
            startActivity(Intent(this, SensorConnectSuccessActivity::class.java))
        }
        finish()
    }

    private fun sendDataToRN(data: String, status: String) {
        if (reactContext != null) {
            try {
                val catalystInstance: CatalystInstance = reactContext.catalystInstance
                val module = catalystInstance.getNativeModule(CgmTrackyLibModule::class.java)

                if (module == null) {
                    sendDataToRNDirectly(data, status)
                    Log.d("sendDataToRN: ", "Module null")
                } else {
                    module.sendDataToReact(data, status, "cgmDeviceEvent")
                    Log.d("sendDataToRN: ", "Module is not null")
                }
            } catch (e: Exception) {
                Log.e("sendDataToRN: Error ", e.message.toString())
            }
        } else {
            Log.e("TrackyActivity", "ReactApplicationContext is null")
        }
    }


    private fun sendDataToRNDirectly(data: String, status: String) {
        try {
            val map: WritableMap = Arguments.createMap().apply {
                putString("data", data)
                putString("status", status)
            }

            reactContext?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
                ?.emit("cgmDeviceEvent", map)
        } catch (e: Exception) {
            Log.e("sendDataToRNDirectly", "Error sending data to React", e)
        }
    }


    override fun bluetoothStateOFF() {
        super.bluetoothStateOFF()
        manageErrorState(true, "Bluetooth Off")

    }

    override fun disconnect() {
        super.disconnect()
        manageErrorState(true, "Disconnected")

    }

    override fun disconnectForTimeout() {
        super.disconnectForTimeout()
        manageErrorState(true, "Disconnected")

    }

    override fun checkFailForLowPower() {
        super.checkFailForLowPower()
        manageErrorState(true, "Low Power")

    }

    override fun checkFailErrorTemperature() {
        super.checkFailErrorTemperature()
        manageErrorState(true, "Temperature Error")

    }

    override fun unbindReset() {
        super.unbindReset()
        manageErrorState(true, "Unbinded")

    }

    override fun unbindCommand() {
        super.unbindCommand()
        manageErrorState(true, "Unbinded")

    }

}
