import 'dart:convert';
import 'dart:io';

import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart';
import 'package:logger/logger.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:sigap/src/cores/services/azure_ocr_service.dart';
import 'package:sigap/src/features/auth/data/models/face_model.dart';
import 'package:sigap/src/features/auth/data/models/kta_model.dart';
import 'package:sigap/src/features/auth/data/models/ktp_model.dart';
import 'package:sigap/src/features/auth/data/repositories/authentication_repository.dart';

class IdCardVerificationController extends GetxController {
  // Singleton instance
  static IdCardVerificationController get instance => Get.find();

  // Services
  final AzureOCRService _ocrService = AzureOCRService();

  // Store isOfficer as a reactive variable instead of a final field
  final RxBool _isOfficer = RxBool(false);
  bool get isOfficer => _isOfficer.value;

  // Maximum allowed file size in bytes (4MB)
  final int maxFileSizeBytes = 4 * 1024 * 1024; // 4MB in bytes

  // Constructor that accepts initial isOfficer value but will be updated from user data
  IdCardVerificationController({bool isOfficer = false}) {
    _isOfficer.value = isOfficer;
    Logger().i(
      'IdCardVerificationController initialized with isOfficer: $_isOfficer',
    );
    // Fetch current user role when controller is created
    fetchCurrentUserRole();
  }

  // Method to fetch current user role and update isOfficer flag
  Future<void> fetchCurrentUserRole() async {
    try {
      final metadata = AuthenticationRepository.instance.authUser?.userMetadata;

      if (metadata == null) {
        Logger().w('User metadata is null, cannot determine role');
        return;
      }

      // Ambil nilai is_officer
      final bool isOfficer = metadata['is_officer'] == true;

      // Simpan ke variabel observasi jika perlu
      _isOfficer.value = isOfficer;

      Logger().i('Updated isOfficer flag from user role: $isOfficer');

      // Tampilkan jenis kartu identitas yang perlu diverifikasi
      final String idCardType = isOfficer ? 'KTA' : 'KTP';
      Logger().i('User should verify $idCardType based on role');
    } catch (e) {
      Logger().e('Error fetching current user role: $e');
      // Keep the initial value if there's an error
    }
  }

  // Local storage keys
  static const String _kOcrResultsKey = 'ocr_results';
  static const String _kOcrModelKey = 'ocr_model';
  static const String _kIdCardTypeKey = 'id_card_type';

  // ID Card variables
  final Rx<XFile?> idCardImage = Rx<XFile?>(null);
  final RxString idCardError = RxString('');
  final RxBool isVerifying = RxBool(false);
  final RxBool isIdCardValid = RxBool(false);
  final RxString idCardValidationMessage = RxString('');
  final RxBool isFormValid = RxBool(true);

  // Loading states for image uploading
  final RxBool isUploadingIdCard = RxBool(false);

  // Confirmation status
  final RxBool hasConfirmedIdCard = RxBool(false);

  // Add RxMap to store OCR extraction results
  final RxMap<String, String> extractedInfo = RxMap<String, String>({});
  final RxBool hasExtractedInfo = RxBool(false);

  // Add model variables for the extracted data
  final Rx<KtpModel?> ktpModel = Rx<KtpModel?>(null);
  final Rx<KtaModel?> ktaModel = Rx<KtaModel?>(null);

  // Use FaceModel to store face details from ID card
  final Rx<FaceModel> idCardFace = Rx<FaceModel>(FaceModel.empty());

  // Store face ID from the ID card for later comparison (for backward compatibility)
  final RxString idCardFaceId = RxString('');
  final RxBool hasFaceDetected = RxBool(false);

  // Save OCR results to local storage
  Future<void> _saveOcrResultsToLocalStorage(
    Map<String, String> results,
  ) async {
    try {
      final prefs = await SharedPreferences.getInstance();
      final String jsonData = jsonEncode(results);
      final String idCardType = isOfficer ? 'KTA' : 'KTP';

      Logger().i(
        'Saving to local storage for ID card type: $idCardType (isOfficer=$isOfficer)',
      );

      await prefs.setString(_kOcrResultsKey, jsonData);
      await prefs.setString(_kIdCardTypeKey, idCardType);

      // Also save the model
      if (isOfficer && ktaModel.value != null) {
        Logger().i('Saving KTA model to storage');
        await prefs.setString(
          _kOcrModelKey,
          jsonEncode(ktaModel.value!.toJson()),
        );
      } else if (!isOfficer && ktpModel.value != null) {
        Logger().i('Saving KTP model to storage');
        await prefs.setString(
          _kOcrModelKey,
          jsonEncode(ktpModel.value!.toJson()),
        );
      }

      Logger().i('OCR results saved to local storage: ${results.length} items');
      Logger().i('ID Card Type saved: $idCardType');
    } catch (e) {
      Logger().e('Error saving OCR results to local storage: $e');
    }
  }

  // Load OCR results from local storage
  Future<Map<String, String>> loadOcrResultsFromLocalStorage() async {
    try {
      final prefs = await SharedPreferences.getInstance();
      final String? jsonData = prefs.getString(_kOcrResultsKey);
      if (jsonData != null) {
        final Map<String, dynamic> decodedData = jsonDecode(jsonData);
        return decodedData.map((key, value) => MapEntry(key, value.toString()));
      }
    } catch (e) {
      Logger().e('Error loading OCR results from local storage: $e');
    }
    return {};
  }

  bool validate() {
    clearErrors();

    if (idCardImage.value == null) {
      final idCardType = isOfficer ? 'KTA' : 'KTP';
      idCardError.value = 'Please upload your $idCardType image';
      isFormValid.value = false;
    } else if (!isIdCardValid.value) {
      idCardError.value = 'Your ID card image is not valid';
      isFormValid.value = false;
    } else if (!hasConfirmedIdCard.value) {
      idCardError.value = 'Please confirm your ID card image';
      isFormValid.value = false;
    }

    return isFormValid.value;
  }

  void clearErrors() {
    idCardError.value = '';
    // idCardValidationMessage.value = '';
  }

  // Pick ID Card Image with file size validation
  Future<void> pickIdCardImage(ImageSource source) async {
    try {
      isUploadingIdCard.value = true;
      hasConfirmedIdCard.value =
          false; // Reset confirmation whenever image changes

      final ImagePicker picker = ImagePicker();
      final XFile? image = await picker.pickImage(
        source: source,
        imageQuality: 80, // Reduce quality to help with file size
      );

      if (image != null) {
        // Check file size
        final File file = File(image.path);
        final int fileSize = await file.length();

        if (fileSize > maxFileSizeBytes) {
          idCardError.value =
              'Image size exceeds 4MB limit. Please choose a smaller image or lower resolution.';
          isIdCardValid.value = false;
          return;
        }

        // Add artificial delay to show loading state
        await Future.delayed(const Duration(seconds: 1));
        idCardImage.value = image;
        idCardError.value = '';

        // Initial validation of the ID card
        await validateIdCardImage();
      }
    } catch (e) {
      idCardError.value = 'Failed to pick image: $e';
      isIdCardValid.value = false;
    } finally {
      isUploadingIdCard.value = false;
    }
  }

  // Initial validation of ID card image
  Future<void> validateIdCardImage() async {
    // Clear previous validation messages
    clearErrors();

    // Also clear previous extraction results
    extractedInfo.clear();
    hasExtractedInfo.value = false;

    // Reset models
    ktpModel.value = null;
    ktaModel.value = null;

    // Initialize face data with empty model (just to maintain compatibility)
    idCardFace.value = FaceModel.empty();
    idCardFaceId.value = '';
    hasFaceDetected.value = false;

    if (idCardImage.value == null) {
      idCardError.value = 'Please upload an ID card image first';
      isIdCardValid.value = false;
      return;
    }

    try {
      // Make sure we have the latest user role before proceeding
      await fetchCurrentUserRole();

      isVerifying.value = true;
      final idCardType = isOfficer ? 'KTA' : 'KTP';

      Logger().i(
        'Starting ID card validation for ${isOfficer ? "KTA (Officer)" : "KTP (Citizen)"} - isOfficer flag: $isOfficer',
      );

      // Basic validation to check if the image is clear enough for OCR
      bool isImageValid = false;

      try {
        Logger().i(
          'About to process ID card image with OCR service - isOfficer flag: $isOfficer',
        );

        // Process the ID card with OCR
        final result = await _ocrService.processIdCard(
          idCardImage.value!,
          isOfficer,
        );

        Logger().i(
          'OCR processing completed for $idCardType - Data received: ${result.length} fields',
        );

        // Store the extraction results
        extractedInfo.assignAll(result);
        hasExtractedInfo.value = result.isNotEmpty;

        // Save the OCR results to local storage
        if (result.isNotEmpty) {
          Logger().i('Saving $idCardType OCR results to local storage...');
          await _saveOcrResultsToLocalStorage(result);
        }

        // Debug the extracted data
        Logger().i('Card type being validated: $idCardType');
        Logger().i('isOfficer flag: $isOfficer');
        Logger().i('Extracted data: $result');

        // Check if the extracted information is valid using our validation methods
        if (isOfficer) {
          Logger().i('Validating as KTA (Officer card)');
          isImageValid = _ocrService.isKtaValid(result);
          Logger().i('KTA validation result: $isImageValid');

          // Create KTA model from extracted data
          ktaModel.value = _ocrService.createKtaModel(result);
          Logger().i('KTA model created: ${ktaModel.value != null}');

          // Ensure KTP model is null
          ktpModel.value = null;
        } else {
          Logger().i('Validating as KTP (Citizen card)');
          isImageValid = _ocrService.isKtpValid(result);
          Logger().i('KTP validation result: $isImageValid');

          // Create KTP model from extracted data
          ktpModel.value = _ocrService.createKtpModel(result);
          Logger().i('KTP model created: ${ktpModel.value != null}');

          // Ensure KTA model is null
          ktaModel.value = null;
        }

        if (isImageValid) {
          // Instead of detecting faces here, we just save the image reference for later comparison
          isIdCardValid.value = true;
          idCardValidationMessage.value =
              '$idCardType image looks valid. Please confirm this is your $idCardType.';
          Logger().i('$idCardType validation successful');
        } else {
          isIdCardValid.value = false;
          idCardValidationMessage.value =
              'Unable to verify your $idCardType clearly. Please ensure all text is visible and try again.';
          Logger().i(
            '$idCardType validation failed - unable to verify clearly',
          );
        }
      } on SocketException catch (e) {
        isIdCardValid.value = false;
        if (e.message.contains('Connection timed out') ||
            e.message.contains('Connection refused')) {
          idCardValidationMessage.value =
              'Unable to connect to verification service. Please check your internet connection and try again later.';
        } else {
          idCardValidationMessage.value =
              'Network error occurred. Please try again later.';
        }
        Logger().e(
          'Network error during $idCardType validation: ${e.toString()}',
        );
      } catch (processingError) {
        isIdCardValid.value = false;
        idCardValidationMessage.value =
            'We\'re having trouble processing your $idCardType. Please try again with a clearer image.';
        Logger().e(
          'Processing error during $idCardType validation: ${processingError.toString()}',
        );
      }
    } catch (e) {
      isIdCardValid.value = false;

      // Provide user-friendly error messages based on error type
      if (e is SocketException) {
        idCardValidationMessage.value =
            'Connection problem detected. Please check your internet connection and try again.';
      } else if (e.toString().contains('timeout')) {
        idCardValidationMessage.value =
            'The verification is taking too long. Please try again later when the connection is better.';
      } else {
        // Generic but still user-friendly error message
        final idCardType = isOfficer ? 'KTA' : 'KTP';
        idCardValidationMessage.value =
            'We encountered an issue during $idCardType verification. Please try again later.';
      }

      // Log the actual error for debugging (wouldn't be shown to the user)
      Logger().e('ID Card validation error: ${e.toString()}');
    } finally {
      isVerifying.value = false;

      // Final verification of which model is set
      Logger().i(
        'Final verification - Card type: ${isOfficer ? "KTA" : "KTP"}',
      );
      Logger().i('KTP model is null: ${ktpModel.value == null}');
      Logger().i('KTA model is null: ${ktaModel.value == null}');
    }
  }

  // Get the ID card image path for face comparison
  String? get idCardImagePath => idCardImage.value?.path;

  // Check if the ID card has a detected face
  bool get hasDetectedFace => idCardFace.value.hasValidFace;

  // Clear ID Card Image
  void clearIdCardImage() async {
    idCardImage.value = null;
    idCardError.value = '';
    isIdCardValid.value = false;
    idCardValidationMessage.value = '';
    hasConfirmedIdCard.value = false;
    extractedInfo.clear();
    hasExtractedInfo.value = false;
    ktpModel.value = null;
    ktaModel.value = null;
    idCardFace.value = FaceModel.empty();
    idCardFaceId.value = '';
    hasFaceDetected.value = false;

    // Also clear local storage
    try {
      final prefs = await SharedPreferences.getInstance();
      await prefs.remove(_kOcrResultsKey);
      await prefs.remove(_kOcrModelKey);
      await prefs.remove(_kIdCardTypeKey);
    } catch (e) {
      Logger().e('Error clearing OCR results from local storage: $e');
    }
  }

  // Confirm ID Card Image
  void confirmIdCardImage() {
    if (isIdCardValid.value) {
      hasConfirmedIdCard.value = true;

      clearErrors(); // Clear any previous errors
    }
  }

  // Get the verified model for passing to the next step
  dynamic get verifiedIdCardModel {
    return isOfficer ? ktaModel.value : ktpModel.value;
  }

  // Debug helper method - can be called from UI for troubleshooting
  void debugControllerState() {
    Logger().i('======= ID CARD VERIFICATION CONTROLLER STATE =======');
    Logger().i('isOfficer: $isOfficer');
    Logger().i('Current ID card type: ${isOfficer ? "KTA" : "KTP"}');
    Logger().i('Has ID card image: ${idCardImage.value != null}');
    Logger().i('Is ID card valid: ${isIdCardValid.value}');
    Logger().i('Has confirmed ID card: ${hasConfirmedIdCard.value}');
    Logger().i('Has extracted info: ${hasExtractedInfo.value}');
    Logger().i('Extracted info fields: ${extractedInfo.length}');
    Logger().i('KTP model null: ${ktpModel.value == null}');
    Logger().i('KTA model null: ${ktaModel.value == null}');
    Logger().i('================================================');
  }

  // Method to force update the isOfficer flag (useful for testing or if user role changes)
  void updateIsOfficerFlag(bool value) {
    Logger().i('Manually updating isOfficer flag from $isOfficer to $value');
    _isOfficer.value = value;
  }
}
