import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:get_it/get_it.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../features/auth/cubit/login_cubit.dart'; import '../features/auth/data/auth_repository.dart'; import '../features/profile/data/profile_repository.dart'; import '../features/rating/cubit/rating_cubit.dart'; import '../features/rating/data/rating_repository.dart'; import '../features/rewards/cubit/rewards_cubit.dart'; import '../features/rewards/data/rewards_repository.dart'; import '../features/settings/cubit/settings_cubit.dart'; import '../features/trip/cubit/history_cubit.dart'; import '../features/chat/cubit/chat_cubit.dart'; import '../features/chat/data/chat_repository.dart'; import '../features/onboarding/cubit/onboarding_cubit.dart'; import '../features/onboarding/data/driver_repository.dart'; import '../features/trip/cubit/duty_cubit.dart'; import '../features/trip/data/history_repository.dart'; import '../features/trip/data/maps_repository.dart'; import '../features/trip/data/trip_repository.dart'; import '../features/wallet/cubit/payout_cubit.dart'; import '../features/wallet/cubit/wallet_cubit.dart'; import '../features/wallet/data/wallet_repository.dart'; import 'api/antlaq_api.dart'; import 'api/api_client.dart'; import 'build_config.dart'; import 'location/location_service.dart'; import 'notifications/push_service.dart'; import 'realtime/realtime_service.dart'; import 'session/session_cubit.dart'; import 'session/session_source.dart'; import 'storage/token_store.dart'; import 'tenant/tenant_cubit.dart'; final sl = GetIt.instance; /// نقطة الإقفال الوحيدة (docs/23 §5): الميزة المطفأة **لا تُسجَّل**، بدل /// `if` مبعثرة في الشاشات. Future setupInjector() async { final prefs = await SharedPreferences.getInstance(); sl.registerSingleton(prefs); const secure = FlutterSecureStorage( iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock), ); final tokens = TokenStore(secure); await tokens.load(); await _ensureDeviceId(tokens); sl.registerSingleton(tokens); sl.registerSingleton(SettingsCubit(prefs)); // انتهاء الجلسة يصعد من طبقة الشبكة إلى `SessionCubit` مباشرة — الراوتر // يستمع إليه فيخرج المستخدم بلا `BuildContext` في الـinterceptor. sl.registerSingleton( ApiClient.create( tokens: tokens, onSessionExpired: () async => sl().onSessionExpired(), ), ); final authRepo = AuthRepository(sl(), sl()); sl.registerSingleton(authRepo); sl.registerSingleton(authRepo); sl.registerSingleton(ProfileRepository(sl())); sl.registerSingleton( SessionCubit(authRepo, onAuthenticated: () => sl().register()), ); // تدفّق الدخول قصير العمر: نسخة جديدة لكل دخول، لا نسخة واحدة أبدية. sl.registerFactory(() => LoginCubit(sl(), sl())); // الخرائط عميل منفصل بلا توكن تريبز — map-saas لا شأن له بجلستنا. sl.registerSingleton(AntlaqApi.create()); sl.registerSingleton(MapsRepository(sl())); sl.registerSingleton(TripRepository(sl())); sl.registerSingleton(LocationService()); sl.registerSingleton(RealtimeService(tokens)); sl.registerSingleton(TenantCubit(sl(), prefs)); sl.registerSingleton(PushService(sl())); sl.registerSingleton(DriverRepository(sl())); sl.registerFactory(() => OnboardingCubit(sl())); sl.registerSingleton(HistoryRepository(sl())); sl.registerFactory(() => HistoryCubit(sl())); sl.registerSingleton(RatingRepository(sl())); // المكافآت خلف علم الكوبونات: الدعوات والكوبونات وجهان لنفس الوحدة. if (Features.coupons) { sl.registerSingleton(RewardsRepository(sl())); sl.registerFactory(() => RewardsCubit(sl())); } sl.registerFactory(() => RatingCubit(sl())); // الدردشة خلف علمها: إطفاؤه يحذف كودها من الـbinary (docs/23 §5). if (Features.chat) { sl.registerSingleton(ChatRepository(sl())); sl.registerFactory(() => ChatCubit(sl())); } // المحفظة خلف علم الاستحقاق: الميزة المطفأة لا تُسجَّل أصلاً (docs/23 §5). if (Features.wallet) { sl.registerSingleton(WalletRepository(sl())); sl.registerFactory(() => WalletCubit(sl())); sl.registerFactory(() => PayoutCubit(sl())); } sl.registerFactory(() => DutyCubit( trips: sl(), location: sl(), realtime: sl(), )); } /// بصمة الجهاز (`x-device-id`) — يفرضها الخادم عند تفعيل /// `AUTH_REQUIRE_DEVICE_BINDING` (docs/38 §8). تُرسَل من الآن كي يُفعَّل /// العَلَم لاحقاً بلا تعديل التطبيق: **أرسل أولاً ثم فعّل الخادم**. Future _ensureDeviceId(TokenStore tokens) async { if (await tokens.deviceId() != null) return; final info = DeviceInfoPlugin(); String? id; try { if (defaultTargetPlatform == TargetPlatform.android) { id = (await info.androidInfo).id; } else if (defaultTargetPlatform == TargetPlatform.iOS) { id = (await info.iosInfo).identifierForVendor; } } catch (_) { // منصّة لا تجيب — المعرّف الفارغ أفضل من إقلاع فاشل. } if (id != null && id.isNotEmpty) await tokens.setDeviceId(id); }