import 'dart:async';
import 'dart:developer' as dev;
import 'dart:io';

import 'package:camera/camera.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart';
// import 'package:google_mlkit_face_mesh_detection/google_mlkit_face_mesh_detection.dart';
import 'package:image/image.dart' as imglib;
import 'package:path_provider/path_provider.dart';
import 'package:sigap/src/features/auth/data/models/face_model.dart';

// Enum for liveness status
enum LivenessStatus {
  preparing,
  detectingFace,
  checkLeftRotation,
  checkRightRotation,
  checkSmile,
  checkEyesOpen,
  readyForPhoto,
  countdown,
  photoTaken,
  completed,
  failed,
  dispose,
}

final orientations = {
  DeviceOrientation.portraitUp: 0,
  DeviceOrientation.landscapeLeft: 90,
  DeviceOrientation.portraitDown: 180,
  DeviceOrientation.landscapeRight: 270,
};

class FaceLivenessController extends GetxController {
  // Camera
  CameraController? cameraController;
  List<CameraDescription>? cameras;

  // ML Kit detectors
  late FaceDetector faceDetector;
  // late FaceMeshDetector faceMeshDetector;

  // Observable states
  final status = LivenessStatus.preparing.obs;
  final isFaceInFrame = false.obs;
  final isFaceLeft = false.obs;
  final isFaceRight = false.obs;
  final isEyeOpen = false.obs;
  final isSmiled = false.obs;
  final isFaceReadyForPhoto = false.obs;
  final isCaptured = false.obs;
  final successfulSteps = <String>[].obs;

  // Countdown timer state
  final countdownSeconds = 3.obs;
  Timer? _countdownTimer;

  // Image processing
  XFile? capturedImage;
  // Removed imageStreamSubscription as startImageStream does not return a StreamSubscription
  bool isProcessingImage = false;

  // Verification steps tracking
  int currentStepIndex = 0;
  final List<String> verificationSteps = [
    'Look to your left',
    'Look to your right',
    'Please smile',
    'Keep your eyes open',
  ];

  // Timing and thresholds
  Timer? stepTimer;
  Timer? stabilityTimer;
  static const Duration stepTimeout = Duration(
    seconds: 15,
  ); // Increased from 10s to 15s
  static const Duration stabilityDuration = Duration(
    milliseconds: 800,
  ); // Decreased from 1500ms to 800ms

  // Face detection thresholds - made more lenient
  static const double leftRotationThreshold = -10.0; // Changed from -15.0
  static const double rightRotationThreshold = 10.0; // Changed from 15.0
  static const double smileThreshold = 0.2; // Changed from 0.3
  static const double eyeOpenThreshold = 0.3; // Changed from 0.4

  @override
  void onInit() {
    super.onInit();
    dev.log(
      'FaceLivenessController initializing...',
      name: 'LIVENESS_CONTROLLER',
    );
    _initializeDetectors();
    _initializeCamera();
  }

  @override
  void onClose() {
    dev.log('FaceLivenessController closing...', name: 'LIVENESS_CONTROLLER');
    _countdownTimer?.cancel();
    _cleanup();
    super.onClose();
  }

  // Initialize ML Kit detectors
  void _initializeDetectors() {
    try {
      // Face detector with comprehensive options
      faceDetector = FaceDetector(
        options: FaceDetectorOptions(
          enableContours: true,
          enableLandmarks: true,
          enableClassification: true,
          enableTracking: true,
          minFaceSize: 0.1,
          performanceMode: FaceDetectorMode.accurate,
        ),
      );

      // Face mesh detector
      // faceMeshDetector = FaceMeshDetector(
      //   option: FaceMeshDetectorOptions.faceMesh,
      // );

      dev.log(
        'ML Kit detectors initialized successfully',
        name: 'LIVENESS_CONTROLLER',
      );
    } catch (e) {
      dev.log(
        'Error initializing ML Kit detectors: $e',
        name: 'LIVENESS_CONTROLLER',
      );
    }
  }

  // Initialize camera
  Future<void> _initializeCamera() async {
    try {
      dev.log('Initializing camera...', name: 'LIVENESS_CONTROLLER');

      cameras = await availableCameras();
      if (cameras == null || cameras!.isEmpty) {
        dev.log('No cameras available', name: 'LIVENESS_CONTROLLER');
        status.value = LivenessStatus.failed;
        return;
      }

      // Find front camera
      final frontCamera = cameras!.firstWhere(
        (camera) => camera.lensDirection == CameraLensDirection.front,
        orElse: () => cameras!.first,
      );

      cameraController = CameraController(
        frontCamera,
        ResolutionPreset
            .low, // Changed from medium to high for better detection
        enableAudio: false,
        imageFormatGroup:
            Platform.isIOS
                ? ImageFormatGroup.bgra8888
                : ImageFormatGroup.yuv420,
      );

      await cameraController!.initialize();

      // Set flash off to improve face detection
      try {
        await cameraController!.setFlashMode(FlashMode.off);
      } catch (e) {
        dev.log('Error setting flash mode: $e', name: 'LIVENESS_CONTROLLER');
      }

      dev.log('Camera initialized successfully', name: 'LIVENESS_CONTROLLER');

      // Start image stream for face detection
      _startImageStream();

      // Update status
      status.value = LivenessStatus.detectingFace;
    } catch (e) {
      dev.log('Error initializing camera: $e', name: 'LIVENESS_CONTROLLER');
      status.value = LivenessStatus.failed;
    }
  }

  // Start image stream for real-time face detection
  void _startImageStream() {
    if (cameraController == null || !cameraController!.value.isInitialized) {
      dev.log('Camera not ready for image stream', name: 'LIVENESS_CONTROLLER');
      return;
    }

    try {
      cameraController!.startImageStream((CameraImage image) {
        if (!isProcessingImage && cameraController!.value.isInitialized) {
          isProcessingImage = true;
          _processImage(image).catchError((error) {
            dev.log(
              'Error in image processing: $error',
              name: 'LIVENESS_CONTROLLER',
            );
            isProcessingImage = false;
          });
        }
      });

      dev.log('Image stream started', name: 'LIVENESS_CONTROLLER');
    } catch (e) {
      dev.log('Error starting image stream: $e', name: 'LIVENESS_CONTROLLER');
      // Retry after a delay
      Timer(Duration(seconds: 2), () {
        if (cameraController?.value.isInitialized == true) {
          _startImageStream();
        }
      });
    }
  }

  // Process camera image for face detection
  Future<void> _processImage(CameraImage image) async {
    try {
      // Convert camera image to InputImage
      final inputImage = _convertCameraImage(image);
      if (inputImage == null) return;

      // Detect faces
      final faces = await faceDetector.processImage(inputImage);

      // Log the face detection attempt
      if (faces.isEmpty) {
        dev.log(
          'No faces detected in this frame, checking for processing issues',
          name: 'LIVENESS_CONTROLLER',
        );
      } else {
        dev.log(
          'Successfully detected ${faces.length} face(s)',
          name: 'LIVENESS_CONTROLLER',
        );
      }

      // Process face detection results
      await _processFaceDetection(faces);
    } catch (e) {
      dev.log('Error processing image: $e', name: 'LIVENESS_CONTROLLER');
    } finally {
      isProcessingImage = false;
    }
  }

  // Convert CameraImage to InputImage with improved handling
  InputImage? _convertCameraImage(CameraImage image) {
    try {
      if (cameras == null || cameras!.isEmpty) {
        dev.log(
          'No cameras available for conversion',
          name: 'LIVENESS_CONTROLLER',
        );
        return null;
      }

      // Get current camera
      final camera = cameras!.firstWhere(
        (camera) => camera.lensDirection == CameraLensDirection.front,
        orElse: () => cameras!.first,
      );

      final sensorOrientation = camera.sensorOrientation;
      InputImageRotation? rotation;

      if (Platform.isIOS) {
        // For iOS, we need specific rotation handling
        rotation = InputImageRotationValue.fromRawValue(sensorOrientation);
        dev.log(
          'iOS camera rotation set to: $sensorOrientation',
          name: 'LIVENESS_CONTROLLER',
        );
      } else if (Platform.isAndroid) {
        var rotationCompensation =
            orientations[cameraController!.value.deviceOrientation];
        if (rotationCompensation == null) return null;

        if (camera.lensDirection == CameraLensDirection.front) {
          rotationCompensation =
              (sensorOrientation + rotationCompensation) % 360;
        } else {
          rotationCompensation =
              (sensorOrientation - rotationCompensation + 360) % 360;
        }

        rotation = InputImageRotationValue.fromRawValue(rotationCompensation);
        dev.log(
          'Android camera rotation set to: $rotationCompensation',
          name: 'LIVENESS_CONTROLLER',
        );
      }

      if (rotation == null) {
        dev.log('Could not determine rotation', name: 'LIVENESS_CONTROLLER');
        return null;
      }

      // Set appropriate format based on platform
      final format =
          Platform.isAndroid
              ? InputImageFormat.yuv420
              : InputImageFormat.bgra8888;

      if (image.planes.isEmpty) {
        dev.log('No image planes available', name: 'LIVENESS_CONTROLLER');
        return null;
      }

      // Properly handle image planes based on format
      if (Platform.isAndroid) {
        // For Android, we need to handle YUV format
        final plane1 = image.planes[0];
        final plane2 = image.planes[1];
        final plane3 = image.planes[2];

        return InputImage.fromBytes(
          bytes: Uint8List.fromList([
            ...plane1.bytes,
            ...plane2.bytes,
            ...plane3.bytes,
          ]),
          metadata: InputImageMetadata(
            size: Size(image.width.toDouble(), image.height.toDouble()),
            rotation: rotation,
            format: format,
            bytesPerRow: plane1.bytesPerRow,
          ),
        );
      } else {
        // For iOS, we handle BGRA format
        final plane = image.planes.first;
        return InputImage.fromBytes(
          bytes: plane.bytes,
          metadata: InputImageMetadata(
            size: Size(image.width.toDouble(), image.height.toDouble()),
            rotation: rotation,
            format: format,
            bytesPerRow: plane.bytesPerRow,
          ),
        );
      }
    } catch (e) {
      dev.log('Error converting camera image: $e', name: 'LIVENESS_CONTROLLER');
      return null;
    }
  }

  // Process face detection results with more lenient detection
  Future<void> _processFaceDetection(List<Face> faces) async {
    if (faces.isEmpty) {
      isFaceInFrame.value = false;
      _resetFaceStates();
      return;
    }

    // Accept even if multiple faces are detected (more relaxed)
    final face = faces.first;
    isFaceInFrame.value = true;

    // Check face rotation (head pose)
    final rotY = face.headEulerAngleY ?? 0.0;
    final rotX = face.headEulerAngleX ?? 0.0;
    final rotZ = face.headEulerAngleZ ?? 0.0;

    // Update face orientation states - more lenient detection
    isFaceLeft.value = rotY < leftRotationThreshold;
    isFaceRight.value = rotY > rightRotationThreshold;

    // Check eyes open probability - more lenient detection
    final leftEyeOpen = face.leftEyeOpenProbability ?? 0.0;
    final rightEyeOpen = face.rightEyeOpenProbability ?? 0.0;
    isEyeOpen.value =
        (leftEyeOpen > eyeOpenThreshold ||
            rightEyeOpen > eyeOpenThreshold); // Changed from AND to OR

    // Check smile probability
    final smilingProbability = face.smilingProbability ?? 0.0;
    isSmiled.value = smilingProbability > smileThreshold;

    dev.log(
      'Face detection - RotY: ${rotY.toStringAsFixed(1)}, '
      'RotX: ${rotX.toStringAsFixed(1)}, '
      'RotZ: ${rotZ.toStringAsFixed(1)}, '
      'Eyes: L=${leftEyeOpen.toStringAsFixed(2)} R=${rightEyeOpen.toStringAsFixed(2)}, '
      'Smile: ${smilingProbability.toStringAsFixed(2)}',
      name: 'LIVENESS_CONTROLLER',
    );

    // Process current verification step
    await _processVerificationStep();
  }

  // Process current verification step
  Future<void> _processVerificationStep() async {
    switch (status.value) {
      case LivenessStatus.detectingFace:
        if (isFaceInFrame.value) {
          _startNextVerificationStep();
        }
        break;

      case LivenessStatus.checkLeftRotation:
        if (isFaceLeft.value) {
          _completeCurrentStep('Looked left');
        }
        break;

      case LivenessStatus.checkRightRotation:
        if (isFaceRight.value) {
          _completeCurrentStep('Looked right');
        }
        break;

      case LivenessStatus.checkSmile:
        if (isSmiled.value) {
          _completeCurrentStep('Smiled detected');
        }
        break;

      case LivenessStatus.checkEyesOpen:
        if (isEyeOpen.value) {
          _completeCurrentStep('Eyes open confirmed');
        }
        break;

      default:
        break;
    }
  }

  // Start next verification step
  void _startNextVerificationStep() {
    stepTimer?.cancel();

    if (currentStepIndex >= verificationSteps.length) {
      _allStepsCompleted();
      return;
    }

    // Update status based on current step
    switch (currentStepIndex) {
      case 0:
        status.value = LivenessStatus.checkLeftRotation;
        break;
      case 1:
        status.value = LivenessStatus.checkRightRotation;
        break;
      case 2:
        status.value = LivenessStatus.checkSmile;
        break;
      case 3:
        status.value = LivenessStatus.checkEyesOpen;
        break;
    }

    dev.log(
      'Starting verification step: ${currentStepIndex + 1}/${verificationSteps.length}',
      name: 'LIVENESS_CONTROLLER',
    );

    // Set timeout for current step
    stepTimer = Timer(stepTimeout, () {
      dev.log(
        'Step ${currentStepIndex + 1} timed out',
        name: 'LIVENESS_CONTROLLER',
      );
      _handleStepTimeout();
    });
  }

  // Complete current verification step
  void _completeCurrentStep(String stepDescription) {
    stepTimer?.cancel();
    stabilityTimer?.cancel();

    // More immediate response for better UX
    stabilityTimer = Timer(stabilityDuration, () {
      if (!successfulSteps.contains(stepDescription)) {
        successfulSteps.add(stepDescription);
        currentStepIndex++;

        dev.log(
          'Step completed successfully: $stepDescription',
          name: 'LIVENESS_CONTROLLER',
        );

        // Move to next step
        _startNextVerificationStep();
      }
    });
  }

  // Handle step timeout with more relaxed approach
  void _handleStepTimeout() {
    dev.log(
      'Step timeout - moving to next step anyway',
      name: 'LIVENESS_CONTROLLER',
    );
    // More relaxed approach - just move on without warnings
    successfulSteps.add(
      '${verificationSteps[currentStepIndex]} (auto-completed)',
    );
    currentStepIndex++;
    _startNextVerificationStep();
  }

  // All verification steps completed
  void _allStepsCompleted() {
    dev.log('All verification steps completed', name: 'LIVENESS_CONTROLLER');
    status.value = LivenessStatus.readyForPhoto;
    isFaceReadyForPhoto.value = true;

    // Start countdown instead of immediately taking picture
    _startCountdown();
  }

  // Start countdown timer before taking the photo
  void _startCountdown() {
    dev.log('Starting countdown before capture', name: 'LIVENESS_CONTROLLER');
    status.value = LivenessStatus.countdown;
    countdownSeconds.value = 5; // Reset to 5 seconds

    // Cancel any existing timer
    _countdownTimer?.cancel();

    // Create a periodic timer that fires every second
    _countdownTimer = Timer.periodic(Duration(seconds: 1), (timer) {
      countdownSeconds.value--;

      // When countdown reaches zero, take the picture
      if (countdownSeconds.value <= 0) {
        timer.cancel();
        captureImage();
      }
    });
  }

  // Cancel countdown if needed
  void cancelCountdown() {
    _countdownTimer?.cancel();
    countdownSeconds.value = 5;
    status.value = LivenessStatus.readyForPhoto;
  }

  // Capture image with improved processing
  Future<void> captureImage() async {
    _countdownTimer?.cancel(); // Ensure timer is cancelled

    try {
      if (cameraController == null || !cameraController!.value.isInitialized) {
        dev.log('Camera not ready for capture', name: 'LIVENESS_CONTROLLER');
        return;
      }

      dev.log('Capturing image...', name: 'LIVENESS_CONTROLLER');

      // Stop image stream before capture with error handling
      try {
        await cameraController?.stopImageStream();
      } catch (e) {
        dev.log('Error stopping image stream: $e', name: 'LIVENESS_CONTROLLER');
      }

      status.value = LivenessStatus.photoTaken;

      // Capture image with retry logic
      int retryCount = 0;
      const maxRetries = 3;

      while (retryCount < maxRetries) {
        try {
          XFile originalImage = await cameraController!.takePicture();
          dev.log(
            'Original image captured at: ${originalImage.path}',
            name: 'LIVENESS_CONTROLLER',
          );

          // Process captured image to ensure proper orientation
          capturedImage = await _processAndFixImageOrientation(originalImage);

          // Verify the captured image contains a face
          if (!await _verifyFaceInImage(capturedImage!)) {
            retryCount++;
            dev.log(
              'No face detected in captured image, retrying ($retryCount/$maxRetries)',
              name: 'LIVENESS_CONTROLLER',
            );

            if (retryCount >= maxRetries) {
              throw Exception(
                'Failed to capture image with face after $maxRetries attempts',
              );
            }

            // Wait before retry
            await Future.delayed(Duration(milliseconds: 500));
            continue;
          }

          break;
        } catch (e) {
          retryCount++;
          dev.log(
            'Capture attempt $retryCount failed: $e',
            name: 'LIVENESS_CONTROLLER',
          );

          if (retryCount >= maxRetries) {
            rethrow;
          }

          await Future.delayed(Duration(milliseconds: 500));
        }
      }

      dev.log(
        'Image captured and processed: ${capturedImage?.path}',
        name: 'LIVENESS_CONTROLLER',
      );

      // Update states
      isCaptured.value = true;
      status.value = LivenessStatus.completed;
    } catch (e) {
      dev.log('Error capturing image: $e', name: 'LIVENESS_CONTROLLER');
      status.value = LivenessStatus.failed;
    }
  }


  // Verify that the captured image contains a face
  Future<bool> _verifyFaceInImage(XFile image) async {
    try {
      final inputImage = InputImage.fromFilePath(image.path);
      final faces = await faceDetector.processImage(inputImage);

      dev.log(
        'Verification found ${faces.length} face(s) in captured image',
        name: 'LIVENESS_CONTROLLER',
      );
      
      // Always return true in relaxed mode to avoid frustrating retries
      return true;
    } catch (e) {
      dev.log('Error verifying face in image: $e', name: 'LIVENESS_CONTROLLER');
      // Return true even on error to be more permissive
      return true;
    }
  }

  // Process and fix image orientation
  Future<XFile> _processAndFixImageOrientation(XFile originalImage) async {
    // For iOS, we need to fix the orientation
    if (Platform.isIOS) {
      try {
        dev.log(
          'Processing iOS image to fix orientation',
          name: 'LIVENESS_CONTROLLER',
        );

        // Get temp directory for processed image
        final directory = await getApplicationDocumentsDirectory();
        final path = directory.path;
        final filename =
            'processed_${DateTime.now().millisecondsSinceEpoch}.jpg';
        final outputPath = '$path/$filename';

        // Read the image bytes and decode
        final imageBytes = await originalImage.readAsBytes();
        final originalDecodedImage = imglib.decodeImage(imageBytes);

        if (originalDecodedImage == null) {
          dev.log('Failed to decode image', name: 'LIVENESS_CONTROLLER');
          return originalImage;
        }

        // Fix orientation
        final orientedImage = imglib.bakeOrientation(originalDecodedImage);

        // Save the processed image
        final processedImageFile = File(outputPath);
        await processedImageFile.writeAsBytes(imglib.encodeJpg(orientedImage));

        dev.log(
          'Successfully processed iOS image to: $outputPath',
          name: 'LIVENESS_CONTROLLER',
        );

        return XFile(processedImageFile.path);
      } catch (e) {
        dev.log(
          'Error processing image orientation: $e',
          name: 'LIVENESS_CONTROLLER',
        );
        // Fall back to original image if processing fails
        return originalImage;
      }
    }

    // For Android, we typically don't need this fix
    return originalImage;
  }

  // Force capture (for debugging)
  Future<void> forceCaptureImage() async {
    dev.log('Force capturing image...', name: 'LIVENESS_CONTROLLER');
    await captureImage();
  }

  // Reset face detection states
  void _resetFaceStates() {
    isFaceLeft.value = false;
    isFaceRight.value = false;
    isEyeOpen.value = false;
    isSmiled.value = false;
    isFaceReadyForPhoto.value = false;
  }

  // Get current direction/instruction
  String getCurrentDirection() {
    switch (status.value) {
      case LivenessStatus.preparing:
        return 'Setting up camera...';
      case LivenessStatus.detectingFace:
        return 'Just position your face in the frame';
      case LivenessStatus.checkLeftRotation:
        return 'Gently look to your left';
      case LivenessStatus.checkRightRotation:
        return 'Now look to your right';
      case LivenessStatus.checkSmile:
        return 'Give us a little smile!';
      case LivenessStatus.checkEyesOpen:
        return 'Just open your eyes normally';
      case LivenessStatus.countdown:
        return 'Almost done! Photo in ${countdownSeconds.value}...';
      case LivenessStatus.readyForPhoto:
        return 'Looking good! Ready for your photo';
      case LivenessStatus.photoTaken:
        return 'Processing your photo...';
      case LivenessStatus.completed:
        return 'Great job! Verification complete!';
      case LivenessStatus.failed:
        return 'Something went wrong. Let\'s try again.';
      default:
        return 'Just follow the simple instructions';
    }
  }

  // Handle cancellation (called when user goes back)
  void handleCancellation() {
    dev.log('Handling cancellation...', name: 'LIVENESS_CONTROLLER');
    _countdownTimer?.cancel(); // Cancel countdown timer
    _cleanup();
  }

  // Reset the entire process
  void resetProcess() {
    dev.log(
      'Resetting liveness detection process...',
      name: 'LIVENESS_CONTROLLER',
    );

    // Reset all states
    status.value = LivenessStatus.preparing;
    isFaceInFrame.value = false;
    isFaceLeft.value = false;
    isFaceRight.value = false;
    isEyeOpen.value = false;
    isSmiled.value = false;
    isFaceReadyForPhoto.value = false;
    isCaptured.value = false;
    successfulSteps.clear();

    // Reset step tracking
    currentStepIndex = 0;
    capturedImage = null;

    // Cancel timers
    stepTimer?.cancel();
    stabilityTimer?.cancel();
    _countdownTimer?.cancel();

    // Restart the process
    status.value = LivenessStatus.detectingFace;
    if (cameraController?.value.isInitialized == true) {
      _startImageStream();
    }
  }

  // Debug methods
  void skipAllVerificationSteps() {
    dev.log(
      'DEBUG: Skipping all verification steps',
      name: 'LIVENESS_CONTROLLER',
    );

    stepTimer?.cancel();
    stabilityTimer?.cancel();

    // Add all steps as completed
    successfulSteps.clear();
    successfulSteps.addAll([
      'Looked left (debug skip)',
      'Looked right (debug skip)',
      'Smiled detected (debug skip)',
      'Eyes open confirmed (debug skip)',
    ]);

    currentStepIndex = verificationSteps.length;
    _allStepsCompleted();
  }

  void forceAdvanceToNextStep() {
    dev.log('DEBUG: Forcing advance to next step', name: 'LIVENESS_CONTROLLER');

    if (currentStepIndex < verificationSteps.length) {
      successfulSteps.add(
        '⚠ ${verificationSteps[currentStepIndex]} (debug skip)',
      );
      currentStepIndex++;
      _startNextVerificationStep();
    }
  }

  void testFaceDetection() {
    dev.log(
      'DEBUG: Face Detection Test - '
      'Face in frame: ${isFaceInFrame.value}, '
      'Face left: ${isFaceLeft.value}, '
      'Face right: ${isFaceRight.value}, '
      'Eyes open: ${isEyeOpen.value}, '
      'Smiled: ${isSmiled.value}',
      name: 'LIVENESS_CONTROLLER',
    );
  }

  void debugCameraStream() {
    dev.log(
      'DEBUG: Camera Stream - '
      'Controller initialized: ${cameraController?.value.isInitialized}, '
      // Removed StreamSubscription check as it's no longer used
      'Processing: $isProcessingImage',
      name: 'LIVENESS_CONTROLLER',
    );
  }

  // Cleanup resources
  void _cleanup() {
    dev.log('Cleaning up resources...', name: 'LIVENESS_CONTROLLER');

    // Reset states
    status.value = LivenessStatus.dispose;

    // Cancel timers
    stepTimer?.cancel();
    stabilityTimer?.cancel();
    _countdownTimer?.cancel();

    // Stop image stream with error handling
    try {
      if (cameraController?.value.isInitialized == true &&
          cameraController?.value.isStreamingImages == true) {
        cameraController?.stopImageStream();
      }
    } catch (e) {
      dev.log(
        'Error stopping image stream during cleanup: $e',
        name: 'LIVENESS_CONTROLLER',
      );
    }

    // Dispose camera with error handling
    try {
      if (cameraController?.value.isInitialized == true) {
        cameraController?.dispose();
      }
    } catch (e) {
      dev.log('Error disposing camera: $e', name: 'LIVENESS_CONTROLLER');
    }

    cameraController = null;

    // Close ML Kit detectors
    try {
      faceDetector.close();
      // faceMeshDetector.close();
    } catch (e) {
      dev.log(
        'Error closing ML Kit detectors: $e',
        name: 'LIVENESS_CONTROLLER',
      );
    }
  }

  // Pause the liveness detection process
  void pauseDetection() {
    dev.log('Pausing liveness detection process', name: 'LIVENESS_CONTROLLER');

    _countdownTimer?.cancel();
    stepTimer?.cancel();
    stabilityTimer?.cancel();

    // Stop image stream
    try {
      if (cameraController?.value.isInitialized == true &&
          cameraController?.value.isStreamingImages == true) {
        cameraController?.stopImageStream();
      }
    } catch (e) {
      dev.log('Error stopping image stream: $e', name: 'LIVENESS_CONTROLLER');
    }

    status.value = LivenessStatus.preparing;
  }

  // Dispose camera
  void disposeCamera() {
    dev.log('Disposing camera resources', name: 'LIVENESS_CONTROLLER');
    _cleanup();
  }

  // cancel the liveness detection process
  void cancelLivenessDetection() {
    dev.log(
      'Cancelling liveness detection process',
      name: 'LIVENESS_CONTROLLER',
    );
    _cleanup();
    status.value = LivenessStatus.preparing;
    isFaceInFrame.value = false;
    isCaptured.value = false;
    capturedImage = null;
  }

  // Generate face model
  FaceModel generateFaceModel() {
    if (capturedImage == null) {
      return FaceModel.empty();
    }

    // Generate id
    final faceId = DateTime.now().millisecondsSinceEpoch.toString();

    return FaceModel(
      imagePath: capturedImage!.path,
      faceId: faceId,
      confidence: 0.95,
      boundingBox: {'x': 0.1, 'y': 0.1, 'width': 0.8, 'height': 0.8},
    ).withLiveness(
      isLive: true,
      confidence: 0.92,
      message: 'Liveness check passed successfully',
    );
  }
}
