import 'package:get/get.dart'; import 'package:agora_chat_sdk/agora_chat_sdk.dart'; import 'package:onufitness/constants/data_constant.dart'; import 'dart:async'; import 'package:onufitness/controller/get_agora_token_controller.dart'; import 'package:onufitness/services/local_storage_services/shared_services.dart'; import 'package:onufitness/services/logger_service.dart'; class AgoraChatService extends GetxService { static AgoraChatService get instance => Get.find(); final logger = LoggerService(); final String appKey = agoraChatAppKey; Timer? _tokenRefreshTimer; Future init() async { await initChatSdk(); return this; } Future initChatSdk() async { final options = ChatOptions( appKey: appKey, autoLogin: false, isAutoDownloadThumbnail: false, requireAck: true, requireDeliveryAck: true, ); try { await ChatClient.getInstance.init(options); // Critical: Wait for native SDK to fully initialize await Future.delayed(Duration(milliseconds: 1500)); await ChatClient.getInstance.startCallback(); await addListener(); logger.log("Agora Chat SDK initialized successfully"); } catch (e, stackTrace) { logger.error( "Failed to initialize Agora Chat SDK", error: e, stackTrace: stackTrace, ); rethrow; } } addListener() async { _startTokenRefreshTimer(); ChatClient.getInstance.addConnectionEventHandler( "TOKEN_REFRESH_HANDLER", ConnectionEventHandler( onTokenWillExpire: () async { await agoraChatTokenAPIcall(); var tokenSuccess = SharedServices.getAgoraUserAndRtmTokens(); var userToken = tokenSuccess!.data!.agoraUserToken.toString(); await ChatClient.getInstance.renewAgoraToken(userToken); }, onTokenDidExpire: () async { await agoraChatTokenAPIcall(); }, onDisconnected: () {}, onConnected: () { _startTokenRefreshTimer(); }, ), ); } void _startTokenRefreshTimer() { _tokenRefreshTimer?.cancel(); _tokenRefreshTimer = Timer.periodic(Duration(minutes: 5), (timer) async { await agoraChatTokenAPIcall(); }); } Future agoraChatTokenAPIcall() async { try { if (!Get.isRegistered()) { Get.put(AgoraTokenController()); } final agoraTokenController = Get.find(); final success = await agoraTokenController.getAgoraUserAndRrmToken(); if (success) { await loginToAgora(); } } catch (e, stackTrace) { logger.error( "Failed to get Agora chat token", error: e, stackTrace: stackTrace, ); } } String globalUserToken = ""; Future loginToAgora() async { globalUserToken = ""; try { final loginDetails = SharedServices.getLoginDetails(); if (loginDetails?.data?.userId == null) { logger.error("No login details found"); return false; } final tokenSuccess = SharedServices.getAgoraUserAndRtmTokens(); if (tokenSuccess?.data == null || tokenSuccess?.data?.agoraUserToken == null) { logger.error("No Agora token found"); return false; } final userToken = tokenSuccess!.data!.agoraUserToken.toString(); globalUserToken = userToken; final userId = loginDetails!.data!.userId.toString(); final agoraUserId = userId.replaceAll("-", ""); // Check connection state first final isConnected = await ChatClient.getInstance.isConnected(); final currentUser = ChatClient.getInstance.currentUserId; if (isConnected && currentUser == agoraUserId) { logger.log("User already logged in and connected: $agoraUserId"); return true; } // If currentUser exists but not connected, logout first if (currentUser != null && currentUser != agoraUserId) { logger.log("Different user logged in, logging out first"); await ChatClient.getInstance.logout(false); } logger.log("Attempting login to Agora chat: $agoraUserId"); await ChatClient.getInstance.loginWithToken(agoraUserId, userToken); // Verify login succeeded await Future.delayed(Duration(milliseconds: 500)); final loginVerified = await ChatClient.getInstance.isConnected(); if (loginVerified) { logger.log("Successfully logged in to Agora chat: $agoraUserId"); return true; } else { logger.error("Login completed but not connected"); return false; } } on ChatError catch (e, stackTrace) { // Handle "already logged in" error gracefully if (e.code == 200) { logger.log("User already logged in to Agora chat (code 200)"); return true; } logger.error( "Failed to login to Agora chat", error: e, stackTrace: stackTrace, ); // Try to renew token if (globalUserToken.isNotEmpty) { try { await ChatClient.getInstance.renewAgoraToken(globalUserToken); } catch (renewError) { logger.error("Failed to renew token", error: renewError); } } return false; } catch (e, stackTrace) { logger.error( "Unexpected error during Agora login", error: e, stackTrace: stackTrace, ); return false; } } Future isUserLoggedIn() async { try { final isConnected = await ChatClient.getInstance.isConnected(); final currentUser = ChatClient.getInstance.currentUserId; if (!isConnected || currentUser == null) { logger.log( "User not logged in. Connected: $isConnected, User: $currentUser", ); return false; } logger.log("User logged in and connected: $currentUser"); return true; } catch (e) { logger.error("Error checking login state", error: e); return false; } } String? get currentUserId => ChatClient.getInstance.currentUserId; @override void onClose() { _tokenRefreshTimer?.cancel(); super.onClose(); } }