import 'dart:typed_data';

import 'package:commons_core/commons_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:tane/db/database.dart';
import 'package:tane/db/enums.dart';
import 'package:tane/i18n/strings.g.dart';
import 'package:tane/ui/inventory_list_screen.dart';

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

/// A valid 1x1 transparent PNG so the avatar image decodes cleanly in tests.
final _tinyPng = Uint8List.fromList(const [
  137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 1, //
  0, 0, 0, 1, 8, 6, 0, 0, 0, 31, 21, 196, 137, 0, 0, 0, 13, 73, 68, 65, 84, //
  120, 156, 99, 250, 207, 0, 0, 0, 2, 0, 1, 226, 33, 188, 51, 0, 0, 0, 0, //
  73, 69, 78, 68, 174, 66, 96, 130,
]);

void main() {
  late AppDatabase db;

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

  testWidgets('shows the empty state when there are no seeds', (tester) async {
    final repo = newTestRepository(db);
    await tester.pumpWidget(
      wrapScreen(repository: repo, child: const InventoryListScreen()),
    );
    await tester.pumpAndSettle();

    expect(find.text('No seeds yet. Tap + to add your first.'), findsOneWidget);
    await disposeTree(tester);
  });

  testWidgets(
    'renders seeds from the repository grouped under their category',
    (tester) async {
      final repo = newTestRepository(db);
      await repo.addQuickVariety(
        label: 'Grandma tomato',
        category: 'Solanaceae',
      );

      await tester.pumpWidget(
        wrapScreen(repository: repo, child: const InventoryListScreen()),
      );
      await tester.pumpAndSettle();

      expect(find.text('Grandma tomato'), findsOneWidget);
      // The category now appears both as a group header and a filter chip.
      expect(find.text('Solanaceae'), findsWidgets);
      await disposeTree(tester);
    },
  );

  testWidgets('search filters the visible list', (tester) async {
    final repo = newTestRepository(db);
    await repo.addQuickVariety(label: 'Tomato');
    await repo.addQuickVariety(label: 'Bean');

    await tester.pumpWidget(
      wrapScreen(repository: repo, child: const InventoryListScreen()),
    );
    await tester.pumpAndSettle();

    await tester.enterText(find.byKey(const Key('inventory.search')), 'bea');
    await tester.pumpAndSettle();

    expect(find.text('Bean'), findsOneWidget);
    expect(find.text('Tomato'), findsNothing);
    await disposeTree(tester);
  });

  testWidgets('a category chip filters the list to that category', (
    tester,
  ) async {
    final repo = newTestRepository(db);
    await repo.addQuickVariety(label: 'Tomato', category: 'Solanaceae');
    await repo.addQuickVariety(label: 'Bean', category: 'Fabaceae');

    await tester.pumpWidget(
      wrapScreen(repository: repo, child: const InventoryListScreen()),
    );
    await tester.pumpAndSettle();

    await tester.tap(
      find.byKey(const Key('inventory.filter.category.Solanaceae')),
    );
    await tester.pumpAndSettle();

    expect(find.text('Tomato'), findsOneWidget);
    expect(find.text('Bean'), findsNothing);
    await disposeTree(tester);
  });

  testWidgets('a form chip filters the list to that lot form', (tester) async {
    final repo = newTestRepository(db);
    const oneUnit = Quantity(kind: QuantityKind.packet, count: 1);
    await repo.addQuickVariety(
      label: 'SeedOnly',
      quantity: oneUnit,
      lotType: LotType.seed,
    );
    await repo.addQuickVariety(
      label: 'PlantOnly',
      quantity: oneUnit,
      lotType: LotType.plant,
    );

    await tester.pumpWidget(
      wrapScreen(repository: repo, child: const InventoryListScreen()),
    );
    await tester.pumpAndSettle();

    await tester.tap(find.byKey(const Key('inventory.filter.type.seed')));
    await tester.pumpAndSettle();

    expect(find.text('SeedOnly'), findsOneWidget);
    expect(find.text('PlantOnly'), findsNothing);
    await disposeTree(tester);
  });

  testWidgets('clearing filters restores the full list', (tester) async {
    final repo = newTestRepository(db);
    await repo.addQuickVariety(label: 'Tomato', category: 'Solanaceae');
    await repo.addQuickVariety(label: 'Bean', category: 'Fabaceae');

    await tester.pumpWidget(
      wrapScreen(repository: repo, child: const InventoryListScreen()),
    );
    await tester.pumpAndSettle();

    await tester.tap(
      find.byKey(const Key('inventory.filter.category.Fabaceae')),
    );
    await tester.pumpAndSettle();
    expect(find.text('Tomato'), findsNothing);

    await tester.tap(find.byKey(const Key('inventory.filter.clear')));
    await tester.pumpAndSettle();
    expect(find.text('Tomato'), findsOneWidget);
    expect(find.text('Bean'), findsOneWidget);
    await disposeTree(tester);
  });

  testWidgets('a filter that hides everything shows the no-matches state', (
    tester,
  ) async {
    final repo = newTestRepository(db);
    const oneUnit = Quantity(kind: QuantityKind.packet, count: 1);
    await repo.addQuickVariety(
      label: 'SeedOnly',
      quantity: oneUnit,
      lotType: LotType.seed,
    );

    await tester.pumpWidget(
      wrapScreen(repository: repo, child: const InventoryListScreen()),
    );
    await tester.pumpAndSettle();

    // Search excludes the only item, so the list empties under an active query.
    await tester.enterText(
      find.byKey(const Key('inventory.search')),
      'zzz-nope',
    );
    await tester.tap(find.byKey(const Key('inventory.filter.type.seed')));
    await tester.pumpAndSettle();

    expect(find.text('No seeds match your filters.'), findsOneWidget);
    await disposeTree(tester);
  });

  testWidgets('meets the tap-target size guideline', (tester) async {
    final repo = newTestRepository(db);
    await repo.addQuickVariety(label: 'Tomato', category: 'Solanaceae');

    await tester.pumpWidget(
      wrapScreen(repository: repo, child: const InventoryListScreen()),
    );
    await tester.pumpAndSettle();

    await expectLater(tester, meetsGuideline(androidTapTargetGuideline));
    await expectLater(tester, meetsGuideline(iOSTapTargetGuideline));
    await disposeTree(tester);
  });

  testWidgets('renders in Spanish when the locale is es', (tester) async {
    final repo = newTestRepository(db);
    await tester.pumpWidget(
      wrapScreen(
        repository: repo,
        child: const InventoryListScreen(),
        locale: AppLocale.es,
      ),
    );
    await tester.pumpAndSettle();

    expect(find.text('Inventario'), findsOneWidget);
    await disposeTree(tester);
  });

  testWidgets(
    'shows a photo avatar instead of the initial when a photo exists',
    (tester) async {
      final repo = newTestRepository(db);
      await repo.addQuickVariety(label: 'Photographed', photoBytes: _tinyPng);

      await tester.pumpWidget(
        wrapScreen(repository: repo, child: const InventoryListScreen()),
      );
      await tester.pumpAndSettle();

      expect(find.text('Photographed'), findsOneWidget);
      expect(find.text('P'), findsNothing); // initial replaced by the photo
      await disposeTree(tester);
    },
  );
}
