package com.dlc.laboratory.ui.leave

import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection
import android.os.*
import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.dlc.eboard.LabApp
import com.dlc.eboard.common.CommonUtils
import com.dlc.eboard.common.Constants
import com.dlc.eboard.mqtt.AudioService
import com.dlc.eboard.ui.dialog.CheckResultDialog
import com.dlc.eboard.ui.leave.LeaveFaceMatchingFragment
import com.rc.core.util.Format
import com.rc.core.util.MediaUtils
import com.rc.httpcore.client.ApiRepository
import com.rc.httpcore.exception.NetException
import com.rc.httpcore.vo.response.SignInCheckResp
import io.fotoapparat.Fotoapparat
import io.fotoapparat.facedetector.processor.FaceDetectorProcessor
import io.fotoapparat.log.fileLogger
import io.fotoapparat.log.logcat
import io.fotoapparat.log.loggers
import io.fotoapparat.selector.back
import io.fotoapparat.selector.front
import java.io.File
import java.text.SimpleDateFormat
import java.util.*

/**
 * info
 *
 * @author ReiChin_
 */
class ExLeaveFaceMatchingFragment: LeaveFaceMatchingFragment() {

    companion object {

        const val TAG = "ExLeaveFaceMatchingFragment"

        private const val WHAT_TAKE_PICTURE = 1
        private const val TIMEOUT_TAKE_PICTURE = 2000L

        /**
         * @param username 学生卡编号
         */
        fun newInstance(username: String): ExLeaveFaceMatchingFragment {
            val args = Bundle()
            args.putString("username", username)
            val fragment = ExLeaveFaceMatchingFragment()
            fragment.arguments = args
            return fragment
        }
    }

    private var isMatching = true

    private fun textParseVideo(text: String?) {
        if (text.isNullOrEmpty()) return

        showLoading()
        val disposable = ApiRepository.textParseVideo(text)
            .subscribe({ data ->
                dismissLoading()
                mAudioBinder?.startPlayer(data.url)
            }, { throwable ->
                dismissLoading()
                throwable.printStackTrace()
                showNetError(throwable)
            })
        addDisposable(disposable)
    }

    private var mAudioBinder: AudioService.AudioBinder? = null

    private val mAudioConnection: ServiceConnection = object : ServiceConnection {

        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            mAudioBinder = service as AudioService.AudioBinder
        }

        override fun onServiceDisconnected(name: ComponentName) {
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        requireContext().bindService(
            Intent(requireContext(), AudioService::class.java), mAudioConnection,
            AppCompatActivity.BIND_AUTO_CREATE
        )
    }

    override fun onDestroy() {
        super.onDestroy()
        requireContext().unbindService(mAudioConnection)
    }

    private lateinit var mFotoapparat: Fotoapparat

    override fun initViews(savedInstanceState: Bundle?) {
        isMatching = false
        mFotoapparat = Fotoapparat.with(requireContext())
            .into(viewBinding.cameraView)
            .lensPosition(back())
            .frameProcessor(
                FaceDetectorProcessor.with(requireContext())
                    .listener { faces ->
                        viewBinding.rectanglesView.setRectangles(faces)
//                        if (!isMatching && isResumed && !faces.isNullOrEmpty()) takePicture()
                        if (!isMatching && isResumed) {
                            isMatching = true
                            mTakePictureHandler.sendEmptyMessageDelayed(WHAT_TAKE_PICTURE, TIMEOUT_TAKE_PICTURE)
                        }
                    }.build()
            )
            .logger(loggers(logcat(), fileLogger(requireContext())))
            .build()
        viewBinding.cameraViewRoot.visibility = View.VISIBLE
        callStudentCheckApi()
    }

    private fun callStudentCheckApi() {
        if (null == LabApp.sLabConfig) {
            showToast("暂无实验室信息，即将重新获取")
            CommonUtils.restartApp(requireActivity())
            return
        }
        val username =  requireArguments().getString("username")!!
        showLoading("查询中...")
        val disposable = ApiRepository.signOutCheck(false, LabApp.sLabConfig!!.labId, username)
            .subscribe({ data ->
                dismissLoading()
                mStudentInfo = data
                refreshPersonViews()
            }, { throwable ->
                dismissLoading()
                throwable.printStackTrace()
                showNetError(throwable)
            })
        addDisposable(disposable)
    }

    @SuppressLint("SetTextI18n")
    override fun updateViolationViews(data: SignInCheckResp) {
        // 违规行为
        viewBinding.violationContent.text =
            "违规行为：${data.singInViolation.violationContent ?: ""}"
        // 违规地点
        viewBinding.subjectName.text = "违规地点：${data.singInViolation.subjectName ?: ""}"
        // 违规时间
        viewBinding.createTime.text = "违规时间：${
            Format.formatZonedDateTime(
                data.singInViolation.createTime,
                "yyyy年MM月dd日 HH:mm"
            )
        }"
        // 提示信息
        if (!data.message.isNullOrEmpty()) {
            viewBinding.infoLayout.visibility = View.VISIBLE
            val message = data.message.reduce { acc, s -> "$acc\n$s" }
//                    ?.let { it.substring(0, it.length - 1) }
            viewBinding.signInTips.text = message
            textParseVideo(data.message[0])
        } else {
            if (!data.tips.isNullOrEmpty()) {
                viewBinding.infoLayout.visibility = View.VISIBLE
                val tips = data.tips.reduce { acc, s -> "$acc\n$s" }
//                        ?.let { it.substring(0, it.length - 1) }
                viewBinding.signInTips.text = tips
                textParseVideo(data.message[0])
            } else {
                viewBinding.infoLayout.visibility = View.INVISIBLE
            }
        }

//            viewBinding.camera.isEnabled = data.state
        if (!data.state) {
            // 弹出核验结果的Dialog，，5秒后关闭Dialog
            val dialog = CheckResultDialog()
            dialog.setSuccess(data.state)
            dialog.show(requireFragmentManager(), CheckResultDialog::class.java.simpleName)
        } else {
            // 核验通过，直接人脸识别
            isMatching = false
        }
    }

    private fun inSignWhiteList(): Boolean {
        return Constants.Mock.SIGN_WHITE_LIST.contains(mStudentInfo?.singInUser?.userId)
    }

    private val mTakePictureHandler = object : Handler(Looper.getMainLooper()) {

        override fun handleMessage(msg: Message) {
            if (!isResumed) return
            if (WHAT_TAKE_PICTURE == msg.what) takePicture()
        }
    }

    private fun takePicture() {
//        isMatching = true
        val format = SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.getDefault())
        val fileName = "${format.format(Calendar.getInstance().time)}.jpg"
        val photoFile = File(requireContext().getExternalFilesDir("photos"), fileName)
        mFotoapparat.takePicture()
            .saveToFile(photoFile)
            .whenAvailable {
                callFaceMatchingApi(photoFile)
            }
    }

    override fun onResume() {
        super.onResume()
        mFotoapparat.start()
        isMatching = false
    }

    override fun onPause() {
        super.onPause()
        mFotoapparat.stop()
        mTakePictureHandler.removeCallbacksAndMessages(null)
    }

    private fun callFaceMatchingApi(photoFile: File) {
        val userId = mStudentInfo?.singInUser?.userId ?: return

        showLoading("比对中....")
        val disposable = ApiRepository.leaveFaceMatching(photoFile, userId)
            .subscribe({ success ->
                dismissLoading()
                MediaUtils.deleteFile(photoFile)
                if (success) {
                    // 人脸比对成功，显示离开检查相关View
                    if (inSignWhiteList()) {
                        callLeaveApi()
                    } else {
                        showLeaveCheckView()
                    }
                }
            }, { throwable ->
                dismissLoading()
                MediaUtils.deleteFile(photoFile)
                if (!pretreatmentError(throwable)) {
                    isMatching = false
                    throwable.printStackTrace()
                    showNetError(throwable)
                }
            })
        addDisposable(disposable)
    }

    private fun pretreatmentError(throwable: Throwable): Boolean {
        if (throwable is NetException) {
            // 600- 签到&签出已超时，请重新刷卡重试！
            if ("600" == throwable.code) {
                AlertDialog.Builder(requireContext())
                    .setTitle("提示")
                    .setMessage(throwable.message)
                    .setPositiveButton("确定") { _, _ ->
                        callStudentCheckApi()
                    }.show()
                return true
            } else if ("500" == throwable.code &&
                true == throwable.message?.startsWith("人脸对比不符")
            ) {
                // 500- 人脸对比不符！
                AlertDialog.Builder(requireContext())
                    .setCancelable(false)
                    .setTitle("提示")
                    .setMessage(throwable.message)
                    .setPositiveButton("确定") { _, _ ->
                        isMatching = false
                    }.show()
                return true
            } else if ("500" == throwable.code
                && throwable.message == "识别中") {
                isMatching = false
                return true
            }
        }
        return false
    }

}