package com.casic.common.detector.gd.view

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.graphics.Color
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.media.AudioAttributes
import android.media.SoundPool
import android.os.Bundle
import android.os.CountDownTimer
import android.os.IBinder
import android.util.Log
import android.view.View
import android.view.WindowManager
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.amap.api.location.AMapLocation
import com.amap.api.maps.AMapUtils
import com.amap.api.maps.model.LatLng
import com.casic.common.detector.gd.R
import com.casic.common.detector.gd.callback.OnGetLocationListener
import com.casic.common.detector.gd.callback.OnSerialPortListener
import com.casic.common.detector.gd.databinding.ActivitySearchMarkerBinding
import com.casic.common.detector.gd.extensions.handleSignalStrength
import com.casic.common.detector.gd.extensions.hexToString
import com.casic.common.detector.gd.extensions.isNumber
import com.casic.common.detector.gd.extensions.toHex
import com.casic.common.detector.gd.model.MarkerDistanceData
import com.casic.common.detector.gd.service.SerialPortService
import com.casic.common.detector.gd.utils.DataBaseManager
import com.casic.common.detector.gd.utils.LocaleConstant
import com.casic.common.detector.gd.utils.LocationTool
import com.casic.common.detector.gd.vm.TaskViewModel
import com.casic.common.detector.gd.widgets.RadarScanView
import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.getSystemService
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.Constant
import com.pengxh.kt.lite.utils.LoadingDialog
import com.pengxh.kt.lite.utils.SaveKeyValues
import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.Timer
import java.util.TimerTask
import kotlin.math.atan2

class SearchMarkerActivity : KotlinBaseActivity<ActivitySearchMarkerBinding>(),
    SensorEventListener {

    private val kTag = "SearchMarkerActivity"
    private val context = this
    private val locationTool by lazy { LocationTool(this) }
    private val markerPoints by lazy { ArrayList<MarkerDistanceData>() }
    private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
    private val sensorManager by lazy { getSystemService<SensorManager>() }
    private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
    private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
    private val rotationMatrix = FloatArray(9)//旋转矩阵缓存
    private val valueArray = FloatArray(3)//方位角数值
    private var slowSoundResourceId = 0
    private var fastSoundResourceId = 0
    private var markerId = ""//实际探测出来的标识器ID
    private var nearestMarkerId = ""//探测不到标识器的时候计算出来的最近的标识器ID
    private var isExecuteTask = false
    private var signalEnergy = 0 //标识器信号强度
    private var gravity: FloatArray? = null
    private var geomagnetic: FloatArray? = null
    private var serialPortService: SerialPortService? = null
    private lateinit var searchSignalEnergyTimer: Timer

    private val serviceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, iBinder: IBinder?) {
            if (iBinder is SerialPortService.ServiceBinder) {
                serialPortService = iBinder.getSerialPortService()
                Log.d(kTag, "onServiceConnected: 服务已绑定")
                lifecycleScope.launch(Dispatchers.Main) {
                    delay(300)
                    searchMarker()
                }
            }
        }

        override fun onServiceDisconnected(name: ComponentName?) {

        }
    }

    override fun initOnCreate(savedInstanceState: Bundle?) {
        val flag = intent.getStringExtra(Constant.INTENT_PARAM_KEY) as String
        isExecuteTask = flag != "0"

        //绑定串口通信服务
        Intent(this, SerialPortService::class.java).also {
            bindService(it, serviceConnection, Context.BIND_AUTO_CREATE)
        }

        slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1)
        fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1)

        //点位渲染，每次定位都计算当前位置与符合条件的点距离
        locationTool.getCurrentLocation(false, object : OnGetLocationListener {
            override fun onSuccess(location: AMapLocation) {
                renderDataPoint(location)
            }

            override fun onError() {
                "当前位置信号差，无法获取定位".show(context)
            }
        })

        if (isExecuteTask) {
            binding.taskStateView.visibility = View.GONE
            binding.taskStateView.isSelected = false
        } else {
            binding.taskStateView.visibility = View.VISIBLE
            binding.taskStateView.isSelected = true
        }

        //在标识器信号强度很强的时候，从数据库中计算出距离最近的点，以防出现探测不到ID的情况
        searchSignalEnergyTimer = Timer()
        searchSignalEnergyTimer.schedule(object : TimerTask() {
            override fun run() {
                if (signalEnergy <= 700) {//18°
                    runOnUiThread {
                        binding.energyTipsView.text = "信号较弱，可能距离较远"
                        binding.energyTipsView.setTextColor(Color.parseColor("#8D1717"))
                        binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_red)

                        binding.depthButton.isEnabled = false
                        binding.depthButton.setTextColor(Color.parseColor("#CCCCCC"))
                        binding.depthButton.setBackgroundResource(R.mipmap.left_button_disable)
                        binding.markerInfoButton.isEnabled = false
                        binding.markerInfoButton.setTextColor(Color.parseColor("#CCCCCC"))
                        binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_disable)

                        binding.searchResultView.text = "未检测到标识器"
                        binding.searchResultView.setTextColor(Color.parseColor("#8D1717"))
                        binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_red)
                    }
                } else if (signalEnergy >= 4100 && markerPoints.isNotEmpty()) {
                    //markerId为空，说明没有通过探测得到标识器ID，那么就需要通过计算得到近似的标识器
                    try {
                        //需要转一下，不然会有并发问题
                        val temp = ArrayList<MarkerDistanceData>()
                        temp.addAll(markerPoints)
                        temp.sortBy(MarkerDistanceData::distance)
                        val nearestPoint = temp.first()
                        nearestMarkerId = nearestPoint.markerId
                        runOnUiThread {
                            handleMarker(nearestMarkerId)
                        }
                        markerPoints.clear()
                    } catch (e: NullPointerException) {
                        e.printStackTrace()
                    }
                } else {
                    runOnUiThread {
                        binding.energyTipsView.text = "已靠近，请继续移动位置"
                        binding.energyTipsView.setTextColor(Color.parseColor("#8C5700"))
                        binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_yellow)
                    }
                }
            }
        }, 0, 2000)
    }

    private val countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
        override fun onTick(millisUntilFinished: Long) {

        }

        override fun onFinish() {
            LoadingDialog.dismiss()
            serialPortService?.closeSerialPort()
            "标识器深度探测超时，请移动位置重试".show(context)
            lifecycleScope.launch(Dispatchers.Main) {
                delay(300)
                searchMarker()
            }
        }
    }

    override fun initEvent() {
        binding.depthButton.setOnClickListener {
            stopSearchMarker()
            val result = DataBaseManager.get.queryMarkerById(markerId)
            if (result.isNotEmpty()) {
                val tag = when (result.first().markerType) {
                    "EM30" -> '7'
                    "EM50" -> '8'
                    "EM14" -> '9'
                    else -> '1'
                }
                if (tag == '1') {
                    "此标识器无法读取埋深！".show(this)
                    lifecycleScope.launch(Dispatchers.Main) {
                        delay(300)
                        searchMarker()
                    }
                } else {
                    LoadingDialog.show(this, "正在探测标识器埋深，请稍后...")
                    countDownTimer.start()
                    // 发送读取标识器埋设深度指令
                    serialPortService?.openSerialPort(
                        arrayListOf(tag), object : OnSerialPortListener {
                            override fun onDataReceived(buffer: ByteArray) {
                                val hex = buffer.toHex()
                                if (hex.startsWith("53")) {
                                    runOnUiThread {
                                        LoadingDialog.dismiss()
                                        countDownTimer.cancel()
                                        showDepthDialog(hex)
                                    }
                                }
                            }
                        })
                }
            } else {
                LoadingDialog.dismiss()
                "标识器未安装，安装成功后才可读取埋深！".show(this)
                lifecycleScope.launch(Dispatchers.Main) {
                    delay(300)
                    searchMarker()
                }
            }
        }

        binding.markerInfoButton.setOnClickListener {
            val id = if (markerId == "") {
                nearestMarkerId
            } else {
                markerId
            }
            //查库
            val result = DataBaseManager.get.queryMarkerById(id)
            if (result.isNotEmpty()) {
                navigatePageTo<ObjectDetailActivity>(id)
            } else {
                navigatePageTo<NewObjectDetailActivity>(id)
            }
            //查看完就把ID置空，便于下次查看最新的ID
            markerId = ""
        }
    }

    private fun showDepthDialog(hex: String) {
        try {
            val depthResponse = hex.take(10).hexToString()
            Log.d(kTag, "showDepthDialog: $depthResponse")
            val depth = depthResponse.drop(2).toInt()
            AlertMessageDialog.Builder().setContext(context)
                .setTitle("温馨提示")
                .setMessage("标识器埋深：${depth}厘米")
                .setPositiveButton("知道了")
                .setOnDialogButtonClickListener(object :
                    AlertMessageDialog.OnDialogButtonClickListener {
                    override fun onConfirmClick() {
                        serialPortService?.closeSerialPort()
                        lifecycleScope.launch(Dispatchers.Main) {
                            delay(300)
                            searchMarker()
                        }
                    }
                }).build().show()
        } catch (e: WindowManager.BadTokenException) {
            e.printStackTrace()
        } catch (e: NumberFormatException) {
            e.printStackTrace()
        }
    }

    /**
     * 搜索标识器
     * */
    private fun searchMarker() {
        serialPortService?.openSerialPort(arrayListOf('2', '6'), object : OnSerialPortListener {
            override fun onDataReceived(buffer: ByteArray) {
                runOnUiThread {
                    if (buffer.first() == 78.toByte()) {
                        val energy = buffer.handleSignalStrength().take(10).hexToString()
                        try {
                            signalEnergy = energy.substring(1).toInt()
                            if (signalEnergy >= 4000) {
                                soundPool.play(fastSoundResourceId, 1f, 1f, 0, 0, 1f)
                            } else {
                                soundPool.play(slowSoundResourceId, 1f, 1f, 0, 0, 1f)
                            }

                            //通过设置进度条表示能量值
                            binding.energyPgBar.progress = signalEnergy
                            binding.energyValueView.text = "${signalEnergy}dB"

                            //根据信号强度更新界面
                            if (signalEnergy <= 700) {//18°
                                binding.energyTipsView.text = "信号较弱，可能距离较远"
                                binding.energyTipsView.setTextColor(Color.parseColor("#8D1717"))
                                binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_red)

                                binding.depthButton.isEnabled = false
                                binding.depthButton.setTextColor(Color.parseColor("#CCCCCC"))
                                binding.depthButton.setBackgroundResource(R.mipmap.left_button_disable)
                                binding.markerInfoButton.isEnabled = false
                                binding.markerInfoButton.setTextColor(Color.parseColor("#CCCCCC"))
                                binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_disable)

                                binding.searchResultView.text = "未检测到标识器"
                                binding.searchResultView.setTextColor(Color.parseColor("#8D1717"))
                                binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_red)
                            } else if (signalEnergy >= 4100) {
                                binding.energyTipsView.text = "信号极强，接近标识器正上方"
                                binding.energyTipsView.setTextColor(Color.parseColor("#428d00"))
                                binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green)
                            } else {
                                binding.energyTipsView.text = "已靠近，请继续移动位置"
                                binding.energyTipsView.setTextColor(Color.parseColor("#8C5700"))
                                binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_yellow)
                            }
                        } catch (e: NumberFormatException) {
                            e.printStackTrace()
                        }
                    } else {
                        val id = buffer.toHex().take(20).hexToString()
                        Log.d(kTag, buffer.contentToString())
                        if (id.isNumber()) {
                            markerId = id
                            handleMarker(markerId)
                        }
                    }
                }
            }
        })
    }

    private fun stopSearchMarker() {
        soundPool.autoPause()
        serialPortService?.closeSerialPort()

        Thread.sleep(100)
    }

    /**
     * 计算并渲染数据点。点太多采用协程计算，不然会有点卡顿。默认2s计算一次
     * @param location 定位点（RTK获取）
     * */
    private fun renderDataPoint(location: AMapLocation) {
        val longitude = location.longitude
        val latitude = location.latitude
        lifecycleScope.launch(Dispatchers.IO) {
            val dataPoints = ArrayList<RadarScanView.DataPoint>()
            DataBaseManager.get.loadMarkers().forEach {
                val distance = AMapUtils.calculateLineDistance(
                    LatLng(it.lat.toDouble(), it.lng.toDouble()), LatLng(latitude, longitude)
                )
                val formatDistance = "%.2f".format(distance).toFloat()
                markerPoints.add(MarkerDistanceData(it.markerId, formatDistance))

                if (formatDistance <= LocaleConstant.MAX_DISTANCE) {
                    val angle = atan2(
                        (it.lat.toDouble() - latitude), (it.lng.toDouble() - longitude)
                    ) + Math.PI
                    val formatAngle = "%.2f".format(angle).toDouble()

                    dataPoints.add(
                        RadarScanView.DataPoint(it.markerId, formatAngle, formatDistance)
                    )
                }
            }
            withContext(Dispatchers.Main) {
                binding.radarScanView.renderPointData(dataPoints,
                    object : RadarScanView.OnGetNearestPointCallback {
                        override fun getNearestPoint(point: RadarScanView.DataPoint?) {
                            if (point == null) {
                                binding.distanceValueView.text = "大于5.5m"
                                binding.distancePgBar.progress = 100
                            } else {
                                binding.distanceValueView.text = "${point.distance}m"
                                val progress = if (point.distance > LocaleConstant.MAX_DISTANCE) {
                                    100
                                } else {
                                    (point.distance / LocaleConstant.MAX_DISTANCE) * 100
                                }
                                binding.distancePgBar.progress = progress.toInt()
                            }
                        }
                    }
                )
            }
        }
    }

    override fun initViewBinding(): ActivitySearchMarkerBinding {
        return ActivitySearchMarkerBinding.inflate(layoutInflater)
    }

    override fun observeRequestState() {

    }

    override fun setupTopBarLayout() {

    }

    private fun handleMarker(id: String) {
        binding.depthButton.isEnabled = true
        binding.depthButton.setTextColor(Color.WHITE)
        binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable)
        binding.markerInfoButton.isEnabled = true
        binding.markerInfoButton.setTextColor(Color.WHITE)
        binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_enable)

        binding.searchResultView.text = "已检测到标识器"
        binding.searchResultView.setTextColor(Color.parseColor("#428d00"))
        binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green)

        //自动上传标识器
        if (isExecuteTask) {
            val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String
            val taskCode = SaveKeyValues.getValue(LocaleConstant.TASK_CODE, "") as String
            val taskMarkerLocalBean = DataBaseManager.get.queryTaskMarkerById(
                taskId, taskCode, id, "0"
            )
            taskMarkerLocalBean?.apply {
                taskViewModel.uploadMarker(context, this)
            }
        }
    }

    override fun onResume() {
        super.onResume()
        //注册加速度传感器监听
        val accelerometer = sensorManager?.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
        sensorManager?.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL)

        //注册磁场传感器监听
        val magnetic = sensorManager?.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
        sensorManager?.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL)
    }

    override fun onPause() {
        super.onPause()
        sensorManager?.unregisterListener(this)
    }

    override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
        //精度发生变化时触发
    }

    override fun onSensorChanged(event: SensorEvent?) {
        //值发生变化时触发
        val type = event?.sensor?.type

        if (type == Sensor.TYPE_ACCELEROMETER) {
            gravity = event.values
        } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
            geomagnetic = event.values
        }

        if (gravity == null || geomagnetic == null) {
            return
        }

        if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) {
            SensorManager.getOrientation(rotationMatrix, valueArray)

            val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt()
            //更新罗盘角度
            binding.radarScanView.setDegreeValue(degree)
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        stopSearchMarker()
        locationTool.stopLocation()
        unbindService(serviceConnection)
    }
}