import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:tane/db/database.dart';
import 'package:tane/security/secure_key_store.dart';
import 'package:tane/services/auto_backup_service.dart';
import 'package:tane/services/auto_backup_store.dart';
import 'package:tane/services/export_import_service.dart';
import 'package:tane/services/file_service.dart';
import 'package:tane/ui/auto_backup_gate.dart';

import '../support/test_support.dart';

class _NoFiles implements FileService {
  @override
  Future<String?> saveFile({
    required String suggestedName,
    required Uint8List bytes,
  }) async => null;

  @override
  Future<Uint8List?> pickFileBytes({List<String>? allowedExtensions}) async =>
      null;
}

/// Counts how many times the lifecycle asked for a backup.
class _SpyAutoBackup extends AutoBackupService {
  _SpyAutoBackup(AppDatabase db)
    : super(
        exporter: ExportImportService(
          repository: newTestRepository(db),
          files: _NoFiles(),
          keys: SecureKeyStore(store: InMemorySecretStore()),
        ),
        store: AutoBackupStore(InMemorySecretStore()),
        directory: () async => throw UnimplementedError(),
      );

  int calls = 0;

  @override
  Future<bool> runIfDue({Duration interval = const Duration(days: 7)}) async {
    calls++;
    return false;
  }
}

void main() {
  late AppDatabase db;

  setUp(() => db = newTestDatabase());
  tearDown(() => db.close());

  testWidgets('runs a backup on startup', (tester) async {
    final spy = _SpyAutoBackup(db);
    await tester.pumpWidget(
      AutoBackupGate(service: spy, child: const SizedBox()),
    );
    await tester.pump(); // let the post-frame callback fire

    expect(spy.calls, 1);
  });

  testWidgets('runs a backup again when the app is hidden', (tester) async {
    final spy = _SpyAutoBackup(db);
    await tester.pumpWidget(
      AutoBackupGate(service: spy, child: const SizedBox()),
    );
    await tester.pump(); // startup backup

    tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.inactive);
    tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.hidden);

    expect(spy.calls, 2);
  });

  testWidgets('does nothing when no service is provided', (tester) async {
    await tester.pumpWidget(
      const AutoBackupGate(child: Text('ok', textDirection: TextDirection.ltr)),
    );
    await tester.pump();

    expect(find.text('ok'), findsOneWidget);
  });
}
