import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

import 'package:sharedinbox/core/models/mailbox.dart';
import 'package:sharedinbox/di.dart';

import 'helpers.dart';

void main() {
  group('SearchScreen', () {
    testWidgets('shows placeholder hint text when empty', (tester) async {
      await tester.pumpWidget(
        buildApp(
          initialLocation: '/accounts/acc-1/search',
          overrides: [
            accountRepositoryProvider.overrideWithValue(
              FakeAccountRepository([kTestAccount]),
            ),
            mailboxRepositoryProvider.overrideWithValue(
              FakeMailboxRepository(),
            ),
            emailRepositoryProvider.overrideWithValue(FakeEmailRepository()),
            searchHistoryRepositoryProvider.overrideWithValue(
              FakeSearchHistoryRepository(),
            ),
          ],
        ),
      );
      await tester.pumpAndSettle();

      expect(find.text('Type 3+ characters to search'), findsOneWidget);
    });

    testWidgets('typing fewer than 3 characters does not trigger search', (
      tester,
    ) async {
      await tester.pumpWidget(
        buildApp(
          initialLocation: '/accounts/acc-1/search',
          overrides: [
            accountRepositoryProvider.overrideWithValue(
              FakeAccountRepository([kTestAccount]),
            ),
            mailboxRepositoryProvider.overrideWithValue(
              FakeMailboxRepository(),
            ),
            emailRepositoryProvider.overrideWithValue(FakeEmailRepository()),
            searchHistoryRepositoryProvider.overrideWithValue(
              FakeSearchHistoryRepository(),
            ),
          ],
        ),
      );
      await tester.pumpAndSettle();

      await tester.enterText(find.byType(TextField), 'hi');
      await tester.pump(const Duration(milliseconds: 400));

      expect(find.text('Type 3+ characters to search'), findsOneWidget);
      expect(find.text('No results'), findsNothing);
    });

    testWidgets('shows "No results" when search returns nothing', (
      tester,
    ) async {
      await tester.pumpWidget(
        buildApp(
          initialLocation: '/accounts/acc-1/search',
          overrides: [
            accountRepositoryProvider.overrideWithValue(
              FakeAccountRepository([kTestAccount]),
            ),
            mailboxRepositoryProvider.overrideWithValue(
              FakeMailboxRepository(),
            ),
            emailRepositoryProvider.overrideWithValue(FakeEmailRepository()),
            searchHistoryRepositoryProvider.overrideWithValue(
              FakeSearchHistoryRepository(),
            ),
          ],
        ),
      );
      await tester.pumpAndSettle();

      await tester.enterText(find.byType(TextField), 'xyz');
      await tester.pump(const Duration(milliseconds: 400));
      await tester.pumpAndSettle();

      expect(find.text('No results'), findsOneWidget);
    });

    testWidgets('shows email results under "Messages" section', (tester) async {
      final email = testEmail(subject: 'Invoice Q3');
      await tester.pumpWidget(
        buildApp(
          initialLocation: '/accounts/acc-1/search',
          overrides: [
            accountRepositoryProvider.overrideWithValue(
              FakeAccountRepository([kTestAccount]),
            ),
            mailboxRepositoryProvider.overrideWithValue(
              FakeMailboxRepository(),
            ),
            emailRepositoryProvider.overrideWithValue(
              FakeEmailRepository(searchResults: [email]),
            ),
            searchHistoryRepositoryProvider.overrideWithValue(
              FakeSearchHistoryRepository(),
            ),
          ],
        ),
      );
      await tester.pumpAndSettle();

      await tester.enterText(find.byType(TextField), 'inv');
      await tester.pump(const Duration(milliseconds: 400));
      await tester.pumpAndSettle();

      expect(find.text('Messages'), findsOneWidget);
      expect(find.text('Invoice Q3'), findsOneWidget);
    });

    testWidgets('shows folder results under "Folders" section', (tester) async {
      const archiveMailbox = Mailbox(
        id: 'acc-1:Archive',
        accountId: 'acc-1',
        path: 'Archive',
        name: 'Archive',
        unreadCount: 0,
        totalCount: 5,
      );
      await tester.pumpWidget(
        buildApp(
          initialLocation: '/accounts/acc-1/search',
          overrides: [
            accountRepositoryProvider.overrideWithValue(
              FakeAccountRepository([kTestAccount]),
            ),
            mailboxRepositoryProvider.overrideWithValue(
              FakeMailboxRepository([archiveMailbox]),
            ),
            emailRepositoryProvider.overrideWithValue(FakeEmailRepository()),
            searchHistoryRepositoryProvider.overrideWithValue(
              FakeSearchHistoryRepository(),
            ),
          ],
        ),
      );
      await tester.pumpAndSettle();

      await tester.enterText(find.byType(TextField), 'arc');
      await tester.pump(const Duration(milliseconds: 400));
      await tester.pumpAndSettle();

      expect(find.text('Folders'), findsOneWidget);
      expect(find.text('Archive'), findsOneWidget);
    });

    testWidgets('folder with query as word prefix is matched', (tester) async {
      const foobarMailbox = Mailbox(
        id: 'acc-1:Foobar',
        accountId: 'acc-1',
        path: 'Foobar',
        name: 'Foobar',
        unreadCount: 0,
        totalCount: 0,
      );
      await tester.pumpWidget(
        buildApp(
          initialLocation: '/accounts/acc-1/search',
          overrides: [
            accountRepositoryProvider.overrideWithValue(
              FakeAccountRepository([kTestAccount]),
            ),
            mailboxRepositoryProvider.overrideWithValue(
              FakeMailboxRepository([foobarMailbox]),
            ),
            emailRepositoryProvider.overrideWithValue(FakeEmailRepository()),
            searchHistoryRepositoryProvider.overrideWithValue(
              FakeSearchHistoryRepository(),
            ),
          ],
        ),
      );
      await tester.pumpAndSettle();

      await tester.enterText(find.byType(TextField), 'foo');
      await tester.pump(const Duration(milliseconds: 400));
      await tester.pumpAndSettle();

      expect(find.text('Folders'), findsOneWidget);
      expect(find.text('Foobar'), findsOneWidget);
    });

    testWidgets('folder whose name ends with query is not matched', (
      tester,
    ) async {
      const blafooMailbox = Mailbox(
        id: 'acc-1:Blafoo',
        accountId: 'acc-1',
        path: 'Blafoo',
        name: 'Blafoo',
        unreadCount: 0,
        totalCount: 0,
      );
      await tester.pumpWidget(
        buildApp(
          initialLocation: '/accounts/acc-1/search',
          overrides: [
            accountRepositoryProvider.overrideWithValue(
              FakeAccountRepository([kTestAccount]),
            ),
            mailboxRepositoryProvider.overrideWithValue(
              FakeMailboxRepository([blafooMailbox]),
            ),
            emailRepositoryProvider.overrideWithValue(FakeEmailRepository()),
            searchHistoryRepositoryProvider.overrideWithValue(
              FakeSearchHistoryRepository(),
            ),
          ],
        ),
      );
      await tester.pumpAndSettle();

      await tester.enterText(find.byType(TextField), 'foo');
      await tester.pump(const Duration(milliseconds: 400));
      await tester.pumpAndSettle();

      expect(find.text('Blafoo'), findsNothing);
      expect(find.text('No results'), findsOneWidget);
    });

    testWidgets('tapping clear button resets results to placeholder', (
      tester,
    ) async {
      final email = testEmail(subject: 'Found email');
      await tester.pumpWidget(
        buildApp(
          initialLocation: '/accounts/acc-1/search',
          overrides: [
            accountRepositoryProvider.overrideWithValue(
              FakeAccountRepository([kTestAccount]),
            ),
            mailboxRepositoryProvider.overrideWithValue(
              FakeMailboxRepository(),
            ),
            emailRepositoryProvider.overrideWithValue(
              FakeEmailRepository(searchResults: [email]),
            ),
            searchHistoryRepositoryProvider.overrideWithValue(
              FakeSearchHistoryRepository(),
            ),
          ],
        ),
      );
      await tester.pumpAndSettle();

      await tester.enterText(find.byType(TextField), 'found');
      await tester.pump(const Duration(milliseconds: 400));
      await tester.pumpAndSettle();
      expect(find.text('Found email'), findsOneWidget);

      await tester.tap(find.byIcon(Icons.clear));
      await tester.pumpAndSettle();

      // Results are gone; the recent-search chip for the prior query appears.
      expect(find.text('Found email'), findsNothing);
      expect(find.text('found'), findsOneWidget);
    });
  });
}
