package com.example.iot_controlhost.ui.dialog;

import static android.util.Base64.NO_WRAP;

import android.app.Dialog;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraManager;
import android.media.FaceDetector;
import android.util.Base64;
import android.view.Gravity;
import android.view.SurfaceHolder;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;

import com.blankj.utilcode.util.GsonUtils;
import com.example.iot_controlhost.R;
import com.example.iot_controlhost.base.BaseDialog;
import com.example.iot_controlhost.model.net.FaceCheck;
import com.example.iot_controlhost.ui.view.CircleOverlay;
import com.example.iot_controlhost.ui.view.OnPasswordEnteredListener;
import com.example.iot_controlhost.utils.MMKVUtil;
import com.example.iot_controlhost.utils.global.RoomSetting;
import com.example.iot_controlhost.utils.log.MyLog;
import com.example.iot_controlhost.utils.network.Url;
import com.example.iot_controlhost.utils.network.XHttpManager;
import com.example.iot_controlhost.utils.network.XHttpShorthand;

import org.xutils.http.RequestParams;
import org.xutils.x;

import java.io.ByteArrayOutputStream;

import es.dmoral.toasty.Toasty;

/**
 * @Author：DuanKaiji
 * @Date:2024年1月9日 14:26:39
 * @Declaration：人脸识别弹窗
 */
public class FaceDetectionDialog extends Dialog {

    /**
     * 照相机是否在采集中
     */
    private boolean isCameraPaused = false;
    /**
     * 是否正在人脸识别中
     */
    private volatile boolean isChecking = false;
    /**
     * 识别次数（一次弹窗显示中）
     */
    public static int times = 0;
    /**
     * 识别到的图片-Bitmap格式
     */
    Bitmap bitmap;
    /**
     * 识别到的图片-ByteArrayOutputStream格式
     */
    ByteArrayOutputStream stream;
    private Camera camera;
    private CircleOverlay surfaceView;
    private SurfaceHolder surfaceHolder;
    ImageView imageView;
    Button button;
    FaceDetector faceDetector;
    FaceDetector.Face[] face;
    YuvImage image;
    Context mContext;
    TextView tvTips;
    OnPasswordEnteredListener onPasswordEnteredListener;

    public FaceDetectionDialog(@NonNull Context context, OnPasswordEnteredListener listener) {
        super(context, R.style.MyDialogTheme);
        this.mContext = context;
        this.onPasswordEnteredListener = listener;
        setContentView(R.layout.dialog_password_face);
        surfaceView = findViewById(R.id.sv);
        imageView = findViewById(R.id.iv_face);
        button = findViewById(R.id.btn_face_check);
        tvTips = findViewById(R.id.tv_tips);
        surfaceHolder = surfaceView.getHolder();
        button.setOnClickListener(view -> {
            if (stream != null) {
                imageView.setImageBitmap(bitmap);
                faceCheck(stream);
            } else {
                Toasty.error(mContext, "请正视摄像头").show();
            }
        });
        findViewById(R.id.iv_dialog_close).setOnClickListener(view -> dismiss());
//        findViewById(R.id.iv_keyboard).setOnClickListener(view -> {
//            //切换为键盘输入
//
//        });
        initFaceRecongize();
        getWindow().setAttributes(BaseDialog.getAttributes(this));
        getWindow().setGravity(Gravity.CENTER);
        show();
    }

    /**
     * 初始化人脸识别
     */
    private void initFaceRecongize() {
        try {
            times = 0;
            if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
                tvTips.setText("设备不支持相机功能");
                return;
            } else if (((CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE)).getCameraIdList().length == 0) {
                tvTips.setText("未发现有效摄像头");
                tvTips.setTextColor(Color.RED);
                return;
            }
            surfaceHolder.addCallback(new SurfaceHolder.Callback() {
                @Override
                public void surfaceCreated(@NonNull SurfaceHolder holder) {
                    // 打开相机
                    try {
                        camera = Camera.open();
                        camera.setPreviewDisplay(holder);
                        camera.setPreviewCallback((bytes, camera) -> myPreviewFrame(bytes, camera)); // 设置预览回调
                        camera.startPreview();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
                    try {
                        if (surfaceHolder.getSurface() == null) {
                            return;
                        }
                        camera.stopPreview();
                        camera.setPreviewDisplay(surfaceHolder);
                        camera.setPreviewCallback((bytes, camera) -> myPreviewFrame(bytes, camera)); // 设置预览回调
                        camera.startPreview();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
                    // 在 Surface 销毁时释放相机资源
                    if (camera != null) {
                        camera.stopPreview();
                        // 取消预览回调
                        camera.setPreviewCallback(null);
                        camera.release();
                        camera = null;
                    }
                }
            });
        } catch (CameraAccessException e) {
            MyLog.face("摄像头初始化失败");
        }
    }

    /**
     * 预览帧处理
     */
    private void myPreviewFrame(byte[] data, Camera camera) {
        Camera.Size size = camera.getParameters().getPreviewSize();
        // 计算裁剪区域
        int centerX = size.width / 2;
        int centerY = size.height / 2;
        int radius = Math.min(size.width, size.height) / CircleOverlay.FACE_RADIUS;
        int left = Math.max(0, centerX - radius);
        int top = Math.max(0, centerY - radius);
        int right = Math.min(size.width, centerX + radius);
        int bottom = Math.min(size.height, centerY + radius);
        stream = new ByteArrayOutputStream();
        face = new FaceDetector.Face[1];
        image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
        image.compressToJpeg(new Rect(left, top, right, bottom), 10, stream);
        bitmap = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size()).copy(Bitmap.Config.RGB_565, true);
        faceDetector = new FaceDetector(bitmap.getWidth(), bitmap.getHeight(), 1);
        if (faceDetector.findFaces(bitmap, face) > 0) {
            //需要自动识别，则启动该方法
            faceCheck(stream);
        } else {
            tvTips.setText("请正视摄像头");
            stream = null;
            bitmap = null;
        }
    }

    /**
     * 人脸识别（在线上传）
     */
    private boolean faceCheck(ByteArrayOutputStream stream) {
        if (isChecking) {
            return false;
        }
        MyLog.face("第" + ++times + "次识别");
        tvTips.setText("正在识别中");
        setChecking(true);
        long start = System.currentTimeMillis();
        RequestParams params = XHttpManager.getInstance().getRequestParams(Url.faceCheck, true);
        String image = "data:image/jpeg;base64," + Base64.encodeToString(stream.toByteArray(), NO_WRAP);
        params.addParameter("image", image);
        params.addParameter("operation", 0);
        x.http().post(params, new XHttpShorthand<FaceCheck>() {
            @Override
            public void success(FaceCheck result) {
                stopPreview();
                long end = System.currentTimeMillis();
                MyLog.face("耗时：" + ((end - start) / 1000) + "s\t" + result.getMessage());
                if (result.getData() == null) {
                    Toasty.info(mContext, result.getMessage()).show();
                    MMKVUtil.put(RoomSetting.USER, GsonUtils.toJson(result.getData()));
                    setChecking(false);
                    startPreview();
                } else {
                    dismiss();
                    Toasty.success(mContext, result.getData().getName() + "，欢迎使用").show();
                    onPasswordEnteredListener.listener(null);
                }
            }

            @Override
            public void error(Throwable e) {
                e.printStackTrace();
                tvTips.setText("识别失败" + e.getMessage());
                MyLog.face("识别失败：" + e.getMessage());
                setChecking(false);
            }
        });
        return true;
    }

    /**
     * 设置是否在人脸识别中
     */
    private void setChecking(boolean isChecking) {
        this.isChecking = isChecking;
        button.setEnabled(!isChecking);
    }

    /**
     * 暂停预览
     */
    private void stopPreview() {
        if (camera != null && !isCameraPaused) {
            isCameraPaused = true;
            camera.stopPreview();
        }
    }

    /**
     * 恢复预览
     */
    private void startPreview(){
            if (camera != null && isCameraPaused) {
                isCameraPaused = false;
                camera.startPreview();
            }
    }

    @Override
    public void dismiss() {
        super.dismiss();
        //关闭摄像头
        MyLog.face("关闭摄像头，停止识别");
        if (camera != null) {
            if (isCameraPaused) {
                isCameraPaused = false;
            }
            camera.stopPreview();
            camera.setPreviewCallback(null);
            camera.release();
            camera = null;
        }
    }
}
