import 'package:flutter/material.dart'; import 'package:jwt_decoder/jwt_decoder.dart'; import 'package:get/get.dart'; import 'package:sefer_admin1/controller/functions/device_info.dart'; import 'package:sefer_admin1/views/auth/login_page.dart'; import '../../constant/box_name.dart'; import '../../constant/links.dart'; import '../../constant/info.dart'; import '../../main.dart'; import '../../print.dart'; import '../../views/admin/admin_home_page.dart'; import '../../views/widgets/snackbar.dart'; import '../admin/dashboard_controller.dart'; import '../functions/crud.dart'; import '../functions/encrypt_decrypt.dart'; class OtpHelper extends GetxController { static final String _sendOtpUrl = '${AppLink.server}/Admin/auth/send_otp_admin.php'; static final String _verifyOtpUrl = '${AppLink.server}/Admin/auth/verify_otp_admin.php'; static final String _checkAdminLogin = '${AppLink.server}/Admin/auth/login.php'; /// إرسال OTP static Future sendOtp(String phoneNumber) async { try { // await CRUD().getJWT(); final response = await CRUD().post( link: _sendOtpUrl, payload: {'receiver': phoneNumber}, ); // Log.print('_sendOtpUrl: ${_sendOtpUrl}'); // Log.print('response: ${response}'); if (response != 'failure') { mySnackbarSuccess('تم إرسال رمز التحقق إلى رقمك عبر WhatsApp'); return true; } else { mySnackeBarError('حدث خطأ من الخادم. حاول مجددًا.'); return false; } } catch (e) { Log.print('OTP SEND ERROR: $e'); mySnackeBarError('حدث خطأ أثناء الإرسال: $e'); return false; } } /// التحقق من OTP Future verifyOtp(String phoneNumber, String otp) async { try { final response = await CRUD().post( link: _verifyOtpUrl, payload: { 'phone_number': phoneNumber, 'otp': otp, 'device_number': box.read(BoxName.fingerPrint) }, ); if (response != 'failure') { if (response['status'] == 'success') { box.write(BoxName.phoneVerified, true); box.write(BoxName.adminPhone, phoneNumber); mySnackbarSuccess('تم التحقق من الرقم بنجاح'); await checkAdminLogin(); } else { mySnackeBarError(response['message'] ?? 'فشل في التحقق.'); } } else { mySnackeBarError('فشل من الخادم. حاول مرة أخرى.'); } } catch (e) { Log.print('OTP VERIFY ERROR: $e'); mySnackeBarError('خطأ في التحقق: $e'); } } /// تسجيل الدخول بكلمة المرور والبصمة Future loginWithPassword(String password) async { try { final fingerprint = box.read(BoxName.fingerPrint); final response = await CRUD().post( link: _checkAdminLogin, payload: { 'fingerprint': fingerprint, 'password': password, }, ); if (response != 'failure') { // إذا كان الرد يتطلب OTP (السيرفر يرجعها بداخل message) final msg = response['message']; if (response['status'] == 'otp_required' || (msg is Map && msg['status'] == 'otp_required')) { String phone = (msg is Map ? msg['phone'] : response['phone']) ?? ''; _showOtpDialog(phone, password, fingerprint); return false; // ننتظر إكمال الـ OTP } // إذا نجح الدخول مباشرة return _handleLoginSuccess(response, password); } else { // سيقوم CRUD بإظهار الخطأ المناسب (مثل "حسابك قيد المراجعة") return false; } } catch (e) { Log.print('LOGIN ERROR: $e'); mySnackeBarError('حدث خطأ أثناء تسجيل الدخول: $e'); return false; } } /// التحقق من OTP الخاص بتسجيل الدخول Future verifyLoginOtp( String phone, String otp, String password, String fingerprint) async { try { final response = await CRUD().post( link: '${AppLink.server}/Admin/auth/verify_login.php', payload: { 'phone': phone, 'otp': otp, 'fingerprint': fingerprint, }, ); if (response != 'failure') { bool success = await _handleLoginSuccess(response, password); if (success) { try { if (Get.isRegistered()) { Get.find().getDashBoard(); } } catch (e) {} Get.offAll(() => const AdminHomePage()); } } } catch (e) { Log.print('OTP VERIFY LOGIN ERROR: $e'); mySnackeBarError('خطأ في التحقق من الرمز: $e'); } } Future _handleLoginSuccess(dynamic response, String password) async { final msg = response['message']; final data = response['admin'] ?? (msg is Map ? msg['admin'] : null); final jwt = response['jwt'] ?? (msg is Map ? msg['jwt'] : null); if (jwt != null) { await box.write(BoxName.jwt, c(jwt)); } if (data != null) { if (data['id'] != null) await box.write(BoxName.driverID, data['id']); if (data['role'] != null) { String role = data['role'].toString().trim(); await box.write('admin_role', role); Log.print('Admin role saved: $role'); } if (data['phone'] != null) await box.write(BoxName.adminPhone, data['phone']); } await box.write(BoxName.phoneVerified, true); await box.write('admin_password', password); mySnackbarSuccess('تم تسجيل الدخول بنجاح'); return true; } void _showOtpDialog(String phone, String password, String fingerprint) { String otpCode = ''; Get.defaultDialog( title: 'رمز التحقق', content: Column( children: [ Text('تم إرسال رمز التحقق إلى WhatsApp الخاص بك ($phone)'), const SizedBox(height: 16), TextField( onChanged: (val) => otpCode = val, keyboardType: TextInputType.number, decoration: const InputDecoration( hintText: 'أدخل الرمز هنا', border: OutlineInputBorder(), ), ), ], ), textConfirm: 'تحقق', confirmTextColor: Colors.white, onConfirm: () { if (otpCode.length >= 3) { Get.back(); verifyLoginOtp(phone, otpCode, password, fingerprint); } else { mySnackeBarError('الرجاء إدخال رمز صحيح'); } }, ); } static bool _isAutoLoginAttempted = false; Future checkAdminLogin() async { final fingerprint = box.read(BoxName.fingerPrint); final password = box.read('admin_password'); if (fingerprint == null || password == null) { Get.offAll(() => const AdminLoginPage()); return; } // ─── أولاً: التحقق من وجود توكن JWT صالح ───────── // إذا وُجد توكن غير منتهي الصلاحية → ندخل مباشرة بدون استدعاء login.php final rawJwt = box.read(BoxName.jwt); if (rawJwt != null) { try { String token = r(rawJwt.toString()).split(AppInformation.addd)[0]; if (!JwtDecoder.isExpired(token)) { Log.print('Valid JWT found, skipping login.php (no OTP needed)'); Get.offAll(() => const AdminHomePage()); return; } Log.print('JWT expired, need fresh login'); } catch (e) { Log.print('JWT decode failed: \$e, need fresh login'); } } // ─── ثانياً: لا يوجد توكن صالح → استدعاء login.php ─── final response = await CRUD().post( link: _checkAdminLogin, payload: { 'fingerprint': fingerprint, 'password': password, 'is_renewal': '1', }, ); if (response != 'failure') { final msg = response['message']; if (response['status'] == 'otp_required' || (msg is Map && msg['status'] == 'otp_required')) { String phone = (msg is Map ? msg['phone'] : response['phone']) ?? ''; _showOtpDialog(phone, password, fingerprint); return; // ننتظر إدخال رمز التحقق } if (msg is Map && msg['jwt'] != null) { box.write(BoxName.jwt, c(msg['jwt'])); if (msg['admin'] != null && msg['admin']['id'] != null) { box.write(BoxName.driverID, msg['admin']['id']); } } else if (response['jwt'] != null) { box.write(BoxName.jwt, c(response['jwt'])); } try { if (Get.isRegistered()) { Get.find().getDashBoard(); } } catch (e) {} Get.offAll(() => const AdminHomePage()); } else { Log.print('Auto-login failed, redirecting to login page'); Get.offAll(() => const AdminLoginPage()); } } @override void onInit() { super.onInit(); DeviceHelper.getDeviceFingerprint().then((deviceFingerprint) { box.write(BoxName.fingerPrint, deviceFingerprint); }); // تأجيل تنفيذ التنقل حتى تنتهي مرحلة البناء // ⚠️ محاولة واحدة فقط للتسجيل التلقائي لمنع الحلقة اللانهائية Future.microtask(() { if (_isAutoLoginAttempted) { // نحن في حلقة — نتوقف ونذهب لصفحة الدخول مباشرة Log.print('Auto-login already attempted, skipping to login page'); return; } _isAutoLoginAttempted = true; if (box.read(BoxName.phoneVerified) == true && box.read(BoxName.adminPhone) != null) { checkAdminLogin(); } else { Get.offAll(() => AdminLoginPage()); } }); } }