import 'package:flutter_test/flutter_test.dart';
import 'package:iop_client/client_bootstrap.dart';
import 'package:iop_client/main.dart';
import 'package:iop_client/src/integrations/nexo/nexo_notification_client.dart';
import 'package:iop_client/src/integrations/nexo/nexo_notification_host_integration.dart';
import 'support/client_test_harness.dart';

/// Fake NexoNotificationClient that does not reach out to Firebase/FCM.
/// Includes `initializedForTest` for test verification.
class _TestFakeNexoClient implements NexoNotificationClient {
  bool _initialized = false;

  bool get initializedForTest => _initialized;

  @override
  Stream<Map<String, dynamic>> get onNotification =>
      const Stream<Map<String, dynamic>>.empty();

  @override
  Future<void> initialize() async {
    _initialized = true;
  }

  @override
  Future<String?> getDeviceToken() async => null;

  @override
  Future<void> setAuthToken(
    String serverUrl,
    String token, {
    String? identifier,
  }) async {}

  @override
  Future<void> setSigningKey(String serverUrl, String signingKey) async {}

  @override
  set onDeviceTokenReady(Future<void> Function(String token)? callback) {}

  @override
  set onNavigateToChannel(
    void Function(String serverUrl, String channelId)? callback,
  ) {}

  @override
  set onNavigateToThread(
    void Function(String serverUrl, String rootId)? callback,
  ) {}
}

void main() {
  testWidgets('runIopClient can skip external integrations', (
    WidgetTester tester,
  ) async {
    const options = IopClientBootstrapOptions(
      initializeFirebase: false,
      initializeNotifications: false,
    );

    // This should run without any exceptions
    await bootstrapIopClient(options: options);

    final fakeClient = FakeClientWireClient(shouldSuccess: true);

    // Verify it doesn't fail basic widget pump
    await tester.pumpWidget(
      IopClientApp(testClient: fakeClient, statusRepository: null),
    );
    expect(find.byType(IopClientApp), findsOneWidget);
  });

  testWidgets('bootstrap initializes Nexo notification host by default', (
    WidgetTester tester,
  ) async {
    // Default initializeNotifications = true, but with fake host to avoid
    // Firebase/FCM plugin calls in test environment.
    final fakeHost = NexoNotificationHostIntegration(
      pushClient: _TestFakeNexoClient(),
    );

    final testOptions = IopClientBootstrapOptions(
      initializeFirebase: false,
      notificationHost: fakeHost,
    );

    await bootstrapIopClient(options: testOptions);

    // Verify the provided host is initialized
    expect(fakeHost.isInitialized, isTrue);
  });

  testWidgets('bootstrap skips notification when disabled', (
    WidgetTester tester,
  ) async {
    final fakeHost = NexoNotificationHostIntegration(
      pushClient: _TestFakeNexoClient(),
    );
    const options = IopClientBootstrapOptions(
      initializeFirebase: false,
      initializeNotifications: false,
    );

    await bootstrapIopClient(
      options: IopClientBootstrapOptions(
        initializeFirebase: options.initializeFirebase,
        initializeNotifications: options.initializeNotifications,
        notificationHost: fakeHost,
      ),
    );

    expect(fakeHost.isInitialized, isFalse);
  });

  testWidgets('bootstrap accepts custom NexoNotificationHostIntegration', (
    WidgetTester tester,
  ) async {
    final customHost = NexoNotificationHostIntegration(
      pushClient: _TestFakeNexoClient(),
    );

    final testOptions = IopClientBootstrapOptions(
      initializeFirebase: false,
      notificationHost: customHost,
    );

    await bootstrapIopClient(options: testOptions);

    expect(customHost.isInitialized, isTrue);
  });

  testWidgets('bootstrap initializes with injected host without requiring '
      'auth login or credential assets', (WidgetTester tester) async {
    final fakeClient = _TestFakeNexoClient();
    final fakeHost = NexoNotificationHostIntegration(pushClient: fakeClient);

    final testOptions = IopClientBootstrapOptions(
      initializeFirebase: false,
      notificationHost: fakeHost,
    );

    // This must succeed without looking for external push credentials.
    await bootstrapIopClient(options: testOptions);

    expect(fakeHost.isInitialized, isTrue);
    expect(fakeClient.initializedForTest, isTrue);
  });
}
