package com.grkj.iscs.view.activity.test.face

import android.annotation.SuppressLint
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ImageFormat
import android.graphics.Matrix
import android.graphics.Rect
import android.graphics.YuvImage
import android.media.FaceDetector
import android.media.Image
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageAnalysis.Analyzer
import androidx.camera.core.ImageProxy
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.content.ContextCompat
import androidx.core.util.Consumer
import java.io.ByteArrayOutputStream
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors


/**
 * 使用cameraX和FaceDetector进行人脸识别
 *
 * @author fdk
 * @date 2024-04-22
 */
class FaceDetectorHelper(
    private var mCameraExecutor: ExecutorService = Executors.newSingleThreadExecutor(),
    private var mSelector: CameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
) {
    // 提供相机服务
    private lateinit var mCameraProvider: ProcessCameraProvider

    private lateinit var imagePreview: Preview

    private lateinit var imageAnalysis: ImageAnalysis

    // 人脸识别控制
    var isOpenDetector = false

    // 摄像头方向
    private var currentLensFacing = CameraSelector.LENS_FACING_BACK

    /**
     * 使用CameraX API进行预览
     *
     * @param activity 带lifecycle的activity，提供context，并且便于使用协程
     * @param view Camera API使用的 PreviewView
     */
    @SuppressLint("RestrictedApi")
    fun startPreview(
        activity: ComponentActivity,
        view: PreviewView,
        callback: Consumer<Bitmap>
    ) {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(activity)
        cameraProviderFuture.addListener({
            // 用于将相机的生命周期绑定到生命周期所有者
            // 消除了打开和关闭相机的任务，因为 CameraX 具有生命周期感知能力
            mCameraProvider = cameraProviderFuture.get()

            // 预览
            imagePreview = Preview.Builder()
                .build()
                .also {
                    it.setSurfaceProvider(view.surfaceProvider)
                }

            // 配置图像分析
            imageAnalysis = ImageAnalysis.Builder()
                .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                .build()
            imageAnalysis.setAnalyzer(mCameraExecutor, FaceAnalyzer(callback))

            // 选择摄像头，省去了去判断摄像头ID
            val cameraSelector = mSelector

            try {
                // Unbind use cases before rebinding
                mCameraProvider.unbindAll()

                // 将相机绑定到 lifecycleOwner，就不用手动关闭了
                mCameraProvider.bindToLifecycle(
                    activity, cameraSelector, imagePreview, imageAnalysis)

            } catch(exc: Exception) {
                Log.e("TAG", "Use case binding failed", exc)
            }

            // 回调代码在主线程处理
        }, ContextCompat.getMainExecutor(activity))
    }

    fun switchCamera(activity: ComponentActivity) {
        currentLensFacing = if (currentLensFacing == CameraSelector.LENS_FACING_BACK) {
            CameraSelector.LENS_FACING_FRONT
        } else {
            CameraSelector.LENS_FACING_BACK
        }

        val newCameraSelector = CameraSelector.Builder()
            .requireLensFacing(currentLensFacing)
            .build()

        try {
            mCameraProvider.unbindAll()
            mCameraProvider.bindToLifecycle(activity, newCameraSelector, imagePreview, imageAnalysis)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 开启人脸识别
     */
    fun startDetector() {
        isOpenDetector = true
    }

    /**
     * 停止人脸识别
     */
    fun stopDetector() {
        isOpenDetector = false
    }

    /**
     * 释放资源
     */
    fun release() {
        // 取消绑定生命周期观察者
        mCameraProvider.unbindAll()
    }

    private inner class FaceAnalyzer(
        private val callback: Consumer<Bitmap>
    ) : Analyzer {

        private val maxFaces = 1
        private var faceDetector: FaceDetector? = null

        @SuppressLint("UnsafeOptInUsageError")
        override fun analyze(image: ImageProxy) {
            // Log.d("TAG", "analyze: ${image.format}")

            // 控制人脸检测
            if (!isOpenDetector) {
                image.close()
                return
            }

            val bitmap = if (image.format == ImageFormat.YUV_420_888) {
                val rotation = image.imageInfo.rotationDegrees
                imageProxyToBitmap(image.image!!, rotation)
            }else {
                imageProxyToBitmap(image)
            }

            // 创建FaceDetector
            if (faceDetector == null) {
                faceDetector = FaceDetector(bitmap.width, bitmap.height, maxFaces)
            }

            // 进行人脸检测
            val faces = arrayOfNulls<FaceDetector.Face>(maxFaces)
            val faceCount = faceDetector!!.findFaces(bitmap, faces)

            // 处理人脸检测结果
            if (faceCount > 0) {

                // 第一张脸信息
                val face1 = faces[0]!!
                // 人脸的可信度，0 - 1
                val confidence = face1.confidence()
                // 双眼的间距
                // val eyesDistance = face1.eyesDistance()
                // 角度
                // val angle = face1.pose(FaceDetector.Face.EULER_X)

                Log.d("TAG", "analyze: confidence = $confidence")

                // 加点判断，传出结果
                if (confidence > 0.5){
                    callback.accept(bitmap)
                }else {
                    bitmap.recycle()
                }
            }else {
                bitmap.recycle()
            }

            image.close()
        }

        private fun imageProxyToBitmap(image: Image, rotationDegrees: Int): Bitmap {
            val yBuffer = image.planes[0].buffer
            val uBuffer = image.planes[1].buffer
            val vBuffer = image.planes[2].buffer

            val ySize = yBuffer.remaining()
            val uSize = uBuffer.remaining()
            val vSize = vBuffer.remaining()

            val nv21 = ByteArray(ySize + uSize + vSize)
            yBuffer.get(nv21, 0, ySize)
            vBuffer.get(nv21, ySize, vSize)
            uBuffer.get(nv21, ySize + vSize, uSize)

            val yuvImage = YuvImage(nv21, ImageFormat.NV21, image.width, image.height, null)
            val outputStream = ByteArrayOutputStream()
            yuvImage.compressToJpeg(Rect(0, 0, image.width, image.height), 100, outputStream)
            val jpegArray = outputStream.toByteArray()

            val options = BitmapFactory.Options()
            options.inPreferredConfig = Bitmap.Config.RGB_565
            val bitmap = BitmapFactory.decodeByteArray(jpegArray, 0, jpegArray.size, options)

            val matrix = Matrix()
            matrix.postRotate(rotationDegrees.toFloat())

            return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
        }

        private fun imageProxyToBitmap(image: ImageProxy): Bitmap {
            val planeProxy = image.planes[0]
            val buffer = planeProxy.buffer

            val bytes = ByteArray(buffer.remaining())
            buffer.get(bytes)

            return BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
        }
    }
}