// test/widget/manual_screen_test.dart
// ignore_for_file: prefer_const_constructors
//
// Widget tests untuk ManualScreen — halaman panduan perintah suara.
// Jalankan: flutter test test/widget/manual_screen_test.dart

// ignore_for_file: avoid_print

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

// ---------------------------------------------------------------------------
// Stubs — mereplikasi VoiceCommandKey dan ManualScreen tanpa plugin
// ---------------------------------------------------------------------------

enum VoiceCommandKey {
  openWalkguide,
  startWalkguide,
  stopWalkguide,
  callGuardian,
  openNotification,
  readAllNotif,
  openSos,
  sendSos,
  whereAmI,
  openActivity,
  openNavigation,
  openSettings,
  repeatLast,
  stopTts,
}

class VoiceCommandEntry {
  final VoiceCommandKey key;
  final String phrase;
  final String description;
  final String category;
  final bool enabled;

  const VoiceCommandEntry({
    required this.key,
    required this.phrase,
    required this.description,
    required this.category,
    this.enabled = true,
  });
}

/// Data perintah suara default (sama seperti di backend)
const List<VoiceCommandEntry> _defaultCommands = [
  VoiceCommandEntry(
    key: VoiceCommandKey.openWalkguide,
    phrase: 'Open Walkguide',
    description: 'Membuka layar WalkGuide',
    category: 'Navigasi',
  ),
  VoiceCommandEntry(
    key: VoiceCommandKey.startWalkguide,
    phrase: 'Start Walkguide',
    description: 'Memulai sesi navigasi WalkGuide',
    category: 'Navigasi',
  ),
  VoiceCommandEntry(
    key: VoiceCommandKey.stopWalkguide,
    phrase: 'Stop Walkguide',
    description: 'Menghentikan sesi navigasi',
    category: 'Navigasi',
  ),
  VoiceCommandEntry(
    key: VoiceCommandKey.callGuardian,
    phrase: 'Call Guardian',
    description: 'Menelepon Guardian',
    category: 'Komunikasi',
  ),
  VoiceCommandEntry(
    key: VoiceCommandKey.openNotification,
    phrase: 'Open Notifications',
    description: 'Membuka layar notifikasi',
    category: 'Navigasi',
  ),
  VoiceCommandEntry(
    key: VoiceCommandKey.readAllNotif,
    phrase: 'Read All My Notifications',
    description: 'TTS membacakan semua notifikasi',
    category: 'Aksesibilitas',
  ),
  VoiceCommandEntry(
    key: VoiceCommandKey.openSos,
    phrase: 'Open SOS',
    description: 'Membuka layar SOS',
    category: 'Darurat',
  ),
  VoiceCommandEntry(
    key: VoiceCommandKey.sendSos,
    phrase: 'Send SOS',
    description: 'Mengirim sinyal darurat',
    category: 'Darurat',
  ),
  VoiceCommandEntry(
    key: VoiceCommandKey.whereAmI,
    phrase: 'Where Am I',
    description: 'TTS membacakan lokasi saat ini',
    category: 'Lokasi',
  ),
  VoiceCommandEntry(
    key: VoiceCommandKey.openActivity,
    phrase: 'Open Activity Log',
    description: 'Membuka log aktivitas',
    category: 'Navigasi',
  ),
  VoiceCommandEntry(
    key: VoiceCommandKey.openNavigation,
    phrase: 'Open Navigation',
    description: 'Membuka layar navigasi',
    category: 'Navigasi',
  ),
  VoiceCommandEntry(
    key: VoiceCommandKey.openSettings,
    phrase: 'Open Settings',
    description: 'Membuka halaman pengaturan',
    category: 'Navigasi',
  ),
  VoiceCommandEntry(
    key: VoiceCommandKey.repeatLast,
    phrase: 'Repeat',
    description: 'Mengulangi TTS terakhir',
    category: 'Aksesibilitas',
  ),
  VoiceCommandEntry(
    key: VoiceCommandKey.stopTts,
    phrase: 'Stop',
    description: 'Menghentikan TTS',
    category: 'Aksesibilitas',
  ),
];

/// Stub ManualScreen yang lebih kaya dari versi asli untuk keperluan testing
class _StubManualScreen extends StatefulWidget {
  final List<VoiceCommandEntry> commands;
  final bool showSearch;

  const _StubManualScreen({
    this.commands = _defaultCommands,
    this.showSearch = false,
  });

  @override
  State<_StubManualScreen> createState() => _StubManualScreenState();
}

class _StubManualScreenState extends State<_StubManualScreen> {
  String _searchQuery = '';
  String? _selectedCategory;

  List<VoiceCommandEntry> get _filteredCommands {
    return widget.commands.where((cmd) {
      final matchesSearch = _searchQuery.isEmpty ||
          cmd.phrase.toLowerCase().contains(_searchQuery.toLowerCase()) ||
          cmd.description.toLowerCase().contains(_searchQuery.toLowerCase());
      final matchesCategory =
          _selectedCategory == null || cmd.category == _selectedCategory;
      return matchesSearch && matchesCategory;
    }).toList();
  }

  Set<String> get _categories => widget.commands.map((c) => c.category).toSet();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Panduan Suara'),
        actions: [
          IconButton(
            key: const Key('info_button'),
            icon: const Icon(Icons.info_outline),
            onPressed: () {
              showDialog(
                context: context,
                builder: (_) => AlertDialog(
                  key: const Key('info_dialog'),
                  title: const Text('Cara Penggunaan'),
                  content: const Text(
                    'Ucapkan perintah suara yang tertera untuk mengontrol aplikasi. '
                    'Pastikan mikrofon aktif.',
                  ),
                  actions: [
                    TextButton(
                      key: const Key('info_close_button'),
                      onPressed: () => Navigator.of(context).pop(),
                      child: const Text('Tutup'),
                    ),
                  ],
                ),
              );
            },
          ),
        ],
      ),
      body: Column(
        children: [
          // Header instruksi
          Container(
            key: const Key('header_banner'),
            width: double.infinity,
            padding: const EdgeInsets.all(12),
            color: Colors.blue.shade50,
            child: const Row(
              children: [
                Icon(Icons.mic, color: Colors.blue),
                SizedBox(width: 8),
                Expanded(
                  child: Text(
                    key: Key('header_text'),
                    'Ucapkan salah satu perintah di bawah ini untuk mengontrol WalkGuide',
                    style: TextStyle(color: Colors.blue),
                  ),
                ),
              ],
            ),
          ),

          // Search bar (opsional)
          if (widget.showSearch)
            Padding(
              padding: const EdgeInsets.all(12),
              child: TextField(
                key: const Key('search_field'),
                decoration: const InputDecoration(
                  hintText: 'Cari perintah...',
                  prefixIcon: Icon(Icons.search),
                  border: OutlineInputBorder(),
                ),
                onChanged: (value) => setState(() => _searchQuery = value),
              ),
            ),

          // Filter kategori
          if (_categories.length > 1)
            SizedBox(
              height: 44,
              child: ListView(
                key: const Key('category_filter'),
                scrollDirection: Axis.horizontal,
                padding: const EdgeInsets.symmetric(horizontal: 12),
                children: [
                  Padding(
                    padding: const EdgeInsets.only(right: 8),
                    child: FilterChip(
                      key: const Key('filter_all'),
                      label: const Text('Semua'),
                      selected: _selectedCategory == null,
                      onSelected: (_) =>
                          setState(() => _selectedCategory = null),
                    ),
                  ),
                  ..._categories.map((cat) => Padding(
                        padding: const EdgeInsets.only(right: 8),
                        child: FilterChip(
                          key: Key('filter_$cat'),
                          label: Text(cat),
                          selected: _selectedCategory == cat,
                          onSelected: (_) =>
                              setState(() => _selectedCategory = cat),
                        ),
                      )),
                ],
              ),
            ),

          // Jumlah perintah
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
            child: Align(
              alignment: Alignment.centerLeft,
              child: Text(
                key: const Key('command_count'),
                '${_filteredCommands.length} perintah tersedia',
                style: TextStyle(color: Colors.grey.shade600, fontSize: 13),
              ),
            ),
          ),

          // Daftar perintah
          Expanded(
            child: _filteredCommands.isEmpty
                ? Center(
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      children: const [
                        Icon(Icons.search_off,
                            size: 48,
                            color: Colors.grey,
                            key: Key('no_result_icon')),
                        SizedBox(height: 8),
                        Text(
                          key: Key('no_result_text'),
                          'Tidak ada perintah yang cocok',
                          style: TextStyle(color: Colors.grey),
                        ),
                      ],
                    ),
                  )
                : ListView.separated(
                    key: const Key('command_list'),
                    padding:
                        const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
                    itemCount: _filteredCommands.length,
                    separatorBuilder: (_, __) => const Divider(height: 1),
                    itemBuilder: (context, index) {
                      final cmd = _filteredCommands[index];
                      return ListTile(
                        key: Key('cmd_tile_${cmd.key.name}'),
                        leading: CircleAvatar(
                          backgroundColor: Colors.blue.shade100,
                          child: const Icon(Icons.record_voice_over,
                              color: Colors.blue),
                        ),
                        title: Text(
                          key: Key('cmd_phrase_${cmd.key.name}'),
                          '"${cmd.phrase}"',
                          style: const TextStyle(fontWeight: FontWeight.bold),
                        ),
                        subtitle: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text(
                              key: Key('cmd_desc_${cmd.key.name}'),
                              cmd.description,
                              style: TextStyle(
                                  fontSize: 12, color: Colors.grey.shade700),
                            ),
                            Container(
                              margin: const EdgeInsets.only(top: 4),
                              padding: const EdgeInsets.symmetric(
                                  horizontal: 8, vertical: 2),
                              decoration: BoxDecoration(
                                color: Colors.grey.shade200,
                                borderRadius: BorderRadius.circular(10),
                              ),
                              child: Text(
                                key: Key('cmd_category_${cmd.key.name}'),
                                cmd.category,
                                style: const TextStyle(fontSize: 11),
                              ),
                            ),
                          ],
                        ),
                        trailing: cmd.enabled
                            ? null
                            : const Icon(Icons.block,
                                color: Colors.grey,
                                size: 16,
                                key: Key('disabled_icon')),
                        isThreeLine: true,
                      );
                    },
                  ),
          ),
        ],
      ),
    );
  }
}

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

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

void main() {
  group('ManualScreen Widget Tests', () {
    // ── Rendering awal ─────────────────────────────────────────────────────

    group('Rendering awal', () {
      testWidgets('menampilkan AppBar dengan judul Panduan Suara',
          (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        expect(find.text('Panduan Suara'), findsOneWidget);
      });

      testWidgets('menampilkan header banner instruksi', (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        expect(find.byKey(const Key('header_banner')), findsOneWidget);
        expect(find.byKey(const Key('header_text')), findsOneWidget);
      });

      testWidgets('menampilkan daftar semua perintah default', (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        expect(find.byKey(const Key('command_list')), findsOneWidget);
      });

      testWidgets('menampilkan jumlah perintah yang benar (14)',
          (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        expect(find.text('14 perintah tersedia'), findsOneWidget);
      });

      testWidgets('menampilkan tombol info di AppBar', (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        expect(find.byKey(const Key('info_button')), findsOneWidget);
      });

      testWidgets('menampilkan filter kategori', (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        expect(find.byKey(const Key('category_filter')), findsOneWidget);
      });

      testWidgets('filter Semua tersedia', (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        expect(find.byKey(const Key('filter_all')), findsOneWidget);
      });
    });

    // ── Konten perintah ───────────────────────────────────────────────────

    group('Konten perintah suara', () {
      testWidgets('menampilkan tile untuk perintah Open Walkguide',
          (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        await tester.scrollUntilVisible(
          find.byKey(const Key('cmd_tile_openWalkguide')),
          200,
        );
        expect(find.byKey(const Key('cmd_tile_openWalkguide')), findsOneWidget);
      });

      testWidgets('menampilkan phrase perintah dalam tanda kutip',
          (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        expect(find.text('"Open Walkguide"'), findsOneWidget);
      });

      testWidgets('menampilkan deskripsi perintah', (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        expect(find.text('Membuka layar WalkGuide'), findsOneWidget);
      });

      testWidgets('menampilkan kategori perintah', (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        expect(find.byKey(const Key('cmd_category_openWalkguide')),
            findsOneWidget);
        expect(find.text('Navigasi'), findsAtLeastNWidgets(1));
      });

      testWidgets('menampilkan perintah Call Guardian', (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        expect(find.text('"Call Guardian"'), findsOneWidget);
      });

      testWidgets('menampilkan perintah Send SOS', (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        await tester.scrollUntilVisible(find.text('"Send SOS"'), 200);
        expect(find.text('"Send SOS"'), findsOneWidget);
      });

      testWidgets('menampilkan perintah Where Am I', (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        await tester.scrollUntilVisible(find.text('"Where Am I"'), 200);
        expect(find.text('"Where Am I"'), findsOneWidget);
      });

      testWidgets('menampilkan kategori Darurat untuk Send SOS',
          (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        await tester.scrollUntilVisible(
            find.byKey(const Key('cmd_category_sendSos')), 200);
        expect(find.byKey(const Key('cmd_category_sendSos')), findsOneWidget);
      });
    });

    // ── Dialog info ───────────────────────────────────────────────────────

    group('Dialog info penggunaan', () {
      testWidgets('tap info button membuka dialog', (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));

        await tester.tap(find.byKey(const Key('info_button')));
        await tester.pumpAndSettle();

        expect(find.byKey(const Key('info_dialog')), findsOneWidget);
        expect(find.text('Cara Penggunaan'), findsOneWidget);
      });

      testWidgets('dialog berisi teks instruksi', (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));

        await tester.tap(find.byKey(const Key('info_button')));
        await tester.pumpAndSettle();

        expect(find.textContaining('mikrofon'), findsOneWidget);
      });

      testWidgets('tombol Tutup menutup dialog', (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));

        await tester.tap(find.byKey(const Key('info_button')));
        await tester.pumpAndSettle();

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

        await tester.tap(find.byKey(const Key('info_close_button')));
        await tester.pumpAndSettle();

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

    // ── Filter kategori ───────────────────────────────────────────────────

    group('Filter kategori', () {
      testWidgets('tap filter Darurat menampilkan hanya perintah darurat',
          (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));

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

        // Hanya Open SOS dan Send SOS
        expect(find.byKey(const Key('command_count')), findsOneWidget);
        expect(find.text('2 perintah tersedia'), findsOneWidget);
      });

      testWidgets('tap filter Komunikasi menampilkan hanya Call Guardian',
          (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));

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

        expect(find.text('1 perintah tersedia'), findsOneWidget);
      });

      testWidgets('tap filter Semua menampilkan kembali semua perintah',
          (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));

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

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

        expect(find.text('14 perintah tersedia'), findsOneWidget);
      });

      testWidgets('tap filter Aksesibilitas menampilkan 3 perintah',
          (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));

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

        expect(find.text('3 perintah tersedia'), findsOneWidget);
      });
    });

    // ── Search ────────────────────────────────────────────────────────────

    group('Pencarian perintah (showSearch=true)', () {
      testWidgets('menampilkan search field saat showSearch=true',
          (tester) async {
        await tester.pumpWidget(
          makeTestable(const _StubManualScreen(showSearch: true)),
        );
        expect(find.byKey(const Key('search_field')), findsOneWidget);
      });

      testWidgets('tidak menampilkan search field secara default',
          (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        expect(find.byKey(const Key('search_field')), findsNothing);
      });

      testWidgets('search "SOS" memfilter perintah SOS', (tester) async {
        await tester.pumpWidget(
          makeTestable(const _StubManualScreen(showSearch: true)),
        );

        await tester.enterText(find.byKey(const Key('search_field')), 'SOS');
        await tester.pump();

        expect(find.text('2 perintah tersedia'), findsOneWidget);
      });

      testWidgets('search tanpa hasil menampilkan empty state', (tester) async {
        await tester.pumpWidget(
          makeTestable(const _StubManualScreen(showSearch: true)),
        );

        await tester.enterText(
            find.byKey(const Key('search_field')), 'xyz tidak ada');
        await tester.pump();

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

      testWidgets('search "guardian" menemukan Call Guardian', (tester) async {
        await tester.pumpWidget(
          makeTestable(const _StubManualScreen(showSearch: true)),
        );

        await tester.enterText(
            find.byKey(const Key('search_field')), 'guardian');
        await tester.pump();

        expect(find.text('"Call Guardian"'), findsOneWidget);
      });
    });

    // ── Perintah disabled ─────────────────────────────────────────────────

    group('Perintah disabled', () {
      testWidgets('perintah disabled menampilkan icon block', (tester) async {
        final disabledCommands = [
          const VoiceCommandEntry(
            key: VoiceCommandKey.callGuardian,
            phrase: 'Call Guardian',
            description: 'Test disabled',
            category: 'Komunikasi',
            enabled: false,
          ),
        ];
        await tester.pumpWidget(makeTestable(
          _StubManualScreen(commands: disabledCommands),
        ));

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

      testWidgets('perintah enabled tidak menampilkan icon block',
          (tester) async {
        await tester.pumpWidget(makeTestable(const _StubManualScreen()));
        expect(find.byKey(const Key('disabled_icon')), findsNothing);
      });
    });

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

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

        await tester.pumpWidget(makeTestable(const _StubManualScreen()));

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

      testWidgets('tidak overflow pada layar 428x926 (iPhone 14 Pro Max)',
          (tester) async {
        tester.view.physicalSize = const Size(428, 926);
        tester.view.devicePixelRatio = 1.0;
        addTearDown(tester.view.resetPhysicalSize);

        await tester.pumpWidget(makeTestable(const _StubManualScreen()));

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