import 'dart:developer' as dev;
import 'dart:io';
import 'dart:math';
import 'dart:ui' as ui;

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart';
import 'package:logger/logger.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sigap/src/cores/services/edge_function_service.dart';
import 'package:sigap/src/features/auth/data/models/face_model.dart';
import 'package:sigap/src/features/auth/presentasion/controllers/signup/step/id-card-verification/id_card_verification_controller.dart';
import 'package:sigap/src/features/auth/presentasion/controllers/signup/step/selfie-verification/face_liveness_detection_controller.dart';
import 'package:sigap/src/features/auth/presentasion/controllers/signup/step/selfie-verification/facial_verification_controller.dart';
import 'package:sigap/src/utils/constants/app_routes.dart';

class SelfieVerificationController extends GetxController {
  // Image picker instance
  final _imagePicker = ImagePicker();

  // Edge function service for face comparison
  final _edgeFunctionService = EdgeFunctionService.instance;

  // Main controller reference
  IdCardVerificationController? idCardController;

  // States
  final selfieImage = Rx<XFile?>(null);
  final isVerifyingFace = false.obs;
  final isSelfieValid = false.obs;
  final selfieError = RxString('');
  final isUploadingSelfie = false.obs;
  final hasConfirmedSelfie = false.obs;

  // Liveness detection states
  final isPerformingLivenessCheck = false.obs;
  final isLivenessCheckPassed = false.obs;

  // New flag for auto starting verification
  bool autoStartVerification = false;

  // Face comparison results
  final isComparingWithIDCard = false.obs;
  final isMatchWithIDCard = false.obs;
  final matchConfidence = 0.0.obs;
  final Rx<FaceComparisonResult?> faceComparisonResult =
      Rx<FaceComparisonResult?>(null);

  // Development mode options
  final RxBool bypassLivenessCheck = RxBool(false);
  final RxBool autoVerifyForDev = RxBool(false);
  
  // Added a flag to prevent multiple image picker attempts
  bool _isImagePickerActive = false;

  // Added counter to track auto-verify attempts
  int _autoVerifyAttempts = 0;

  // Add a GlobalKey for rendering a widget to an image (for dev mode)
  final GlobalKey _previewContainer = GlobalKey();

  // Constructor
  SelfieVerificationController({this.idCardController});

  @override
  void onInit() {
    super.onInit();

    // Check if we should auto-verify immediately on initialization
    final facialVerificationService = FacialVerificationService.instance;
    if (facialVerificationService.skipFaceVerification) {
      // Read the stored preference for auto-verify if available
      // This could be replaced with your app's preference storage mechanism
      autoVerifyForDev.value =
          false; // Default to false, can be loaded from storage
      bypassLivenessCheck.value =
          false; // Default to false, can be loaded from storage
    }

    // Check if we need to enable auto-verify from arguments
    final dynamic args = Get.arguments;
    if (args != null && args is Map<String, dynamic>) {
      if (args.containsKey('autoVerify') && args['autoVerify'] as bool) {
        autoVerifyForDev.value = true;
        bypassLivenessCheck.value = true;
        Logger().i('Auto-verify enabled from arguments');

        // Auto-complete verification after a short delay
        Future.delayed(const Duration(milliseconds: 500), () {
          autoCompleteVerification();
        });
      }

      if (args.containsKey('bypassLiveness') &&
          args['bypassLiveness'] as bool) {
        bypassLivenessCheck.value = true;
        Logger().i('Bypass liveness enabled from arguments');
      }
    }

    // Don't access other controllers during initialization
    // Defer any cross-controller communication until after initialization
    Future.microtask(() {
      _initializeAfterDependencies();
    });

    // Add listeners to the dev mode flags to reset state when turned off
    ever(bypassLivenessCheck, _handleDevModeChange);
    ever(autoVerifyForDev, _handleDevModeChange);
  }

  // New method to handle changes in dev mode settings
  void _handleDevModeChange(bool isEnabled) {
    if (!isEnabled) {
      // If dev mode is turned off, reset to initial state
      Logger().i('Dev mode disabled, resetting state to initial');
      _resetToInitialState();
    }
  }

  // New method to reset everything to initial state when dev mode is turned off
  void _resetToInitialState() {
    // Reset all states to initial values
    clearSelfieImage();
    resetVerificationState();
    _autoVerifyAttempts = 0;
    _isImagePickerActive = false;

    // Clean up any temporary image files
    _cleanupTemporaryFiles();
  }

  // Method to clean up any temporary image files
  Future<void> _cleanupTemporaryFiles() async {
    try {
      if (selfieImage.value != null &&
          File(selfieImage.value!.path).existsSync()) {
        // Delete the actual file from storage
        await File(selfieImage.value!.path).delete();
        Logger().i('Temporary selfie image file deleted');
      }
    } catch (e) {
      Logger().e('Error cleaning up temporary files: $e');
    }
  }

  void _initializeAfterDependencies() {
    // Listen for changes to selfieImage with improved null safety
    ever(selfieImage, (XFile? image) {
      dev.log(
        'Selfie image changed: ${image?.path}',
        name: 'SELFIE_VERIFICATION',
      );

      if (image != null && autoStartVerification) {
        // When returning from liveness check with a selfie,
        // immediately start verification with a delay for UI to update
        autoStartVerification = false; // Reset flag

        Future.delayed(Duration(milliseconds: 500), () {
          startFaceVerification();
        });
      }
    });
  }

  // Add public method to start verification process with better error handling
  void startFaceVerification() {
    if (selfieImage.value == null) {
      dev.log(
        'Cannot start verification - no selfie image!',
        name: 'SELFIE_VERIFICATION',
      );
      selfieError.value = 'No selfie image available for verification';
      return;
    }

    if (isVerifyingFace.value || isComparingWithIDCard.value) {
      dev.log('Verification already in progress', name: 'SELFIE_VERIFICATION');
      return;
    }

    dev.log(
      'Starting face verification with image: ${selfieImage.value!.path}',
      name: 'SELFIE_VERIFICATION',
    );

    _processCapturedLivenessImage();
  }

  // Enhanced version of the method to perform liveness detection
  void performLivenessDetection() async {
    try {
      // Clear any existing verification data first
      clearSelfieImage();
      resetVerificationState();
      
      isPerformingLivenessCheck.value = true;
      autoStartVerification = true; // Set flag for auto verification

      // Check if FaceLivenessController is already registered
      final bool hasExistingController =
          Get.isRegistered<FaceLivenessController>();

      // Clear existing controller if it exists to ensure fresh state
      if (hasExistingController) {
        final existingController = Get.find<FaceLivenessController>();
        existingController.handleCancellation();
        await Get.delete<FaceLivenessController>();
      }

      // Navigate to liveness detection page and wait for result
      await Get.toNamed(
        AppRoutes.livenessDetection,
        preventDuplicates: false, // Allow navigation to same route if needed
      );

      // When returning here, the image should already be set by CapturedSelfieView
      // and automatic verification should be triggered by the listener in onInit

      // Reset liveness check flag since we're back
      isPerformingLivenessCheck.value = false;
    } catch (e) {
      dev.log('Error in liveness detection: $e', name: 'SELFIE_VERIFICATION');
      isPerformingLivenessCheck.value = false;
      isLivenessCheckPassed.value = false;
      selfieError.value = 'Liveness check failed: $e';
      autoStartVerification = false; // Reset flag on error
    }
  }

  // Process the captured image after liveness check with better error handling
  Future<void> _processCapturedLivenessImage() async {
    try {
      if (selfieImage.value == null) {
        dev.log('No selfie image to process', name: 'SELFIE_VERIFICATION');
        selfieError.value = 'Missing selfie image. Please try again.';
        return;
      }

      final imagePath = selfieImage.value!.path;
      if (!File(imagePath).existsSync()) {
        dev.log(
          'Selfie image file does not exist: $imagePath',
          name: 'SELFIE_VERIFICATION',
        );
        selfieError.value = 'Selfie image file not found. Please try again.';
        return;
      }

      isVerifyingFace.value = true;
      selfieError.value = '';

      dev.log(
        'Processing captured image for verification: $imagePath',
        name: 'SELFIE_VERIFICATION',
      );

      // Now verify that the selfie contains a valid face
      // Use a try-catch specifically for the face detection call
      try {
        final faces = await _edgeFunctionService.detectFaces(
          selfieImage.value!,
        );

        if (faces.isEmpty) {
          selfieError.value = 'No face detected in your selfie';
          isVerifyingFace.value = false;
          isSelfieValid.value = false;
          return;
        }

        // Face detected successfully
        isSelfieValid.value = true;
        isVerifyingFace.value = false;

        // Now compare with ID card if available
        await _compareWithIdCard();
      } catch (e) {
        dev.log('Face detection API error: $e', name: 'SELFIE_VERIFICATION');
        selfieError.value = 'Error detecting face: Please try again.';
        isVerifyingFace.value = false;
        isSelfieValid.value = false;
      }
    } catch (e) {
      dev.log('Error processing selfie: $e', name: 'SELFIE_VERIFICATION');
      selfieError.value = 'Error processing selfie: $e';
      isVerifyingFace.value = false;
      isSelfieValid.value = false;
    } finally {
      isPerformingLivenessCheck.value = false;
    }
  }

  // Compare selfie with ID card with better null handling
  Future<void> _compareWithIdCard() async {
    if (selfieImage.value == null) {
      dev.log(
        'No selfie image available for comparison',
        name: 'SELFIE_VERIFICATION',
      );
      selfieError.value = 'Missing selfie image for ID comparison';
      return;
    }

    // Find controller if it exists, with better error handling
    if (idCardController == null) {
      try {
        // Try to get the controller if it's registered
        if (Get.isRegistered<IdCardVerificationController>()) {
          idCardController = Get.find<IdCardVerificationController>();
        } else {
          dev.log(
            'ID card controller not found, cannot compare faces',
            name: 'SELFIE_VERIFICATION',
          );
          selfieError.value = 'ID card data not available for comparison';
          return;
        }
      } catch (e) {
        dev.log(
          'Error getting ID card controller: $e',
          name: 'SELFIE_VERIFICATION',
        );
        selfieError.value = 'ID card data not available for comparison';
        return;
      }
    }

    // Check if ID card image exists
    if (idCardController!.idCardImage.value == null) {
      dev.log(
        'No ID card image available for comparison',
        name: 'SELFIE_VERIFICATION',
      );
      selfieError.value = 'No ID card image available for comparison';
      return;
    }

    XFile idCardImage = idCardController!.idCardImage.value!;

    // Verify both image files exist
    if (!File(idCardImage.path).existsSync()) {
      dev.log(
        'ID card image file does not exist: ${idCardImage.path}',
        name: 'SELFIE_VERIFICATION',
      );
      selfieError.value = 'ID card image file not found';
      return;
    }

    if (!File(selfieImage.value!.path).existsSync()) {
      dev.log(
        'Selfie image file does not exist: ${selfieImage.value!.path}',
        name: 'SELFIE_VERIFICATION',
      );
      selfieError.value = 'Selfie image file not found';
      return;
    }

    try {
      isComparingWithIDCard.value = true;

      // Compare faces using edge function
      final result = await _edgeFunctionService.compareFaces(
        idCardImage,
        selfieImage.value!,
        similarityThreshold: 70.0, // Use 70% as default threshold
      );

      // Update comparison results
      faceComparisonResult.value = result;
      isMatchWithIDCard.value = result.isMatch;
      matchConfidence.value = result.confidence;

      dev.log(
        'Face comparison complete: Match=${result.isMatch}, '
        'Confidence=${(result.confidence * 100).toStringAsFixed(1)}%, '
        'Message=${result.message}',
        name: 'SELFIE_VERIFICATION',
      );

      if (!result.isMatch) {
        selfieError.value = result.message;
      }
    } catch (e) {
      dev.log('Error comparing faces: $e', name: 'SELFIE_VERIFICATION');
      selfieError.value = 'Error comparing with ID card: $e';
      isMatchWithIDCard.value = false;
      matchConfidence.value = 0.0;
    } finally {
      isComparingWithIDCard.value = false;
    }
  }

  // Clear selfie image - Enhanced to ensure proper cleanup
  void clearSelfieImage() {
    try {
      // Delete any existing image file
      if (selfieImage.value != null) {
        final imagePath = selfieImage.value!.path;
        try {
          if (File(imagePath).existsSync()) {
            File(imagePath).deleteSync();
            Logger().i('Deleted selfie image file: $imagePath');
          }
        } catch (e) {
          Logger().e('Error deleting selfie image file: $e');
        }
      }
    } finally {
      // Always reset the state values
      selfieImage.value = null;
      isSelfieValid.value = false;
      hasConfirmedSelfie.value = false;
      selfieError.value = '';
    }
  }

  // Confirm the selfie
  void confirmSelfieImage() {
    if (selfieImage.value != null && isSelfieValid.value) {
      hasConfirmedSelfie.value = true;

      // If we have a main controller, update its state
      if (idCardController != null) {
        idCardController!.hasConfirmedIdCard.value = true;
      }
    }
  }

  void clearErrors() {
    selfieError.value = '';
  }

  // Reset verification state - update to make it more thorough
  void resetVerificationState() {
    // Reset all related state variables to initial values
    isVerifyingFace.value = false;
    isComparingWithIDCard.value = false;
    isMatchWithIDCard.value = false;
    matchConfidence.value = 0.0;
    faceComparisonResult.value = null;
    isLivenessCheckPassed.value = false;
    isPerformingLivenessCheck.value = false;
    isUploadingSelfie.value = false;
    hasConfirmedSelfie.value = false;
    autoStartVerification = false;
    selfieError.value = '';
    isSelfieValid.value = false;

    // Ensure the image is fully reset as well
    if (selfieImage.value != null) {
      clearSelfieImage();
    }
  }
  
  // Auto-complete verification for development purposes
  Future<void> autoCompleteVerification() async {
    try {
      // Clear existing data first to ensure fresh state
      clearSelfieImage();
      resetVerificationState();
      
      // Prevent multiple simultaneous attempts
      if (_isImagePickerActive) {
        Logger().w(
          'DEV MODE: Image picker already active, skipping auto-verification',
        );
        return;
      }
      
      // Check if we've tried too many times
      if (_autoVerifyAttempts > 2) {
        Logger().w('DEV MODE: Too many auto-verify attempts, using fallback');
        await _simulateVerificationWithoutImage();
        return;
      }
      
      _autoVerifyAttempts++;
      _isImagePickerActive = true;
      
      final logger = Logger();
      logger.i(
        'DEV MODE: Auto-completing verification (attempt $_autoVerifyAttempts)',
      );

      // Clear previous states
      clearSelfieImage();
      resetVerificationState();

      // Set loading states to show progress
      isPerformingLivenessCheck.value = true;

      // Create a temporary file using our improved method
      final tempFile = await _createDevModeImageFile();

      if (tempFile != null) {
        // Set the selfie image
        selfieImage.value = XFile(tempFile.path);

        // Wait a bit to simulate processing
        await Future.delayed(const Duration(milliseconds: 500));
        isPerformingLivenessCheck.value = false;
        isLivenessCheckPassed.value = true;

        // Simulate face verification
        isVerifyingFace.value = true;
        await Future.delayed(const Duration(milliseconds: 500));
        isVerifyingFace.value = false;
        isSelfieValid.value = true;

        // Simulate comparison with ID
        isComparingWithIDCard.value = true;
        await Future.delayed(const Duration(milliseconds: 500));
        isComparingWithIDCard.value = false;

        // Set to successful result
        final confidence = 0.98; // Very high confidence for auto-verification
        matchConfidence.value = confidence;
        isMatchWithIDCard.value = true;

        // Set face comparison result
        faceComparisonResult.value = FaceComparisonResult(
          sourceFace: FaceModel(
            imagePath: selfieImage.value?.path ?? '',
            faceId: 'selfie_face_id',
          ),
          targetFace: FaceModel(
            imagePath: idCardController?.idCardImage.value?.path ?? '',
            faceId: 'idcard_face_id',
          ),
          isMatch: true,
          confidence: confidence,
          message: 'DEV MODE: Auto-verified successfully',
        );

        // Auto-confirm
        await Future.delayed(const Duration(milliseconds: 500));
        hasConfirmedSelfie.value = true;

        logger.i('DEV MODE: Auto-verification completed successfully');
      } else {
        // If we couldn't create an image file, simulate verification without an image
        logger.w(
          'DEV MODE: Failed to create temporary image file, using fallback',
        );
        await _simulateVerificationWithoutImage();
      }
    } catch (e) {
      Logger().e('DEV MODE: Error in auto-verification: $e');
      selfieError.value = 'Error in auto-verification';
      isPerformingLivenessCheck.value = false;
      
      // Try the fallback approach if we had an error
      if (_autoVerifyAttempts <= 3) {
        Logger().w('DEV MODE: Auto-verify error, attempting fallback');
        await _simulateVerificationWithoutImage();
      }
    } finally {
      _isImagePickerActive = false;
    }
  }

  // New method to simulate verification without needing a real image file
  Future<void> _simulateVerificationWithoutImage() async {
    try {
      // Reset all states first
      clearErrors();
      isPerformingLivenessCheck.value = false;
      isVerifyingFace.value = false;
      isComparingWithIDCard.value = false;

      // Create a colored rectangle image
      final tempFile = await _generateColoredRectangleImage();

      if (tempFile != null) {
        // Set as selfie image
        selfieImage.value = XFile(tempFile.path);

        // Set all verification flags to success
        isLivenessCheckPassed.value = true;
        isSelfieValid.value = true;
        isMatchWithIDCard.value = true;
        matchConfidence.value = 0.99;

        // Create a result object
        faceComparisonResult.value = FaceComparisonResult(
          sourceFace: FaceModel(
            imagePath: tempFile.path,
            faceId: 'dev_mode_face_id',
          ),
          targetFace: FaceModel(
            imagePath: 'dev_mode_target',
            faceId: 'dev_mode_target_id',
          ),
          isMatch: true,
          confidence: 0.99,
          message: 'DEV MODE: Simulated verification',
        );

        // Auto-confirm
        hasConfirmedSelfie.value = true;

        Logger().i('DEV MODE: Fallback verification completed successfully');
      } else {
        // Last resort - just set the flags without an image
        Logger().w(
          'DEV MODE: Could not create even a fallback image, setting flags only',
        );
        isLivenessCheckPassed.value = true;
        isSelfieValid.value = true;
        isMatchWithIDCard.value = true;
        hasConfirmedSelfie.value = true;
      }
    } catch (e) {
      Logger().e('DEV MODE: Error in fallback verification: $e');
    }
  }

  // Helper method to create a temporary image file from assets or generate one
  Future<File?> _createDevModeImageFile() async {
    try {
      Logger().i('DEV MODE: Creating temporary image file');

      // Option 1: Use a bundled asset (if available)
      try {
        final ByteData byteData = await rootBundle.load(
          'assets/images/sample_selfie.jpg',
        );
        final Uint8List bytes = byteData.buffer.asUint8List();

        final tempDir = await getTemporaryDirectory();
        final tempFile = File(
          '${tempDir.path}/dev_sample_selfie_${DateTime.now().millisecondsSinceEpoch}.jpg',
        );
        await tempFile.writeAsBytes(bytes);
        Logger().i('DEV MODE: Created image from asset bundle');
        return tempFile;
      } catch (e) {
        // If no bundled asset, fall back to generated image
        Logger().i(
          'DEV MODE: No bundled selfie asset found, will generate an image',
        );
      }

      // Option 2: Generate a simple image programmatically
      return await _generateColoredRectangleImage();
    } catch (e) {
      Logger().e('DEV MODE: Error creating dev mode image file: $e');
      return null;
    }
  }

  // New method to generate a simple colored rectangle as an image
  Future<File?> _generateColoredRectangleImage() async {
    try {
      // Create a simple colored rectangle picture
      final recorder = ui.PictureRecorder();
      final canvas = Canvas(recorder);
      final paint = Paint()..color = Colors.blue;

      // Draw a face-like shape
      canvas.drawRect(Rect.fromLTWH(0, 0, 200, 200), paint);

      // Draw some face-like features
      final facePaint = Paint()..color = Colors.white;
      // Eyes
      canvas.drawCircle(const Offset(70, 80), 20, facePaint);
      canvas.drawCircle(const Offset(130, 80), 20, facePaint);
      // Mouth
      canvas.drawOval(Rect.fromLTWH(60, 120, 80, 30), facePaint);

      // Convert to image
      final picture = recorder.endRecording();
      final img = await picture.toImage(200, 200);
      final pngBytes = await img.toByteData(format: ui.ImageByteFormat.png);

      if (pngBytes != null) {
        final tempDir = await getTemporaryDirectory();
        final tempFile = File(
          '${tempDir.path}/dev_face_${DateTime.now().millisecondsSinceEpoch}.png',
        );
        await tempFile.writeAsBytes(pngBytes.buffer.asUint8List());
        
        Logger().i('DEV MODE: Generated colored rectangle image successfully');
        return tempFile;
      }
      
      return null;
    } catch (e) {
      Logger().e('DEV MODE: Error generating colored rectangle: $e');
      return null;
    }
  }

  // Method to bypass liveness check with a generated selfie
  Future<void> bypassLivenessCheckWithRandomImage() async {
    try {
      // Clear existing data first
      clearSelfieImage();
      resetVerificationState();

      // Avoid multiple simultaneous attempts
      if (_isImagePickerActive) {
        Logger().w('DEV MODE: Image picker already active, skipping bypass');
        return;
      }

      _isImagePickerActive = true;
      final logger = Logger();
      logger.i('DEV MODE: Bypassing liveness check with generated image');

      // Start loading state
      isPerformingLivenessCheck.value = true;

      // Simulate loading time
      await Future.delayed(const Duration(seconds: 1));

      // Create a temporary file using dev mode method
      final tempFile = await _createDevModeImageFile();

      if (tempFile != null) {
        // Set the selfie image
        selfieImage.value = XFile(tempFile.path);

        // Set liveness check as passed
        isLivenessCheckPassed.value = true;

        // Automatically start verification
        autoStartVerification = true;

        // Log the bypass action
        logger.i('DEV MODE: Liveness check bypassed successfully');

        // Start face verification
        await Future.delayed(const Duration(seconds: 1));
        await _simulateSuccessfulVerification();
      } else {
        // Try the fallback approach
        logger.w('DEV MODE: Failed with primary method, trying fallback');
        await _simulateVerificationWithoutImage();
      }
    } catch (e) {
      Logger().e('DEV MODE: Error bypassing liveness check: $e');
      selfieError.value = 'Error bypassing liveness check';

      // Try the fallback approach
      await _simulateVerificationWithoutImage();
    } finally {
      isPerformingLivenessCheck.value = false;
      _isImagePickerActive = false;
    }
  }

  // Simulate successful verification for development purposes
  Future<void> _simulateSuccessfulVerification() async {
    try {
      // Simulate face detection
      isVerifyingFace.value = true;
      await Future.delayed(const Duration(seconds: 1));
      isVerifyingFace.value = false;

      // Simulate ID card comparison
      isComparingWithIDCard.value = true;
      await Future.delayed(const Duration(seconds: 1));
      isComparingWithIDCard.value = false;

      // Set successful result
      final confidence =
          0.85 + (Random().nextDouble() * 0.14); // Between 85% and 99%
      matchConfidence.value = confidence;
      isMatchWithIDCard.value = true;

      // Create a sample result
      faceComparisonResult.value = FaceComparisonResult(
        sourceFace: FaceModel(
          imagePath: selfieImage.value!.path,
          faceId: 'selfie_face_id', // Provide a suitable faceId here
        ),
        targetFace: FaceModel(
          imagePath: idCardController?.idCardImage.value?.path ?? '',
          faceId: 'idcard_face_id', // Provide a suitable faceId here
        ),
        isMatch: true,
        confidence: confidence,
        message: 'DEV MODE: Simulated successful match',
      );

      Logger().i(
        'DEV MODE: Simulated successful verification with ${(confidence * 100).toStringAsFixed(1)}% confidence',
      );
    } catch (e) {
      Logger().e('DEV MODE: Error in simulated verification: $e');
    }
  }
}
