import 'package:flutter_test/flutter_test.dart';
import 'package:moonwell_launcher/features/launcher/data/launcher_log_service.dart';
import 'package:moonwell_launcher/features/launcher/data/launcher_update_service.dart';

void main() {
  group('LauncherUpdateService', () {
    test('does nothing on unsupported platforms', () async {
      final client = _FakeLauncherUpdateClient();
      final logger = _FakeLauncherLogService();
      final service = LauncherUpdateService.forTesting(
        launcherLogService: logger,
        updateClient: client,
        isWindows: false,
      );

      await service.checkForUpdates(
        feedUrl: 'https://moon-well.online/launcher/updates/appcast.xml',
      );

      expect(client.calls, isEmpty);
      expect(logger.entries, isEmpty);
    });

    test('logs disabled state when the feed URL is empty', () async {
      final client = _FakeLauncherUpdateClient();
      final logger = _FakeLauncherLogService();
      final service = LauncherUpdateService.forTesting(
        launcherLogService: logger,
        updateClient: client,
        isWindows: true,
      );

      await service.checkForUpdates(feedUrl: '  ');

      expect(client.calls, isEmpty);
      expect(logger.entries.single, startsWith('INFO:'));
    });

    test('rejects a non-HTTPS feed URL without invoking the updater', () async {
      final client = _FakeLauncherUpdateClient();
      final logger = _FakeLauncherLogService();
      final service = LauncherUpdateService.forTesting(
        launcherLogService: logger,
        updateClient: client,
        isWindows: true,
      );

      await service.checkForUpdates(
        feedUrl: 'http://moon-well.online/appcast.xml',
      );

      expect(client.calls, isEmpty);
      expect(logger.entries.single, startsWith('ERROR:'));
    });

    test('rejects an HTTPS URL without a host', () async {
      final client = _FakeLauncherUpdateClient();
      final logger = _FakeLauncherLogService();
      final service = LauncherUpdateService.forTesting(
        launcherLogService: logger,
        updateClient: client,
        isWindows: true,
      );

      await service.checkForUpdates(feedUrl: 'https:appcast.xml');

      expect(client.calls, isEmpty);
      expect(logger.entries.single, startsWith('ERROR:'));
    });

    test(
      'configures WinSparkle before starting one background check',
      () async {
        final client = _FakeLauncherUpdateClient();
        final logger = _FakeLauncherLogService();
        final service = LauncherUpdateService.forTesting(
          launcherLogService: logger,
          updateClient: client,
          isWindows: true,
        );
        const feedUrl = 'https://moon-well.online/launcher/updates/appcast.xml';

        await service.checkForUpdates(feedUrl: feedUrl);
        await service.checkForUpdates(feedUrl: feedUrl);

        expect(client.calls, <String>[
          'setFeedUrl:$feedUrl',
          'disableScheduledChecks',
          'checkInBackground',
        ]);
        expect(logger.entries.single, startsWith('INFO:'));
      },
    );

    test('logs updater failures without propagating them', () async {
      final client = _FakeLauncherUpdateClient(failure: Exception('offline'));
      final logger = _FakeLauncherLogService();
      final service = LauncherUpdateService.forTesting(
        launcherLogService: logger,
        updateClient: client,
        isWindows: true,
      );

      await expectLater(
        service.checkForUpdates(
          feedUrl: 'https://moon-well.online/launcher/updates/appcast.xml',
        ),
        completes,
      );

      expect(logger.entries.single, contains('offline'));
    });
  });
}

class _FakeLauncherUpdateClient implements LauncherUpdateClient {
  _FakeLauncherUpdateClient({this.failure});

  final Object? failure;
  final List<String> calls = <String>[];

  @override
  Future<void> setFeedUrl(String feedUrl) async {
    calls.add('setFeedUrl:$feedUrl');
    if (failure case final error?) {
      throw error;
    }
  }

  @override
  Future<void> disableScheduledChecks() async {
    calls.add('disableScheduledChecks');
  }

  @override
  Future<void> checkInBackground() async {
    calls.add('checkInBackground');
  }
}

class _FakeLauncherLogService extends LauncherLogService {
  final List<String> entries = <String>[];

  @override
  Future<void> info(
    String message, {
    String? installationDir,
    Map<String, Object?> details = const <String, Object?>{},
  }) async {
    entries.add('INFO:$message');
  }

  @override
  Future<void> error(
    String message, {
    String? installationDir,
    Map<String, Object?> details = const <String, Object?>{},
    Object? error,
    StackTrace? stackTrace,
  }) async {
    entries.add('ERROR:$message:$error');
  }
}
