import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:marco/helpers/services/auth_service.dart'; import 'package:marco/helpers/services/storage/local_storage.dart'; import 'package:marco/helpers/widgets/my_form_validator.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:marco/view/dashboard/dashboard_screen.dart'; import 'package:marco/helpers/services/app_logger.dart'; // import 'package:marco/helpers/services/firebase/firebase_messaging_service.dart'; // 🔴 Commented out class MPINController extends GetxController { final MyFormValidator basicValidator = MyFormValidator(); final isNewUser = false.obs; final isChangeMpin = false.obs; final RxBool isLoading = false.obs; final formKey = GlobalKey(); // Updated to 4-digit MPIN final digitControllers = List.generate(4, (_) => TextEditingController()); final focusNodes = List.generate(4, (_) => FocusNode()); final retypeControllers = List.generate(4, (_) => TextEditingController()); final retypeFocusNodes = List.generate(4, (_) => FocusNode()); final RxInt failedAttempts = 0.obs; @override void onInit() { super.onInit(); final bool hasMpin = LocalStorage.getIsMpin(); isNewUser.value = !hasMpin; logSafe("onInit called. isNewUser: ${isNewUser.value}"); } /// Enable Change MPIN mode void setChangeMpinMode() { isChangeMpin.value = true; isNewUser.value = false; clearFields(); clearRetypeFields(); logSafe("setChangeMpinMode activated"); } /// Handle digit entry and focus movement void onDigitChanged(String value, int index, {bool isRetype = false}) { logSafe( "onDigitChanged -> index: $index, value: $value, isRetype: $isRetype"); final nodes = isRetype ? retypeFocusNodes : focusNodes; if (value.isNotEmpty && index < 3) { nodes[index + 1].requestFocus(); } else if (value.isEmpty && index > 0) { nodes[index - 1].requestFocus(); } } /// Submit MPIN for verification or generation Future onSubmitMPIN() async { logSafe("onSubmitMPIN triggered"); if (!formKey.currentState!.validate()) { logSafe("Form validation failed", level: LogLevel.warning); return; } final enteredMPIN = digitControllers.map((c) => c.text).join(); logSafe("Entered MPIN: $enteredMPIN"); if (enteredMPIN.length < 4) { _showError("Please enter all 4 digits."); return; } if (isNewUser.value || isChangeMpin.value) { final retypeMPIN = retypeControllers.map((c) => c.text).join(); logSafe("Retyped MPIN: $retypeMPIN"); if (retypeMPIN.length < 4) { _showError("Please enter all 4 digits in Retype MPIN."); return; } if (enteredMPIN != retypeMPIN) { _showError("MPIN and Retype MPIN do not match."); clearFields(); clearRetypeFields(); return; } final bool success = await generateMPIN(mpin: enteredMPIN); if (success) { logSafe("MPIN generation/change successful."); showAppSnackbar( title: "Success", message: isChangeMpin.value ? "MPIN changed successfully." : "MPIN generated successfully. Please login again.", type: SnackbarType.success, ); await LocalStorage.logout(); } else { logSafe("MPIN generation/change failed.", level: LogLevel.warning); clearFields(); clearRetypeFields(); } } else { logSafe("Existing user. Proceeding to verify MPIN."); await verifyMPIN(); } } /// Forgot MPIN Future onForgotMPIN() async { logSafe("onForgotMPIN called"); isNewUser.value = true; isChangeMpin.value = false; clearFields(); clearRetypeFields(); } /// Switch to login/enter MPIN screen void switchToEnterMPIN() { logSafe("switchToEnterMPIN called"); isNewUser.value = false; isChangeMpin.value = false; clearFields(); clearRetypeFields(); } /// Show error snackbar void _showError(String message) { logSafe("ERROR: $message", level: LogLevel.error); showAppSnackbar( title: "Error", message: message, type: SnackbarType.error, ); } /// Navigate to dashboard void _navigateToDashboard({String? message}) { if (message != null) { logSafe("Navigating to Dashboard with message: $message"); showAppSnackbar( title: "Success", message: message, type: SnackbarType.success, ); } Get.offAll(() => const DashboardScreen()); } /// Clear the primary MPIN fields void clearFields() { logSafe("clearFields called"); for (final c in digitControllers) { c.clear(); } focusNodes.first.requestFocus(); } /// Clear the retype MPIN fields void clearRetypeFields() { logSafe("clearRetypeFields called"); for (final c in retypeControllers) { c.clear(); } retypeFocusNodes.first.requestFocus(); } /// Cleanup @override void onClose() { logSafe("onClose called"); for (final controller in digitControllers) { controller.dispose(); } for (final node in focusNodes) { node.dispose(); } for (final controller in retypeControllers) { controller.dispose(); } for (final node in retypeFocusNodes) { node.dispose(); } super.onClose(); } /// Generate MPIN for new user/change MPIN Future generateMPIN({required String mpin}) async { try { isLoading.value = true; logSafe("generateMPIN started"); final employeeInfo = LocalStorage.getEmployeeInfo(); final String? employeeId = employeeInfo?.id; if (employeeId == null || employeeId.isEmpty) { isLoading.value = false; _showError("Missing employee ID."); return false; } logSafe("Calling AuthService.generateMpin for employeeId: $employeeId"); final response = await AuthService.generateMpin( employeeId: employeeId, mpin: mpin, ); isLoading.value = false; if (response == null) { return true; } else { logSafe("MPIN generation returned error: $response", level: LogLevel.warning); showAppSnackbar( title: "MPIN Operation Failed", message: "Please check your inputs.", type: SnackbarType.error, ); basicValidator.addErrors(response); basicValidator.validateForm(); basicValidator.clearErrors(); return false; } } catch (e) { isLoading.value = false; logSafe("Exception in generateMPIN", level: LogLevel.error, error: e); _showError("Failed to process MPIN."); return false; } } /// Verify MPIN for existing user Future verifyMPIN() async { logSafe("verifyMPIN triggered"); final enteredMPIN = digitControllers.map((c) => c.text).join(); logSafe("Entered MPIN: $enteredMPIN"); if (enteredMPIN.length < 4) { _showError("Please enter all 4 digits."); return; } final mpinToken = await LocalStorage.getMpinToken(); if (mpinToken == null || mpinToken.isEmpty) { _showError("Missing MPIN token. Please log in again."); return; } try { isLoading.value = true; // ✅ Fetch FCM Token here (DISABLED) // final fcmToken = await FirebaseNotificationService().getFcmToken(); final response = await AuthService.verifyMpin( mpin: enteredMPIN, mpinToken: mpinToken, // fcmToken: fcmToken ?? '', // 🔴 Commented out fcmToken: '', // ✅ Passing empty string instead ); isLoading.value = false; if (response == null) { logSafe("MPIN verified successfully"); await LocalStorage.setBool('mpin_verified', true); showAppSnackbar( title: "Success", message: "MPIN Verified Successfully", type: SnackbarType.success, ); _navigateToDashboard(); } else { final errorMessage = response["error"] ?? "Invalid MPIN"; logSafe("MPIN verification failed: $errorMessage", level: LogLevel.warning); showAppSnackbar( title: "Error", message: errorMessage, type: SnackbarType.error, ); clearFields(); onInvalidMPIN(); } } catch (e) { isLoading.value = false; logSafe("Exception in verifyMPIN", level: LogLevel.error, error: e); showAppSnackbar( title: "Error", message: "Something went wrong. Please try again.", type: SnackbarType.error, ); } } /// Increment failed attempts and warn void onInvalidMPIN() { failedAttempts.value++; if (failedAttempts.value >= 3) { showAppSnackbar( title: "Error", message: "Too many failed attempts. Consider logging in again.", type: SnackbarType.error, ); } } }