runDiagnostics method

Runs a best-effort diagnostics sweep and returns actionable hints.

Implementation

Future<NotificationDiagnosticsResult> runDiagnostics() async {
  try {
    final NotificationSettings settings =
        await _fcmService.getNotificationSettings();
    final bool fcmSupported = _fcmService.isSupportedOnCurrentPlatform;
    final bool permissionsGranted =
        !fcmSupported || _isAuthorized(settings.authorizationStatus);

    final String? storedToken = await _storageService.getFcmToken();
    final bool tokenAvailable = storedToken != null && storedToken.isNotEmpty;

    final bool badgeSupported = await _notificationService.isBadgeSupported();
    final List<dynamic> pendingNotifications =
        await _notificationService.getPendingNotifications();

    final String webPermission =
        await _notificationService.getWebNotificationPermissionStatus();
    final bool webAllowed = webPermission == 'granted';
    final Map<String, dynamic> webRuntimeDiagnostics =
        await _notificationService.getWebRuntimeDiagnostics();

    final Map<String, dynamic> deliveryDiagnostics =
        _inAppMessageManager.getDeliveryDiagnostics(DateTime.now());
    final int queuedBackgroundMessages =
        (await _storageService.getQueuedBackgroundMessages()).length;

    final List<String> recommendations = <String>[];

    if (!permissionsGranted) {
      recommendations.add(
          'Prompt the user for notification permissions; current status: '
          '${settings.authorizationStatus.name}.');
    }

    if (!fcmSupported) {
      recommendations.add(
          _fcmService.unsupportedPlatformReason ??
              'Firebase Cloud Messaging is unavailable on this platform.');
      recommendations.add(
          'Use local notifications, scheduling, inbox, and in-app templates on desktop. For remote delivery, send through your own backend and handle desktop presentation locally.');
    }

    if (fcmSupported && !tokenAvailable) {
      recommendations.add(
          'No stored FCM token found. Ensure init() completed and updateTokenCallback saved the token.');
    }

    if (!badgeSupported) {
      recommendations.add(
          'App icon badges are not supported on $currentPlatformName or the current launcher.');
    }

    if (isWeb && !webAllowed) {
      recommendations.add(
          'Browser notifications are currently "$webPermission". Trigger a permission prompt or guide the user to allow notifications.');
    }

    if (isWeb &&
        webRuntimeDiagnostics['notificationApiAvailable'] == false) {
      recommendations.add(
          'This browser does not expose the Notification API. Use a supported browser such as Chrome, Edge, or Safari with web notifications enabled.');
    }

    if (isWeb && webRuntimeDiagnostics['isSecureContext'] == false) {
      recommendations.add(
          'Web notifications require a secure context. Serve the app from HTTPS or localhost before testing push delivery.');
    }

    if (isWeb &&
        webRuntimeDiagnostics['serviceWorkerApiAvailable'] == false) {
      recommendations.add(
          'Service workers are unavailable in this browser context. Web push will not function until service worker support is available.');
    }

    if (isWeb &&
        webRuntimeDiagnostics['serviceWorkerApiAvailable'] == true &&
        webRuntimeDiagnostics['serviceWorkerControllerPresent'] == false) {
      recommendations.add(
          'No active service worker is controlling this page. Verify the Firebase messaging service worker is registered at the expected scope.');
    }

    if (pendingNotifications.length > 16) {
      recommendations.add(
          'There are ${pendingNotifications.length} pending notifications queued locally. Consider pruning scheduled notifications.');
    }

    return NotificationDiagnosticsResult(
      success: true,
      permissionsGranted: permissionsGranted,
      authorizationStatus: settings.authorizationStatus.name,
      fcmTokenAvailable: tokenAvailable,
      badgeSupported: badgeSupported,
      webNotificationsAllowed: webAllowed,
      pendingNotificationCount: pendingNotifications.length,
      platform: currentPlatformName,
      recommendations: recommendations,
      metadata: {
        'alertSetting': settings.alert.name,
        'badgeSetting': settings.badge.name,
        'soundSetting': settings.sound.name,
        'showPreviews': settings.showPreviews.name,
        'providesAppNotificationSettings':
            settings.providesAppNotificationSettings.name,
        'fcmSupported': fcmSupported,
        'fcmUnsupportedReason': _fcmService.unsupportedPlatformReason,
        'webPermission': webPermission,
        'webDiagnostics': webRuntimeDiagnostics,
        'storedTokenPresent': tokenAvailable,
        'deliveryPolicy': deliveryDiagnostics,
        'queuedBackgroundMessages': queuedBackgroundMessages,
        'dataBridgeEnabled': _dataOnlyMessageBridge != null,
        'backgroundHandlerRegistered': _backgroundHandlerRegistered,
        'invalidPayloadCount': _invalidPayloadCount,
      },
    );
  } catch (error, stack) {
    _logMessage('[NotificationManager] Diagnostics error: $error');
    _logMessage('[NotificationManager] Stack trace: $stack');
    return NotificationDiagnosticsResult.failure(
      platform: currentPlatformName,
      error: error.toString(),
    );
  }
}