package com.dspread.pos.faceID;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import java.util.Arrays;

public class FaceIDHelper implements TextureView.SurfaceTextureListener {

    private static final int REQUEST_CAMERA_PERMISSION = 200;
    private static final int DETECTION_INTERVAL_MS = 1000; // Check every second

    private Context context;
    private TextureView textureView;
    private FaceIDCallback callback;

    private CameraManager cameraManager;
    private CameraDevice cameraDevice;
    private CameraCaptureSession cameraCaptureSession;
    private CaptureRequest.Builder captureRequestBuilder;

    private Handler backgroundHandler;
    private HandlerThread backgroundThread;
    private String frontCameraId;
    private RealFaceDetector realFaceDetector;
    private Handler detectionHandler;
    private Runnable detectionRunnable;

    public interface FaceIDCallback {
        void onFaceDetected();
        void onCameraError(String error);
    }

    public FaceIDHelper(Context context, TextureView textureView, FaceIDCallback callback) {
        this.context = context;
        this.textureView = textureView;
        this.callback = callback;
        this.cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);

        // Initialize real face detector
        realFaceDetector = new RealFaceDetector(context, new RealFaceDetector.FaceDetectionCallback() {
            @Override
            public void onFaceDetected() {
                if (callback != null) {
                    callback.onFaceDetected();
                }
            }

            @Override
            public void onFaceDetectionError(String error) {
                Log.d("FaceIDHelper", "Face detection error: " + error);
            }

            @Override
            public void onNoFaceDetected() {
                // Continue detection
            }
        });
    }

    public void startCamera() {
        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {
            callback.onCameraError("Camera permission required");
            return;
        }

        setupCamera();
    }

    private void setupCamera() {
        try {
            frontCameraId = getFrontCameraId();
            if (frontCameraId == null) {
                callback.onCameraError("Front camera not found");
                return;
            }

            textureView.setSurfaceTextureListener(this);

        } catch (CameraAccessException e) {
            e.printStackTrace();
            callback.onCameraError("Camera access error");
        }
    }

    private String getFrontCameraId() throws CameraAccessException {
        String[] cameraIds = cameraManager.getCameraIdList();
        for (String cameraId : cameraIds) {
            CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
            Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
            if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
                return cameraId;
            }
        }
        return null;
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        openCamera();
        startFaceDetection();
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        stopFaceDetection();
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {}

    private void openCamera() {
        try {
            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
                    != PackageManager.PERMISSION_GRANTED) {
                return;
            }

            cameraManager.openCamera(frontCameraId, stateCallback, backgroundHandler);

        } catch (CameraAccessException e) {
            e.printStackTrace();
            callback.onCameraError("Failed to open camera");
        }
    }

    private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            cameraDevice = camera;
            createCameraPreview();
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
            cameraDevice.close();
        }

        @Override
        public void onError(@NonNull CameraDevice camera, int error) {
            cameraDevice.close();
            cameraDevice = null;
            callback.onCameraError("Camera error: " + error);
        }
    };

    private void createCameraPreview() {
        try {
            SurfaceTexture texture = textureView.getSurfaceTexture();
            Surface surface = new Surface(texture);

            captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            captureRequestBuilder.addTarget(surface);

            cameraDevice.createCaptureSession(Arrays.asList(surface),
                    new CameraCaptureSession.StateCallback() {
                        @Override
                        public void onConfigured(@NonNull CameraCaptureSession session) {
                            if (cameraDevice == null) return;

                            cameraCaptureSession = session;
                            try {
                                captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                                        CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                                captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                                        CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);

                                session.setRepeatingRequest(captureRequestBuilder.build(),
                                        null, backgroundHandler);

                            } catch (CameraAccessException e) {
                                e.printStackTrace();
                            }
                        }

                        @Override
                        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                            callback.onCameraError("Camera configuration failed");
                        }
                    }, null);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void startFaceDetection() {
        detectionHandler = new Handler();
        detectionRunnable = new Runnable() {
            @Override
            public void run() {
                if (textureView.isAvailable()) {
                    Bitmap frameBitmap = textureView.getBitmap();
                    if (frameBitmap != null) {
                        realFaceDetector.detectFaces(frameBitmap);
                    }
                }
                detectionHandler.postDelayed(this, DETECTION_INTERVAL_MS);
            }
        };
        detectionHandler.postDelayed(detectionRunnable, DETECTION_INTERVAL_MS);
    }

    private void stopFaceDetection() {
        if (detectionHandler != null && detectionRunnable != null) {
            detectionHandler.removeCallbacks(detectionRunnable);
        }
        realFaceDetector.stop();
    }

    public void startBackgroundThread() {
        backgroundThread = new HandlerThread("CameraBackground");
        backgroundThread.start();
        backgroundHandler = new Handler(backgroundThread.getLooper());
    }

    public void stopBackgroundThread() {
        stopFaceDetection();
        if (backgroundThread != null) {
            backgroundThread.quitSafely();
            try {
                backgroundThread.join();
                backgroundThread = null;
                backgroundHandler = null;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void closeCamera() {
        stopFaceDetection();
        if (cameraCaptureSession != null) {
            cameraCaptureSession.close();
            cameraCaptureSession = null;
        }
        if (cameraDevice != null) {
            cameraDevice.close();
            cameraDevice = null;
        }
    }
}