// test/widget/notification_screen_test.dart
// ignore_for_file: prefer_const_constructors
//
// Widget tests untuk NotificationScreen — menampilkan notifikasi dari Guardian.
// Jalankan: flutter test test/widget/notification_screen_test.dart

// ignore_for_file: avoid_print

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

// ---------------------------------------------------------------------------
// Stubs / Models
// ---------------------------------------------------------------------------

enum NotifType { text, voiceNote }

class NotifItem {
  final int id;
  final NotifType type;
  final String content;
  final bool isRead;
  final DateTime createdAt;
  final int? voiceNoteDuration;

  const NotifItem({
    required this.id,
    required this.type,
    required this.content,
    required this.isRead,
    required this.createdAt,
    this.voiceNoteDuration,
  });
}

/// Stub NotificationScreen yang mereplikasi UI asli tanpa DI / API calls
class _StubNotificationScreen extends StatefulWidget {
  final List<NotifItem> notifications;
  final bool isLoading;
  final String? errorMessage;

  const _StubNotificationScreen({
    this.notifications = const [],
    this.isLoading = false,
    this.errorMessage,
  });

  @override
  State<_StubNotificationScreen> createState() =>
      _StubNotificationScreenState();
}

class _StubNotificationScreenState extends State<_StubNotificationScreen> {
  late List<NotifItem> _items;
  bool _markingAll = false;

  @override
  void initState() {
    super.initState();
    _items = List.from(widget.notifications);
  }

  void _markAllRead() {
    setState(() {
      _markingAll = true;
      _items = _items
          .map((e) => NotifItem(
                id: e.id,
                type: e.type,
                content: e.content,
                isRead: true,
                createdAt: e.createdAt,
                voiceNoteDuration: e.voiceNoteDuration,
              ))
          .toList();
      _markingAll = false;
    });
  }

  int get _unreadCount => _items.where((e) => !e.isRead).length;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Row(
          children: [
            const Text('Notifikasi'),
            if (_unreadCount > 0) ...[
              const SizedBox(width: 8),
              Container(
                key: const Key('unread_badge'),
                padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
                decoration: BoxDecoration(
                  color: Colors.red,
                  borderRadius: BorderRadius.circular(12),
                ),
                child: Text(
                  '$_unreadCount',
                  style: const TextStyle(color: Colors.white, fontSize: 12),
                ),
              ),
            ],
          ],
        ),
        actions: [
          if (_items.any((e) => !e.isRead))
            TextButton(
              key: const Key('mark_all_read_button'),
              onPressed: _markingAll ? null : _markAllRead,
              child: const Text('Tandai Semua Dibaca'),
            ),
        ],
      ),
      body: widget.isLoading
          ? const Center(
              child: CircularProgressIndicator(key: Key('loading_indicator')))
          : widget.errorMessage != null
              ? Center(
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      const Icon(Icons.error_outline,
                          size: 48, color: Colors.red, key: Key('error_icon')),
                      const SizedBox(height: 8),
                      Text(
                        key: const Key('error_message'),
                        widget.errorMessage!,
                        textAlign: TextAlign.center,
                      ),
                      const SizedBox(height: 16),
                      ElevatedButton(
                        key: const Key('retry_button'),
                        onPressed: () {},
                        child: const Text('Coba Lagi'),
                      ),
                    ],
                  ),
                )
              : _items.isEmpty
                  ? Center(
                      child: Column(
                        mainAxisSize: MainAxisSize.min,
                        children: const [
                          Icon(Icons.notifications_none,
                              size: 64,
                              color: Colors.grey,
                              key: Key('empty_icon')),
                          SizedBox(height: 8),
                          Text(
                            key: Key('empty_text'),
                            'Tidak ada notifikasi',
                            style: TextStyle(color: Colors.grey),
                          ),
                        ],
                      ),
                    )
                  : RefreshIndicator(
                      key: const Key('refresh_indicator'),
                      onRefresh: () async {},
                      child: ListView.separated(
                        key: const Key('notification_list'),
                        padding: const EdgeInsets.all(12),
                        itemCount: _items.length,
                        separatorBuilder: (_, __) => const Divider(height: 1),
                        itemBuilder: (context, index) {
                          final item = _items[index];
                          return _NotifTile(
                            key: Key('notif_tile_${item.id}'),
                            item: item,
                          );
                        },
                      ),
                    ),
    );
  }
}

class _NotifTile extends StatelessWidget {
  final NotifItem item;

  const _NotifTile({super.key, required this.item});

  @override
  Widget build(BuildContext context) {
    return ListTile(
      leading: CircleAvatar(
        backgroundColor:
            item.isRead ? Colors.grey.shade200 : Colors.blue.shade100,
        child: Icon(
          item.type == NotifType.voiceNote ? Icons.mic : Icons.message,
          key: Key('notif_icon_${item.id}'),
          color: item.isRead ? Colors.grey : Colors.blue,
        ),
      ),
      title: Text(
        key: Key('notif_content_${item.id}'),
        item.content,
        maxLines: 2,
        overflow: TextOverflow.ellipsis,
        style: TextStyle(
          fontWeight: item.isRead ? FontWeight.normal : FontWeight.bold,
        ),
      ),
      subtitle: Row(
        children: [
          Text(
            key: Key('notif_type_${item.id}'),
            item.type == NotifType.voiceNote
                ? 'Voice Note${item.voiceNoteDuration != null ? ' (${item.voiceNoteDuration}s)' : ''}'
                : 'Pesan Teks',
            style: TextStyle(fontSize: 12, color: Colors.grey.shade600),
          ),
        ],
      ),
      trailing: item.isRead
          ? null
          : Container(
              key: Key('unread_dot_${item.id}'),
              width: 8,
              height: 8,
              decoration: const BoxDecoration(
                color: Colors.blue,
                shape: BoxShape.circle,
              ),
            ),
    );
  }
}

Widget makeTestable(Widget child) => MaterialApp(home: child);

// Fixtures
final _textNotif = NotifItem(
  id: 1,
  type: NotifType.text,
  content: 'Hati-hati di persimpangan depan',
  isRead: false,
  createdAt: DateTime(2025, 5, 10, 10, 30),
);

final _voiceNotif = NotifItem(
  id: 2,
  type: NotifType.voiceNote,
  content: 'Voice note dari Guardian',
  isRead: false,
  createdAt: DateTime(2025, 5, 10, 11, 0),
  voiceNoteDuration: 12,
);

final _readNotif = NotifItem(
  id: 3,
  type: NotifType.text,
  content: 'Sudah dibaca sebelumnya',
  isRead: true,
  createdAt: DateTime(2025, 5, 9, 9, 0),
);

// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------

void main() {
  group('NotificationScreen Widget Tests', () {
    // ── Loading state ─────────────────────────────────────────────────────

    group('Loading state', () {
      testWidgets('menampilkan loading indicator saat isLoading=true',
          (tester) async {
        await tester.pumpWidget(
          makeTestable(const _StubNotificationScreen(isLoading: true)),
        );

        expect(find.byKey(const Key('loading_indicator')), findsOneWidget);
      });

      testWidgets('menyembunyikan list saat loading', (tester) async {
        await tester.pumpWidget(
          makeTestable(const _StubNotificationScreen(isLoading: true)),
        );

        expect(find.byKey(const Key('notification_list')), findsNothing);
      });
    });

    // ── Error state ───────────────────────────────────────────────────────

    group('Error state', () {
      testWidgets('menampilkan error message saat ada error', (tester) async {
        await tester.pumpWidget(makeTestable(
          const _StubNotificationScreen(
              errorMessage: 'Gagal memuat notifikasi'),
        ));

        expect(find.byKey(const Key('error_message')), findsOneWidget);
        expect(find.text('Gagal memuat notifikasi'), findsOneWidget);
      });

      testWidgets('menampilkan icon error saat ada error', (tester) async {
        await tester.pumpWidget(makeTestable(
          const _StubNotificationScreen(errorMessage: 'Koneksi gagal'),
        ));

        expect(find.byKey(const Key('error_icon')), findsOneWidget);
      });

      testWidgets('menampilkan tombol Retry saat error', (tester) async {
        await tester.pumpWidget(makeTestable(
          const _StubNotificationScreen(errorMessage: 'Timeout'),
        ));

        expect(find.byKey(const Key('retry_button')), findsOneWidget);
      });
    });

    // ── Empty state ───────────────────────────────────────────────────────

    group('Empty state', () {
      testWidgets('menampilkan empty state saat tidak ada notifikasi',
          (tester) async {
        await tester.pumpWidget(makeTestable(const _StubNotificationScreen()));

        expect(find.byKey(const Key('empty_text')), findsOneWidget);
        expect(find.text('Tidak ada notifikasi'), findsOneWidget);
      });

      testWidgets('menampilkan icon empty state', (tester) async {
        await tester.pumpWidget(makeTestable(const _StubNotificationScreen()));

        expect(find.byKey(const Key('empty_icon')), findsOneWidget);
      });

      testWidgets('tidak menampilkan tombol mark all read saat list kosong',
          (tester) async {
        await tester.pumpWidget(makeTestable(const _StubNotificationScreen()));

        expect(find.byKey(const Key('mark_all_read_button')), findsNothing);
      });
    });

    // ── Daftar notifikasi ─────────────────────────────────────────────────

    group('Daftar notifikasi', () {
      testWidgets('menampilkan semua notifikasi dalam list', (tester) async {
        await tester.pumpWidget(makeTestable(
          _StubNotificationScreen(
              notifications: [_textNotif, _voiceNotif, _readNotif]),
        ));

        expect(find.byKey(const Key('notification_list')), findsOneWidget);
        expect(find.byKey(const Key('notif_tile_1')), findsOneWidget);
        expect(find.byKey(const Key('notif_tile_2')), findsOneWidget);
        expect(find.byKey(const Key('notif_tile_3')), findsOneWidget);
      });

      testWidgets('menampilkan konten notifikasi teks dengan benar',
          (tester) async {
        await tester.pumpWidget(makeTestable(
          _StubNotificationScreen(notifications: [_textNotif]),
        ));

        expect(find.text('Hati-hati di persimpangan depan'), findsOneWidget);
      });

      testWidgets('menampilkan badge unread count di AppBar', (tester) async {
        await tester.pumpWidget(makeTestable(
          _StubNotificationScreen(notifications: [_textNotif, _voiceNotif]),
        ));

        expect(find.byKey(const Key('unread_badge')), findsOneWidget);
        expect(find.text('2'), findsOneWidget);
      });

      testWidgets('tidak menampilkan unread badge saat semua sudah dibaca',
          (tester) async {
        await tester.pumpWidget(makeTestable(
          _StubNotificationScreen(notifications: [_readNotif]),
        ));

        expect(find.byKey(const Key('unread_badge')), findsNothing);
      });

      testWidgets('menampilkan unread dot untuk notifikasi belum dibaca',
          (tester) async {
        await tester.pumpWidget(makeTestable(
          _StubNotificationScreen(notifications: [_textNotif]),
        ));

        expect(find.byKey(const Key('unread_dot_1')), findsOneWidget);
      });

      testWidgets('tidak menampilkan unread dot untuk notif sudah dibaca',
          (tester) async {
        await tester.pumpWidget(makeTestable(
          _StubNotificationScreen(notifications: [_readNotif]),
        ));

        expect(find.byKey(const Key('unread_dot_3')), findsNothing);
      });

      testWidgets('menampilkan jenis voice note dengan durasi', (tester) async {
        await tester.pumpWidget(makeTestable(
          _StubNotificationScreen(notifications: [_voiceNotif]),
        ));

        expect(find.textContaining('Voice Note'), findsOneWidget);
        expect(find.textContaining('12s'), findsOneWidget);
      });

      testWidgets('menampilkan icon mic untuk voice note', (tester) async {
        await tester.pumpWidget(makeTestable(
          _StubNotificationScreen(notifications: [_voiceNotif]),
        ));

        expect(find.byKey(const Key('notif_icon_2')), findsOneWidget);
      });
    });

    // ── Mark all read ─────────────────────────────────────────────────────

    group('Mark all read', () {
      testWidgets('menampilkan tombol mark all read saat ada unread',
          (tester) async {
        await tester.pumpWidget(makeTestable(
          _StubNotificationScreen(notifications: [_textNotif, _voiceNotif]),
        ));

        expect(find.byKey(const Key('mark_all_read_button')), findsOneWidget);
      });

      testWidgets('tap mark all read menghapus semua unread dot',
          (tester) async {
        await tester.pumpWidget(makeTestable(
          _StubNotificationScreen(notifications: [_textNotif, _voiceNotif]),
        ));

        expect(find.byKey(const Key('unread_dot_1')), findsOneWidget);
        expect(find.byKey(const Key('unread_dot_2')), findsOneWidget);

        await tester.tap(find.byKey(const Key('mark_all_read_button')));
        await tester.pump();

        expect(find.byKey(const Key('unread_dot_1')), findsNothing);
        expect(find.byKey(const Key('unread_dot_2')), findsNothing);
      });

      testWidgets('tap mark all read menghapus unread badge', (tester) async {
        await tester.pumpWidget(makeTestable(
          _StubNotificationScreen(notifications: [_textNotif]),
        ));

        expect(find.byKey(const Key('unread_badge')), findsOneWidget);

        await tester.tap(find.byKey(const Key('mark_all_read_button')));
        await tester.pump();

        expect(find.byKey(const Key('unread_badge')), findsNothing);
      });

      testWidgets('tombol mark all read hilang setelah semua dibaca',
          (tester) async {
        await tester.pumpWidget(makeTestable(
          _StubNotificationScreen(notifications: [_textNotif]),
        ));

        await tester.tap(find.byKey(const Key('mark_all_read_button')));
        await tester.pump();

        expect(find.byKey(const Key('mark_all_read_button')), findsNothing);
      });
    });

    // ── RefreshIndicator ──────────────────────────────────────────────────

    group('Pull to refresh', () {
      testWidgets('terdapat RefreshIndicator di daftar notifikasi',
          (tester) async {
        await tester.pumpWidget(makeTestable(
          _StubNotificationScreen(notifications: [_textNotif]),
        ));

        expect(find.byKey(const Key('refresh_indicator')), findsOneWidget);
      });
    });

    // ── Layout responsif ──────────────────────────────────────────────────

    group('Responsif', () {
      testWidgets('tidak overflow pada layar kecil', (tester) async {
        tester.view.physicalSize = const Size(360, 640);
        tester.view.devicePixelRatio = 1.0;
        addTearDown(tester.view.resetPhysicalSize);

        await tester.pumpWidget(makeTestable(
          _StubNotificationScreen(
              notifications: [_textNotif, _voiceNotif, _readNotif]),
        ));

        expect(tester.takeException(), isNull);
      });
    });
  });
}
