import 'package:flutter_test/flutter_test.dart';
import 'package:sharedinbox/core/repositories/sync_log_repository.dart';
import 'package:sharedinbox/data/db/database.dart';
import 'package:sharedinbox/data/repositories/sync_log_repository_impl.dart';

import 'db_test_helper.dart';

void main() {
  configureSqliteForTests();

  late final db = openTestDatabase();

  setUpAll(() async {
    await db.into(db.accounts).insert(
          AccountsCompanion.insert(
            id: 'acc1',
            displayName: 'Test',
            email: 'test@example.com',
            imapHost: 'imap.example.com',
            imapPort: 993,
            imapSsl: true,
            smtpHost: 'smtp.example.com',
            smtpPort: 587,
            smtpSsl: true,
          ),
        );
  });

  tearDownAll(() => db.close());

  test('logs success entry', () async {
    final repo = SyncLogRepositoryImpl(db);
    final start = DateTime(2024, 1, 1, 10);
    final end = DateTime(2024, 1, 1, 10, 0, 5);

    await repo.log(
      accountId: 'acc1',
      success: true,
      protocol: 'imap',
      emailsFetched: 5,
      emailsSkipped: 0,
      mailboxesSynced: 3,
      pendingFlushed: 0,
      bytesTransferred: 0,
      startedAt: start,
      finishedAt: end,
    );

    final rows = await db.select(db.syncLogs).get();
    expect(rows, hasLength(1));
    expect(rows.first.result, 'ok');
    expect(rows.first.errorMessage, null);
    expect(rows.first.accountId, 'acc1');
    expect(rows.first.protocol, 'imap');
    expect(rows.first.itemsSynced, 5);
    expect(rows.first.mailboxesSynced, 3);
    expect(rows.first.pendingFlushed, 0);
  });

  test('stores and retrieves per-mailbox duration', () async {
    final repo = SyncLogRepositoryImpl(db);
    final start = DateTime(2024, 2, 1, 10);
    final end = DateTime(2024, 2, 1, 10, 0, 8);

    await repo.log(
      accountId: 'acc1',
      success: true,
      protocol: 'imap',
      emailsFetched: 3,
      emailsSkipped: 1,
      mailboxesSynced: 2,
      pendingFlushed: 0,
      bytesTransferred: 1024,
      startedAt: start,
      finishedAt: end,
      mailboxStats: const [
        MailboxSyncStats(
          mailboxPath: 'INBOX',
          fetched: 2,
          skipped: 1,
          bytesTransferred: 512,
          duration: Duration(milliseconds: 3200),
        ),
        MailboxSyncStats(
          mailboxPath: 'Sent',
          fetched: 1,
          skipped: 0,
          bytesTransferred: 512,
        ),
      ],
    );

    final entries = await repo.observeSyncLogs('acc1').first;
    final latest = entries.first;
    expect(latest.mailboxStats, hasLength(2));
    expect(latest.mailboxStats[0].mailboxPath, 'INBOX');
    expect(latest.mailboxStats[0].duration, const Duration(milliseconds: 3200));
    expect(latest.mailboxStats[1].mailboxPath, 'Sent');
    expect(latest.mailboxStats[1].duration, isNull);
  });

  test('logs error entry with message', () async {
    final repo = SyncLogRepositoryImpl(db);
    final start = DateTime(2024, 1, 1, 11);
    final end = DateTime(2024, 1, 1, 11, 0, 2);

    await repo.log(
      accountId: 'acc1',
      success: false,
      errorMessage: 'Connection refused',
      protocol: 'imap',
      emailsFetched: 0,
      emailsSkipped: 0,
      mailboxesSynced: 0,
      pendingFlushed: 0,
      bytesTransferred: 0,
      startedAt: start,
      finishedAt: end,
    );

    final rows = await (db.select(
      db.syncLogs,
    )..where((r) => r.result.equals('error')))
        .get();
    expect(rows, hasLength(1));
    expect(rows.first.result, 'error');
    expect(rows.first.errorMessage, 'Connection refused');
  });

  test(
    'stores and retrieves stackTrace and isPermanent on error entries',
    () async {
      final repo = SyncLogRepositoryImpl(db);
      final start = DateTime(2024, 3, 1, 9);
      final end = DateTime(2024, 3, 1, 9, 0, 1);
      const fakeTrace = '#0 main (file:///app/lib/main.dart:10:5)';

      await repo.log(
        accountId: 'acc1',
        success: false,
        errorMessage: 'MissingPluginException',
        stackTrace: fakeTrace,
        isPermanent: true,
        protocol: 'imap',
        emailsFetched: 0,
        emailsSkipped: 0,
        mailboxesSynced: 0,
        pendingFlushed: 0,
        bytesTransferred: 0,
        startedAt: start,
        finishedAt: end,
      );

      final entries = await repo.observeSyncLogs('acc1').first;
      final entry = entries.firstWhere((e) => e.startedAt == start);
      expect(entry.stackTrace, fakeTrace);
      expect(entry.isPermanent, true);
      expect(entry.errorMessage, 'MissingPluginException');
    },
  );
}
