// Generates Play Store promotional screenshots for all three device classes.
//
// Run with:
//   fvm flutter test test/screenshot_automation_test.dart --update-goldens
//
// Output: screenshots/{phone,tablet_7in,tablet_10in}/{light,dark}/<scene>.png
// at the repository root (one directory above test/).

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/misc.dart' show Override;
import 'package:flutter_test/flutter_test.dart';
import 'package:go_router/go_router.dart';

import 'package:sharedinbox/core/models/account.dart';
import 'package:sharedinbox/core/models/email.dart';
import 'package:sharedinbox/core/models/mailbox.dart';
import 'package:sharedinbox/di.dart';
import 'package:sharedinbox/ui/screens/email_list_screen.dart';

import 'widget/helpers.dart';

// ---------------------------------------------------------------------------
// Device configurations
// ---------------------------------------------------------------------------

typedef _Device = ({String name, double width, double height, double dpr});

const _devices = <_Device>[
  (name: 'phone', width: 1080.0, height: 1920.0, dpr: 3.0),
  (name: 'tablet_7in', width: 1200.0, height: 1920.0, dpr: 2.0),
  (name: 'tablet_10in', width: 1600.0, height: 2560.0, dpr: 2.0),
];

// ---------------------------------------------------------------------------
// Sample data — fixed date so golden files are stable between runs
// ---------------------------------------------------------------------------

const _kAccount = Account(
  id: 'acc-1',
  displayName: 'Alice',
  email: 'alice@sharedinbox.de',
  imapHost: 'imap.sharedinbox.de',
  smtpHost: 'smtp.sharedinbox.de',
);

final _kDate = DateTime(2025, 5, 14, 10, 30);

Email _email({
  required String id,
  required String subject,
  required String fromName,
  required String fromEmail,
  bool isSeen = true,
  bool isFlagged = false,
  bool hasAttachment = false,
  String? preview,
}) =>
    Email(
      id: id,
      accountId: 'acc-1',
      mailboxPath: 'INBOX',
      uid: int.parse(id.split(':').last),
      subject: subject,
      receivedAt: _kDate,
      sentAt: _kDate,
      from: [EmailAddress(name: fromName, email: fromEmail)],
      to: const [EmailAddress(name: 'Alice', email: 'alice@sharedinbox.de')],
      cc: const [],
      isSeen: isSeen,
      isFlagged: isFlagged,
      hasAttachment: hasAttachment,
      preview: preview,
    );

final _sampleEmails = [
  _email(
    id: 'acc-1:1',
    subject: 'Re: Project kick-off next week',
    fromName: 'Maria Hoffmann',
    fromEmail: 'maria@corp.example',
    isSeen: false,
    preview: 'Sounds great! I will prepare the slides beforehand.',
  ),
  _email(
    id: 'acc-1:2',
    subject: 'Your invoice #2024-0312 is ready',
    fromName: 'Billing',
    fromEmail: 'billing@service.example',
    isSeen: false,
    preview: 'Your invoice for May is attached as a PDF.',
  ),
  _email(
    id: 'acc-1:3',
    subject: 'Team lunch — Friday 12:30',
    fromName: 'Thomas Müller',
    fromEmail: 'thomas@corp.example',
    isFlagged: true,
    preview: 'The Italian place on Main Street. RSVP by Thursday please.',
  ),
  _email(
    id: 'acc-1:4',
    subject: 'Quarterly review agenda',
    fromName: 'HR Team',
    fromEmail: 'hr@corp.example',
    preview:
        "Please find the agenda for next week's quarterly review attached.",
  ),
  _email(
    id: 'acc-1:5',
    subject: 'Weekend hiking trip — photos inside',
    fromName: 'Jonas Weber',
    fromEmail: 'jonas@personal.example',
    hasAttachment: true,
    preview: 'Had such a great time! Here are the photos from Saturday.',
  ),
  _email(
    id: 'acc-1:6',
    subject: 'Reminder: dentist appointment tomorrow',
    fromName: 'City Dental',
    fromEmail: 'noreply@citydental.example',
    preview: 'Your appointment is confirmed for Thursday at 14:00.',
  ),
  _email(
    id: 'acc-1:7',
    subject: 'Re: Feedback on the draft',
    fromName: 'Laura Schmidt',
    fromEmail: 'laura@corp.example',
    isSeen: false,
    preview: 'I left some comments on page 3. Overall it looks really solid!',
  ),
  _email(
    id: 'acc-1:8',
    subject: 'Flight confirmation PNR XYZ123',
    fromName: 'Sunshine Airlines',
    fromEmail: 'noreply@airline.example',
    preview:
        'Your booking is confirmed. Check-in opens 24 hours before departure.',
  ),
];

final _sampleMailboxes = [
  const Mailbox(
    id: 'acc-1:INBOX',
    accountId: 'acc-1',
    path: 'INBOX',
    name: 'INBOX',
    role: 'inbox',
    unreadCount: 3,
    totalCount: 8,
  ),
  const Mailbox(
    id: 'acc-1:Sent',
    accountId: 'acc-1',
    path: 'Sent',
    name: 'Sent',
    role: 'sent',
    unreadCount: 0,
    totalCount: 42,
  ),
  const Mailbox(
    id: 'acc-1:Drafts',
    accountId: 'acc-1',
    path: 'Drafts',
    name: 'Drafts',
    role: 'drafts',
    unreadCount: 0,
    totalCount: 1,
  ),
  const Mailbox(
    id: 'acc-1:Trash',
    accountId: 'acc-1',
    path: 'Trash',
    name: 'Trash',
    role: 'trash',
    unreadCount: 0,
    totalCount: 7,
  ),
];

// Email shown in the detail scene.
final _detailEmail = _email(
  id: 'acc-1:1',
  subject: 'Re: Project kick-off next week',
  fromName: 'Maria Hoffmann',
  fromEmail: 'maria@corp.example',
);

const _detailBody = EmailBody(
  emailId: 'acc-1:1',
  attachments: [],
  textBody: 'Hi Alice,\n\n'
      'Sounds great! I will prepare the slides beforehand so we have '
      'something concrete to discuss.\n\n'
      'Looking forward to meeting everyone!\n\n'
      'Best,\nMaria',
);

// Emails shown when the user searches for "invoice".
final _searchResults = [
  _email(
    id: 'acc-1:2',
    subject: 'Your invoice #2024-0312 is ready',
    fromName: 'Billing',
    fromEmail: 'billing@service.example',
    isSeen: false,
  ),
  _email(
    id: 'acc-1:9',
    subject: 'Invoice for March services',
    fromName: 'Cloud Services',
    fromEmail: 'noreply@cloud.example',
  ),
];

// ---------------------------------------------------------------------------
// Provider override sets for each scene
// ---------------------------------------------------------------------------

List<Override> _inboxOverrides() => [
      accountRepositoryProvider.overrideWithValue(
        FakeAccountRepository([_kAccount]),
      ),
      mailboxRepositoryProvider.overrideWithValue(
        FakeMailboxRepository(_sampleMailboxes),
      ),
      emailRepositoryProvider.overrideWithValue(
        FakeEmailRepository(emails: _sampleEmails),
      ),
      draftRepositoryProvider.overrideWithValue(FakeDraftRepository()),
      searchHistoryRepositoryProvider.overrideWithValue(
        FakeSearchHistoryRepository(),
      ),
      syncLastErrorProvider.overrideWith((ref, _) => Stream.value(null)),
    ];

List<Override> _detailOverrides() => [
      accountRepositoryProvider.overrideWithValue(
        FakeAccountRepository([_kAccount]),
      ),
      mailboxRepositoryProvider.overrideWithValue(
        FakeMailboxRepository(_sampleMailboxes),
      ),
      emailRepositoryProvider.overrideWithValue(
        FakeEmailRepository(
          emails: _sampleEmails,
          emailDetail: _detailEmail,
          emailBody: _detailBody,
        ),
      ),
      draftRepositoryProvider.overrideWithValue(FakeDraftRepository()),
      syncLastErrorProvider.overrideWith((ref, _) => Stream.value(null)),
    ];

List<Override> _composeOverrides() => [
      accountRepositoryProvider.overrideWithValue(
        FakeAccountRepository([_kAccount]),
      ),
      mailboxRepositoryProvider.overrideWithValue(
        FakeMailboxRepository(_sampleMailboxes),
      ),
      emailRepositoryProvider.overrideWithValue(
        FakeEmailRepository(emails: _sampleEmails),
      ),
      draftRepositoryProvider.overrideWithValue(FakeDraftRepository()),
      searchHistoryRepositoryProvider.overrideWithValue(
        FakeSearchHistoryRepository(),
      ),
      syncLastErrorProvider.overrideWith((ref, _) => Stream.value(null)),
    ];

List<Override> _mailboxOverrides() => [
      accountRepositoryProvider.overrideWithValue(
        FakeAccountRepository([_kAccount]),
      ),
      mailboxRepositoryProvider.overrideWithValue(
        FakeMailboxRepository(_sampleMailboxes),
      ),
      emailRepositoryProvider.overrideWithValue(FakeEmailRepository()),
      draftRepositoryProvider.overrideWithValue(FakeDraftRepository()),
      syncLastErrorProvider.overrideWith((ref, _) => Stream.value(null)),
    ];

List<Override> _searchOverrides() => [
      accountRepositoryProvider.overrideWithValue(
        FakeAccountRepository([_kAccount]),
      ),
      mailboxRepositoryProvider.overrideWithValue(
        FakeMailboxRepository(_sampleMailboxes),
      ),
      emailRepositoryProvider.overrideWithValue(
        FakeEmailRepository(
          emails: _sampleEmails,
          searchResults: _searchResults,
        ),
      ),
      draftRepositoryProvider.overrideWithValue(FakeDraftRepository()),
      searchHistoryRepositoryProvider.overrideWithValue(
        FakeSearchHistoryRepository(),
      ),
      syncLastErrorProvider.overrideWith((ref, _) => Stream.value(null)),
    ];

// ---------------------------------------------------------------------------
// Tests — 3 devices × 2 themes × 5 scenes = 30 golden files
// ---------------------------------------------------------------------------

void main() {
  for (final device in _devices) {
    for (final themeMode in [ThemeMode.light, ThemeMode.dark]) {
      final themeName = themeMode == ThemeMode.light ? 'light' : 'dark';
      // Golden files are stored relative to this test file (test/).
      // The ../  prefix places them at repo root under screenshots/.
      final dir = '../screenshots/${device.name}/$themeName';
      final prefix = '${device.name}_$themeName';

      group('${device.name}/$themeName', () {
        void setDevice(WidgetTester tester) {
          tester.view.physicalSize = Size(device.width, device.height);
          tester.view.devicePixelRatio = device.dpr;
          addTearDown(tester.view.reset);
        }

        testWidgets('inbox_list', (tester) async {
          setDevice(tester);
          await tester.pumpWidget(
            buildApp(
              debugShowCheckedModeBanner: false,
              initialLocation: '/accounts/acc-1/mailboxes/INBOX/emails',
              overrides: _inboxOverrides(),
              themeMode: themeMode,
            ),
          );
          await tester.pumpAndSettle();
          await expectLater(
            find.byType(MaterialApp),
            matchesGoldenFile('$dir/${prefix}_inbox_list.png'),
          );
        });

        testWidgets('email_detail', (tester) async {
          setDevice(tester);
          await tester.pumpWidget(
            buildApp(
              // The colon in "acc-1:1" must be percent-encoded in the URL.
              initialLocation:
                  '/accounts/acc-1/mailboxes/INBOX/emails/acc-1%3A1',
              overrides: _detailOverrides(),
              themeMode: themeMode,
            ),
          );
          await tester.pumpAndSettle();
          await expectLater(
            find.byType(MaterialApp),
            matchesGoldenFile('$dir/${prefix}_email_detail.png'),
          );
        });

        testWidgets('compose', (tester) async {
          setDevice(tester);
          // Start at the inbox, then navigate to compose with pre-fill extras
          // so GoRouter can pass them to ComposeScreen via state.extra.
          await tester.pumpWidget(
            buildApp(
              debugShowCheckedModeBanner: false,
              initialLocation: '/accounts/acc-1/mailboxes/INBOX/emails',
              overrides: _composeOverrides(),
              themeMode: themeMode,
            ),
          );
          await tester.pumpAndSettle();
          GoRouter.of(tester.element(find.byType(EmailListScreen))).go(
            '/compose',
            extra: <String, dynamic>{
              'accountId': 'acc-1',
              'prefillTo': 'thomas@corp.example',
              'prefillSubject': 'Re: Team lunch — Friday 12:30',
              'prefillBody':
                  'Hi Thomas,\n\nCount me in! See you on Friday.\n\nBest,\nAlice',
            },
          );
          await tester.pumpAndSettle();
          await expectLater(
            find.byType(MaterialApp),
            matchesGoldenFile('$dir/${prefix}_compose.png'),
          );
        });

        testWidgets('mailbox_list', (tester) async {
          setDevice(tester);
          await tester.pumpWidget(
            buildApp(
              debugShowCheckedModeBanner: false,
              initialLocation: '/accounts/acc-1/mailboxes',
              overrides: _mailboxOverrides(),
              themeMode: themeMode,
            ),
          );
          await tester.pumpAndSettle();
          await expectLater(
            find.byType(MaterialApp),
            matchesGoldenFile('$dir/${prefix}_mailbox_list.png'),
          );
        });

        testWidgets('search_results', (tester) async {
          setDevice(tester);
          await tester.pumpWidget(
            buildApp(
              debugShowCheckedModeBanner: false,
              initialLocation: '/accounts/acc-1/mailboxes/INBOX/emails',
              overrides: _searchOverrides(),
              themeMode: themeMode,
            ),
          );
          await tester.pumpAndSettle();
          await tester.enterText(find.byType(SearchBar), 'invoice');
          await tester.testTextInput.receiveAction(TextInputAction.search);
          await tester.pumpAndSettle();
          await expectLater(
            find.byType(MaterialApp),
            matchesGoldenFile('$dir/${prefix}_search_results.png'),
          );
        });
      });
    }
  }
}
