import 'dart:convert'; import 'dart:developer' as dev; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; import 'package:test_sa/controllers/notification/notification_manger.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/settings/app_settings.dart'; import 'package:test_sa/dashboard_latest/dashboard_view.dart'; import 'package:test_sa/dashboard_latest/widgets/app_bar_widget.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/models/enums/user_types.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/pages/land_page/create_request_type_bottom_sheet.dart'; import 'package:test_sa/new_views/pages/land_page/my_request/my_requests_page.dart'; import 'package:test_sa/new_views/pages/login_page.dart'; import 'package:test_sa/new_views/pages/settings_page.dart'; import 'package:test_sa/providers/work_order/vendor_provider.dart'; import 'package:test_sa/views/widgets/equipment/my_assets_page.dart'; import 'package:test_sa/modules/cx_module/chat/services/call_manager.dart'; import 'package:test_sa/modules/cx_module/chat/services/signalr_service.dart'; import 'package:test_sa/modules/cx_module/chat/chat_api_client.dart'; import '../../../controllers/providers/settings/setting_provider.dart'; import '../../../views/widgets/dialogs/dialog.dart'; import '../../common_widgets/app_bottom_nav_bar.dart'; import '../../common_widgets/app_drawer.dart'; import 'contact_us_bottom_sheet.dart'; class LandPage extends StatefulWidget { static const String routeName = "/land-page"; const LandPage({Key? key}) : super(key: key); @override State createState() => _LandPageState(); } class _LandPageState extends State { final GlobalKey _scaffoldKey = GlobalKey(); int currentPageIndex = 0; bool showAppbar = true; late List _pages; UserProvider? _userProvider; bool isFCM = true; @override void initState() { _pages = []; super.initState(); } void checkLocalAuth() async { if (await Provider.of(context, listen: false).auth.isDeviceSupported()) { SharedPreferences prefs = await SharedPreferences.getInstance(); if (!prefs.containsKey(ASettings.localAuth)) { (await Provider.of(context, listen: false)).setAuth(false); showModalBottomSheet( context: context, useSafeArea: true, backgroundColor: Colors.transparent, builder: (context) => SafeArea( child: Container( clipBehavior: Clip.antiAlias, decoration: BoxDecoration( color: AppColor.bottomSheetColor(context), borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), ), padding: EdgeInsets.symmetric(horizontal: 24.toScreenWidth, vertical: 24.toScreenHeight), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( width: 40.toScreenWidth, height: 5.toScreenHeight, decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), ), 16.height, Align( alignment: AlignmentDirectional.centerStart, child: (Platform.isAndroid ? "Fingerprint" : "Face ID").addTranslation.heading3(context).custom(fontWeight: FontWeight.w600), ), 16.height, (Platform.isAndroid ? "fingerprint" : "faceid").toLottieAsset(height: 180), 16.height, Align( alignment: AlignmentDirectional.centerStart, child: Text( "Let's set up Face ID/Fingerprint for quick and secure logins in the future".addTranslation, style: AppTextStyles.bodyText, )), 24.height, AppFilledButton( onPressed: () { Navigator.pop(context); Navigator.of(context).pushNamed(SettingsPage.id); }, label: "Continue".addTranslation), ], )), ), ); } } } @override Widget build(BuildContext context) { if (_userProvider == null) { _userProvider = Provider.of(context, listen: false); if (_userProvider!.user != null && _userProvider!.user!.employeeIsHMG == false) { WidgetsBinding.instance.addPostFrameCallback((_) { _userProvider!.getSwipeLastTransaction(userId: _userProvider!.user!.userID!); _userProvider!.getSiteContactInfo(); if(!_userProvider!.isHouseKeeper) { Provider.of(context, listen: false).getData(); } }); } _pages = [ DashboardView(onDrawerPress: (() { _scaffoldKey.currentState!.isDrawerOpen ? _scaffoldKey.currentState!.closeDrawer() : _scaffoldKey.currentState!.openDrawer(); })), const MyRequestsPage(), const SizedBox(), const MyAssetsPage(fromBottomBar: true), ]; if (isFCM) { FirebaseNotificationManger.initialized(context); NotificationManger.initialisation((notificationDetails) { FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload!)); }, (id, title, body, payload) async {}); // ⭐ Initialize SignalR & CallManager ONCE at app startup WidgetsBinding.instance.addPostFrameCallback((_) async { await _initializeCallingSystem(); }); isFCM = false; } checkLocalAuth(); } return WillPopScope( onWillPop: () async { bool result = await showDialog( context: context, builder: (_) => AAlertDialog(title: context.translation.signOut, content: context.translation.logoutAlert), ); if (result) { // Cleanup calling system before logout await _cleanupCallingSystem(); bool isSuccess = await Provider.of(context, listen: false).logout(context); if (isSuccess) { Provider.of(context, listen: false).resetSettings(); Provider.of(context, listen: false).reset(); Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); } } return false; }, child: Scaffold( key: _scaffoldKey, appBar: _pages.isEmpty ? PreferredSize( preferredSize: const Size.fromHeight(kToolbarHeight), child: AppBarWidget( onDrawerPress: () { _scaffoldKey.currentState!.isDrawerOpen ? _scaffoldKey.currentState!.closeDrawer() : _scaffoldKey.currentState!.openDrawer(); }, )) : null, drawer: const AppDrawer(), body: _pages[currentPageIndex], bottomNavigationBar: _pages.isEmpty ? null : AppBottomNavigationBar( selectedIndex: currentPageIndex, onPressed: (index) { if (index == 2) { showModalBottomSheet( context: context, useSafeArea: true, backgroundColor: Colors.white, builder: (context) => CreateRequestTypeBottomSheet(), ); } else if (index == 4) { showModalBottomSheet( context: context, useSafeArea: true, backgroundColor: Colors.transparent, builder: (context) => const ContactUsBottomSheet(), ); } else { setState(() { currentPageIndex = index; }); if (index == 1) { setState(() { showAppbar = false; }); } else { setState(() { showAppbar = true; }); } } }, ), ), ); } /// Initialize SignalR and CallManager once at app startup /// This ensures calls work from ANY screen without CMDetailPage dependency Future _initializeCallingSystem() async { try { final user = _userProvider?.user; if (user?.username == null) { dev.log('⚠️ [LAND PAGE] User not logged in, skipping call initialization', name: 'LandPage'); return; } final myEmployeeNumber = user!.username!; // Use username as employee number final userId = user.userID?.toString() ?? user.username!; dev.log('═══════════════════════════════════════════', name: 'LandPage'); dev.log('🚀 [LAND PAGE] Initializing calling system...', name: 'LandPage'); dev.log(' User: ${user.username}', name: 'LandPage'); dev.log(' User ID: $userId', name: 'LandPage'); dev.log(' Employee Number: $myEmployeeNumber', name: 'LandPage'); // Step 1: Get chat credentials dev.log('🔑 [LAND PAGE] Fetching chat credentials...', name: 'LandPage'); final chatLoginResponse = await ChatApiClient().getChatLoginToken( 1002, // moduleId - using default 0, // referenceId - using default for app-level init 'App Init', myEmployeeNumber, myEmployeeNumber, ); if (chatLoginResponse == null || chatLoginResponse.token == null) { dev.log('❌ [LAND PAGE] Failed to get chat credentials', name: 'LandPage'); dev.log(' Response: ${chatLoginResponse?.toJson()}', name: 'LandPage'); return; } dev.log('✅ [LAND PAGE] Got chat credentials', name: 'LandPage'); dev.log(' User ID: ${chatLoginResponse.userId}', name: 'LandPage'); dev.log(' Token: ${chatLoginResponse.token!.substring(0, 20)}...', name: 'LandPage'); // Step 2: Initialize SignalR Service (SINGLETON - only once) dev.log('🔌 [LAND PAGE] Initializing SignalR Service...', name: 'LandPage'); final signalRService = SignalRService(); final connected = await signalRService.initialize( userId: chatLoginResponse.userId.toString(), authToken: chatLoginResponse.token!, conversationId: null, // No conversation at app level ); if (!connected) { dev.log('❌ [LAND PAGE] SignalR initialization failed', name: 'LandPage'); return; } dev.log('✅ [LAND PAGE] SignalR Service initialized', name: 'LandPage'); dev.log(' Connection State: ${signalRService.connectionState}', name: 'LandPage'); dev.log(' Connection ID: ${signalRService.connectionId ?? "NULL"}', name: 'LandPage'); // Step 3: Initialize CallManager (registers call event handlers) dev.log('📞 [LAND PAGE] Initializing CallManager...', name: 'LandPage'); await CallManager().initialize( userId: chatLoginResponse.userId.toString(), authToken: chatLoginResponse.token!, conversationId: null, moduleId: '1002', referenceId: '0', employeeNumber: myEmployeeNumber, ); dev.log('✅ [LAND PAGE] CallManager initialized', name: 'LandPage'); dev.log('═══════════════════════════════════════════', name: 'LandPage'); dev.log('✅ [LAND PAGE] Calling system ready!', name: 'LandPage'); dev.log(' ✅ SignalR: Connected', name: 'LandPage'); dev.log(' ✅ CallManager: Ready', name: 'LandPage'); dev.log(' ✅ WebRTC: Will initialize on first call', name: 'LandPage'); dev.log(' ✅ Calls work from ANY screen now', name: 'LandPage'); dev.log('═══════════════════════════════════════════', name: 'LandPage'); } catch (e, stackTrace) { dev.log('❌ [LAND PAGE] Error initializing calling system: $e', name: 'LandPage', error: e, stackTrace: stackTrace); // Don't crash the app, just log the error // User can still use the app, calls just won't work } } /// Cleanup SignalR and CallManager on logout Future _cleanupCallingSystem() async { try { dev.log('🧹 [LAND PAGE] Cleaning up calling system...', name: 'LandPage'); // Reset CallManager await CallManager().reset(); // Disconnect SignalR await SignalRService().disconnect(); dev.log('✅ [LAND PAGE] Calling system cleaned up', name: 'LandPage'); } catch (e) { dev.log('⚠️ [LAND PAGE] Error during cleanup: $e', name: 'LandPage'); } } }