import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hugeicons/hugeicons.dart';
import 'package:intl/intl.dart';

import '../../core/sacred_tokens.dart';
import '../../providers.dart';
import '../../data/services/sync_service.dart';
import '../../data/services/myquran_service.dart';
import '../../data/services/sound_service.dart';
import 'package:file_picker/file_picker.dart';
import 'dart:io';

class AdminScreen extends ConsumerStatefulWidget {
  final int initialTab;
  final bool focusSelectedTabOnOpen;

  const AdminScreen({
    super.key,
    this.initialTab = 0,
    this.focusSelectedTabOnOpen = false,
  });

  @override
  ConsumerState<AdminScreen> createState() => _AdminScreenState();
}

class _AdminScreenState extends ConsumerState<AdminScreen> {
  final _masjidNameCtrl = TextEditingController();
  final _masjidAddressCtrl = TextEditingController();
  final _cityCtrl = TextEditingController(); // Displays DisplayName or CityID
  
  final _mainDurCtrl = TextEditingController();
  final _slideDurCtrl = TextEditingController();
  
  int _selectedTab = 0;
  bool _isSyncing = false;
  int _textScaleIndex = 1;
  List<String> _slideshowImages = [];
  bool _useUnsplash = false;
  final _unsplashKeywordCtrl = TextEditingController();
  final _unsplashRotationCtrl = TextEditingController();

  // Branded background
  String? _brandedBgImage;

  // Running text repeater
  String _marqueeAnimType = 'marquee';
  List<String> _runningTexts = [];
  List<int> _runningTextDurations = [];

  // Granular text group scales
  double _scaleCardLabel = 1.0;
  double _scaleCardBody = 1.0;
  double _scaleRunningText = 1.0;

  // Jumat fields
  final _khatibCtrl = TextEditingController();
  final _imamCtrl = TextEditingController();

  // Iqomah Jeda fields
  final _iqomahSubuhCtrl = TextEditingController();
  final _iqomahDzuhurCtrl = TextEditingController();
  final _iqomahAsharCtrl = TextEditingController();
  final _iqomahMaghribCtrl = TextEditingController();
  final _iqomahIsyaCtrl = TextEditingController();
  final _preAdzanLeadCtrl = TextEditingController();
  final _blankNormalCtrl = TextEditingController();
  final _blankJumatCtrl = TextEditingController();

  final _identityScrollController = ScrollController();
  final _jadwalScrollController = ScrollController();
  final _tampilanScrollController = ScrollController();
  final _jumatScrollController = ScrollController();
  final _simulasiScrollController = ScrollController();
  late final FocusNode _identityEntryFocusNode;
  late final FocusNode _tampilanEntryFocusNode;
  late final FocusNode _jumatEntryFocusNode;
  late final FocusNode _simulasiEntryFocusNode;
  late final List<FocusNode> _navFocusNodes;
  late final List<FocusNode> _jadwalFocusNodes;
  late final List<FocusNode> _identityFocusNodes;
  late final List<FocusNode> _jumatFocusNodes;
  late final List<FocusNode> _simulasiFocusNodes;
  final Map<int, FocusNode> _tampilanFocusNodes = {};
  Timer? _identityAutoSaveTimer;
  Timer? _tampilanAutoSaveTimer;
  Timer? _jumatAutoSaveTimer;
  Timer? _jadwalAutoSaveTimer;
  Timer? _statusBadgeTimer;
  String? _statusBadgeMessage;
  bool _statusBadgeIsError = false;
  int _hijriOffsetDays = 0;

  @override
  void initState() {
    super.initState();
    _selectedTab = widget.initialTab.clamp(0, 4);
    _identityEntryFocusNode = FocusNode(debugLabel: 'identity_entry');
    _tampilanEntryFocusNode = FocusNode(debugLabel: 'tampilan_entry');
    _jumatEntryFocusNode = FocusNode(debugLabel: 'jumat_entry');
    _simulasiEntryFocusNode = FocusNode(debugLabel: 'simulasi_entry');
    _navFocusNodes = List.generate(
      5,
      (index) => FocusNode(debugLabel: 'admin_nav_$index'),
    );
    _identityFocusNodes = [
      _identityEntryFocusNode,
      ...List.generate(
        2,
        (index) => FocusNode(debugLabel: 'identity_row_${index + 1}'),
      ),
    ];
    _jumatFocusNodes = [
      _jumatEntryFocusNode,
      FocusNode(debugLabel: 'jumat_row_1'),
    ];
    _simulasiFocusNodes = [
      _simulasiEntryFocusNode,
      ...List.generate(
        8,
        (index) => FocusNode(debugLabel: 'simulasi_row_${index + 1}'),
      ),
    ];
    _jadwalFocusNodes = List.generate(
      11,
      (index) => FocusNode(debugLabel: 'jadwal_row_$index'),
    );
    final settings = ref.read(settingsProvider);
    _masjidNameCtrl.text = settings.masjidName;
    _masjidAddressCtrl.text = settings.masjidAddress;
    _cityCtrl.text = '${settings.cityDisplayName} (${settings.cityIdApi})';
    _mainDurCtrl.text = settings.mainScreenDurationSec.toString();
    _slideDurCtrl.text = settings.slideDurationSec.toString();
    _textScaleIndex = settings.textScaleIndex;
    _slideshowImages = List.from(settings.slideshowImages);
    _useUnsplash = settings.useUnsplashBackground;
    _unsplashKeywordCtrl.text = settings.unsplashKeyword;
    _unsplashRotationCtrl.text = settings.unsplashRotationHours.toString();
    _brandedBgImage = settings.brandedBgImage;
    _marqueeAnimType = settings.marqueeAnimType;
    _runningTexts = List.from(settings.runningTexts);
    _runningTextDurations = List.from(
      settings.runningTextDurations.isNotEmpty
          ? settings.runningTextDurations
          : List.filled(settings.runningTexts.length, 12),
    );
    // Ensure durations list length matches texts
    while (_runningTextDurations.length < _runningTexts.length) {
      _runningTextDurations.add(12);
    }
    _scaleCardLabel = settings.scaleCardLabel;
    _scaleCardBody = settings.scaleCardBody;
    _scaleRunningText = settings.scaleRunningText;
    _khatibCtrl.text = settings.khatibName;
    _imamCtrl.text = settings.imamName;
    
    _iqomahSubuhCtrl.text = settings.iqomahSubuh.toString();
    _iqomahDzuhurCtrl.text = settings.iqomahDzuhur.toString();
    _iqomahAsharCtrl.text = settings.iqomahAshar.toString();
    _iqomahMaghribCtrl.text = settings.iqomahMaghrib.toString();
    _iqomahIsyaCtrl.text = settings.iqomahIsya.toString();
    _preAdzanLeadCtrl.text = settings.preAdzanLead.toString();
    _blankNormalCtrl.text = settings.blankScreenNormal.toString();
    _blankJumatCtrl.text = settings.blankScreenJumat.toString();
    _hijriOffsetDays = settings.hijriOffsetDays;
    
    _mainDurCtrl.addListener(_queueTampilanAutoSave);
    _slideDurCtrl.addListener(_queueTampilanAutoSave);
    _unsplashKeywordCtrl.addListener(_queueTampilanAutoSave);
    _unsplashRotationCtrl.addListener(_queueTampilanAutoSave);
    _masjidNameCtrl.addListener(_queueIdentityAutoSave);
    _masjidAddressCtrl.addListener(_queueIdentityAutoSave);
    _khatibCtrl.addListener(() {
      if (!mounted) return;
      setState(() {});
      _queueJumatAutoSave();
    });
    _imamCtrl.addListener(() {
      if (!mounted) return;
      setState(() {});
      _queueJumatAutoSave();
    });
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (!mounted) return;
      if (widget.focusSelectedTabOnOpen) {
        _focusEntryForTab(_selectedTab);
      } else {
        _focusNavTab(_selectedTab);
      }
    });
  }

  @override
  void dispose() {
    _masjidNameCtrl.dispose();
    _masjidAddressCtrl.dispose();
    _cityCtrl.dispose();
    _mainDurCtrl.dispose();
    _slideDurCtrl.dispose();
    _unsplashKeywordCtrl.dispose();
    _unsplashRotationCtrl.dispose();
    _khatibCtrl.dispose();
    _imamCtrl.dispose();
    _iqomahSubuhCtrl.dispose();
    _iqomahDzuhurCtrl.dispose();
    _iqomahAsharCtrl.dispose();
    _iqomahMaghribCtrl.dispose();
    _iqomahIsyaCtrl.dispose();
    _preAdzanLeadCtrl.dispose();
    _blankNormalCtrl.dispose();
    _blankJumatCtrl.dispose();
    _identityScrollController.dispose();
    _jadwalScrollController.dispose();
    _tampilanScrollController.dispose();
    _jumatScrollController.dispose();
    _simulasiScrollController.dispose();
    _tampilanEntryFocusNode.dispose();
    _identityAutoSaveTimer?.cancel();
    _tampilanAutoSaveTimer?.cancel();
    _jumatAutoSaveTimer?.cancel();
    _jadwalAutoSaveTimer?.cancel();
    _statusBadgeTimer?.cancel();
    for (final node in _navFocusNodes) {
      node.dispose();
    }
    for (final node in _identityFocusNodes) {
      node.dispose();
    }
    for (final node in _jumatFocusNodes) {
      node.dispose();
    }
    for (final node in _simulasiFocusNodes) {
      node.dispose();
    }
    for (final node in _jadwalFocusNodes) {
      node.dispose();
    }
    for (final node in _tampilanFocusNodes.values) {
      node.dispose();
    }
    super.dispose();
  }

  Future<void> _saveIdentity({
    String message = 'Identitas masjid otomatis tersimpan',
  }) async {
    await ref.read(settingsProvider.notifier).updateSettings((s) {
      s.masjidName = _masjidNameCtrl.text.trim();
      s.masjidAddress = _masjidAddressCtrl.text.trim();
      // cityId is saved instantly when selected from dialog
      return s;
    });
    if (mounted) {
      _showStatusBadge(message);
    }
  }

  void _queueIdentityAutoSave() {
    _identityAutoSaveTimer?.cancel();
    _identityAutoSaveTimer = Timer(
      const Duration(milliseconds: 450),
      () => _saveIdentity(),
    );
  }

  Future<void> _saveTampilan({
    String message = 'Pengaturan tampilan otomatis tersimpan',
  }) async {
    await ref.read(settingsProvider.notifier).updateSettings((s) {
      s.textScaleIndex = _textScaleIndex;
      s.slideshowImages = List.from(_slideshowImages);
      s.mainScreenDurationSec = int.tryParse(_mainDurCtrl.text.trim()) ?? 15;
      s.slideDurationSec = int.tryParse(_slideDurCtrl.text.trim()) ?? 10;
      s.useUnsplashBackground = _useUnsplash;
      s.unsplashKeyword = _unsplashKeywordCtrl.text.trim().isEmpty ? 'mosque' : _unsplashKeywordCtrl.text.trim();
      s.unsplashRotationHours = int.tryParse(_unsplashRotationCtrl.text.trim()) ?? 6;
      s.brandedBgImage = _brandedBgImage;
      s.runningTexts = List.from(_runningTexts);
      s.runningTextDurations = List.from(_runningTextDurations);
      s.marqueeAnimType = _marqueeAnimType;
      s.scaleCardLabel = _scaleCardLabel;
      s.scaleCardBody = _scaleCardBody;
      s.scaleRunningText = _scaleRunningText;
      return s;
    });
    if (mounted) {
      _showStatusBadge(message);
    }
  }

  void _queueTampilanAutoSave({
    String message = 'Pengaturan tampilan otomatis tersimpan',
  }) {
    _tampilanAutoSaveTimer?.cancel();
    _tampilanAutoSaveTimer = Timer(
      const Duration(milliseconds: 450),
      () => _saveTampilan(message: message),
    );
  }

  Future<void> _saveJadwalSettings({
    String message = 'Pengaturan jadwal otomatis tersimpan',
  }) async {
    await ref.read(settingsProvider.notifier).updateSettings((s) {
      s.preAdzanLead = int.tryParse(_preAdzanLeadCtrl.text.trim()) ?? 10;
      s.blankScreenNormal = int.tryParse(_blankNormalCtrl.text.trim()) ?? 15;
      s.blankScreenJumat = int.tryParse(_blankJumatCtrl.text.trim()) ?? 45;
      s.iqomahSubuh = int.tryParse(_iqomahSubuhCtrl.text.trim()) ?? 15;
      s.iqomahDzuhur = int.tryParse(_iqomahDzuhurCtrl.text.trim()) ?? 10;
      s.iqomahAshar = int.tryParse(_iqomahAsharCtrl.text.trim()) ?? 10;
      s.iqomahMaghrib = int.tryParse(_iqomahMaghribCtrl.text.trim()) ?? 10;
      s.iqomahIsya = int.tryParse(_iqomahIsyaCtrl.text.trim()) ?? 10;
      s.hijriOffsetDays = _hijriOffsetDays;
      return s;
    });

    if (mounted) {
      ref.invalidate(hijriDateProvider);
      _showStatusBadge(message);
    }
  }

  void _queueJadwalAutoSave({
    String message = 'Pengaturan jadwal otomatis tersimpan',
  }) {
    _jadwalAutoSaveTimer?.cancel();
    _jadwalAutoSaveTimer = Timer(
      const Duration(milliseconds: 450),
      () => _saveJadwalSettings(message: message),
    );
  }

  Future<void> _saveJumat({
    String message = 'Pengaturan Jumat otomatis tersimpan',
  }) async {
    await ref.read(settingsProvider.notifier).updateSettings((s) {
      s.khatibName = _khatibCtrl.text.trim();
      s.imamName = _imamCtrl.text.trim();
      return s;
    });
    if (mounted) {
      _showStatusBadge(message);
    }
  }

  void _queueJumatAutoSave() {
    _jumatAutoSaveTimer?.cancel();
    _jumatAutoSaveTimer = Timer(
      const Duration(milliseconds: 450),
      () => _saveJumat(),
    );
  }

  void _showStatusBadge(String message, {bool isError = false}) {
    if (!mounted) return;
    _statusBadgeTimer?.cancel();
    setState(() {
      _statusBadgeMessage = message;
      _statusBadgeIsError = isError;
    });
    _statusBadgeTimer = Timer(const Duration(seconds: 2), () {
      if (!mounted) return;
      setState(() {
        _statusBadgeMessage = null;
        _statusBadgeIsError = false;
      });
    });
  }

  Future<void> _syncData() async {
    setState(() => _isSyncing = true);
    final success = await SyncService.instance.syncMonthlyData();
    setState(() => _isSyncing = false);

    if (mounted) {
      ref.invalidate(todayScheduleProvider);
      ref.invalidate(scheduleCacheStatusProvider);

      _showStatusBadge(
        success
            ? 'Sinkronisasi jadwal berhasil'
            : 'Sinkronisasi gagal. Periksa koneksi internet.',
        isError: !success,
      );
    }
  }

  Future<void> _showCitySearchDialog(double s) async {
    final queryCtrl = TextEditingController();
    final queryFocusNode = FocusNode(debugLabel: 'city_query');
    final searchFocusNode = FocusNode(debugLabel: 'city_search');
    final resultsScrollController = ScrollController();
    final resultFocusNodes = <FocusNode>[];
    List<Map<String, dynamic>> results = [];
    bool isSearching = false;

    try {
      await showDialog(
        context: context,
        builder: (ctx) {
          return StatefulBuilder(
            builder: (context, setDialogState) {
              Future<void> selectCity(Map<String, dynamic> city) async {
                final id = city['id'].toString();
                final loc = city['lokasi'].toString();

                await ref.read(settingsProvider.notifier).updateSettings((s) {
                  s.cityIdApi = id;
                  s.cityDisplayName = loc;
                  return s;
                });
                if (!mounted || !ctx.mounted) {
                  return;
                }
                setState(() {
                  _cityCtrl.text = '$loc ($id)';
                });
                _showStatusBadge(
                  'Lokasi jadwal otomatis tersimpan',
                );
                Navigator.pop(ctx);
              }

              Future<void> runSearch() async {
                final query = queryCtrl.text.trim();
                if (query.isEmpty) return;
                setDialogState(() => isSearching = true);
                final res = await MyQuranSholatService.instance.searchCity(query);
                for (final node in resultFocusNodes) {
                  node.dispose();
                }
                resultFocusNodes
                  ..clear()
                  ..addAll(
                    List.generate(
                      res.length,
                      (index) => FocusNode(debugLabel: 'city_result_$index'),
                    ),
                  );
                setDialogState(() {
                  results = res;
                  isSearching = false;
                });
                WidgetsBinding.instance.addPostFrameCallback((_) {
                  if (!ctx.mounted) return;
                  if (res.isNotEmpty) {
                    resultFocusNodes.first.requestFocus();
                  } else {
                    searchFocusNode.requestFocus();
                  }
                });
              }

              return FocusTraversalGroup(
                policy: WidgetOrderTraversalPolicy(),
                child: Focus(
                  autofocus: true,
                  canRequestFocus: false,
                  onKeyEvent: (node, event) {
                    if ((event is KeyDownEvent || event is KeyRepeatEvent) &&
                        event.logicalKey == LogicalKeyboardKey.escape) {
                      Navigator.pop(ctx);
                      return KeyEventResult.handled;
                    }
                    return KeyEventResult.ignored;
                  },
                  child: Dialog(
                    backgroundColor: SacredColors.surfaceContainerLowest,
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(SacredRadii.xl),
                    ),
                    child: Container(
                      width: 820 * s,
                      height: 680 * s,
                      padding: EdgeInsets.all(40 * s),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            'Cari Kota / Kabupaten',
                            style: GoogleFonts.plusJakartaSans(
                              fontSize: 32 * s,
                              fontWeight: FontWeight.bold,
                              color: SacredColors.primary,
                            ),
                          ),
                          SizedBox(height: 12 * s),
                          Text(
                            'Gunakan OK untuk edit kata kunci, lalu tekan tombol cari.',
                            style: GoogleFonts.manrope(
                              fontSize: 16 * s,
                              color: SacredColors.onSurfaceVariant,
                            ),
                          ),
                          SizedBox(height: 24 * s),
                          _TvEditableTextTile(
                            scale: s,
                            label: 'Kata Kunci Kota / Kabupaten',
                            controller: queryCtrl,
                            focusNode: queryFocusNode,
                            onEditComplete: () {
                              WidgetsBinding.instance.addPostFrameCallback((_) {
                                if (ctx.mounted) {
                                  searchFocusNode.requestFocus();
                                }
                              });
                            },
                          ),
                          SizedBox(height: 16 * s),
                          Focus(
                            focusNode: searchFocusNode,
                            onKeyEvent: (node, event) {
                              if (event is! KeyDownEvent &&
                                  event is! KeyRepeatEvent) {
                                return KeyEventResult.ignored;
                              }
                              final key = event.logicalKey;
                              if (key == LogicalKeyboardKey.arrowUp) {
                                queryFocusNode.requestFocus();
                                return KeyEventResult.handled;
                              }
                              if (key == LogicalKeyboardKey.arrowDown) {
                                if (resultFocusNodes.isNotEmpty) {
                                  resultFocusNodes.first.requestFocus();
                                  return KeyEventResult.handled;
                                }
                                return KeyEventResult.handled;
                              }
                              if (key == LogicalKeyboardKey.enter ||
                                  key == LogicalKeyboardKey.select) {
                                runSearch();
                                return KeyEventResult.handled;
                              }
                              return KeyEventResult.ignored;
                            },
                            child: ListenableBuilder(
                              listenable: searchFocusNode,
                              builder: (context, child) {
                                final hasFocus = searchFocusNode.hasFocus;
                                return AnimatedScale(
                                  scale: hasFocus ? 1.01 : 1.0,
                                  duration: const Duration(milliseconds: 140),
                                  curve: Curves.easeOutCubic,
                                  child: InkWell(
                                    onTap: runSearch,
                                    borderRadius:
                                        BorderRadius.circular(SacredRadii.lg),
                                    child: AnimatedContainer(
                                      duration:
                                          const Duration(milliseconds: 140),
                                      curve: Curves.easeOutCubic,
                                      width: double.infinity,
                                      padding: EdgeInsets.symmetric(
                                        horizontal: 28 * s,
                                        vertical: 22 * s,
                                      ),
                                      decoration: BoxDecoration(
                                        color: hasFocus
                                            ? SacredColors.primary
                                            : SacredColors.secondary,
                                        borderRadius: BorderRadius.circular(
                                          SacredRadii.lg,
                                        ),
                                        border: Border.all(
                                          color: hasFocus
                                              ? SacredColors.primary
                                              : Colors.transparent,
                                          width: hasFocus ? 3 : 0,
                                        ),
                                        boxShadow: hasFocus
                                            ? [
                                                BoxShadow(
                                                  color: SacredColors.primary
                                                      .withValues(alpha: 0.28),
                                                  blurRadius: 24 * s,
                                                  spreadRadius: 2 * s,
                                                ),
                                              ]
                                            : null,
                                      ),
                                      child: Row(
                                        mainAxisAlignment:
                                            MainAxisAlignment.center,
                                        children: [
                                          isSearching
                                              ? SizedBox(
                                                  width: 20 * s,
                                                  height: 20 * s,
                                                  child:
                                                      CircularProgressIndicator(
                                                    color: hasFocus
                                                        ? SacredColors.onPrimary
                                                        : SacredColors.onSecondary,
                                                    strokeWidth: 2,
                                                  ),
                                                )
                                              : HugeIcon(
                                                  icon: HugeIcons
                                                      .strokeRoundedSearch01,
                                                  color: hasFocus
                                                      ? SacredColors.onPrimary
                                                      : SacredColors.onSecondary,
                                                ),
                                          SizedBox(width: 12 * s),
                                          Text(
                                            'CARI KOTA / KABUPATEN',
                                            style: GoogleFonts.plusJakartaSans(
                                              fontSize: 20 * s,
                                              fontWeight: FontWeight.bold,
                                              color: hasFocus
                                                  ? SacredColors.onPrimary
                                                  : SacredColors.onSecondary,
                                            ),
                                          ),
                                        ],
                                      ),
                                    ),
                                  ),
                                );
                              },
                            ),
                          ),
                          SizedBox(height: 24 * s),
                          Expanded(
                            child: results.isEmpty && !isSearching
                                ? Center(
                                    child: Text(
                                      'Tidak ada hasil',
                                      style: GoogleFonts.manrope(
                                        fontSize: 20 * s,
                                        color: SacredColors.onSurfaceVariant,
                                      ),
                                    ),
                                  )
                                : ListView.builder(
                                    controller: resultsScrollController,
                                    itemCount: results.length,
                                    itemBuilder: (context, index) {
                                      final city = results[index];
                                      return Padding(
                                        padding:
                                            EdgeInsets.only(bottom: 10 * s),
                                        child: Focus(
                                          focusNode: resultFocusNodes[index],
                                          onFocusChange: (value) {
                                            if (!value) return;
                                            final focusContext =
                                                resultFocusNodes[index].context;
                                            if (focusContext != null) {
                                              Scrollable.ensureVisible(
                                                focusContext,
                                                duration: const Duration(
                                                  milliseconds: 140,
                                                ),
                                                alignment: 0.25,
                                                curve: Curves.easeOutCubic,
                                              );
                                            }
                                          },
                                          onKeyEvent: (node, event) {
                                            if (event is! KeyDownEvent &&
                                                event is! KeyRepeatEvent) {
                                              return KeyEventResult.ignored;
                                            }
                                            final key = event.logicalKey;
                                            if (key ==
                                                    LogicalKeyboardKey.enter ||
                                                key ==
                                                    LogicalKeyboardKey.select) {
                                              selectCity(city);
                                              return KeyEventResult.handled;
                                            }
                                            if (key ==
                                                LogicalKeyboardKey.arrowUp) {
                                              if (index == 0) {
                                                searchFocusNode.requestFocus();
                                              } else {
                                                resultFocusNodes[index - 1]
                                                    .requestFocus();
                                              }
                                              return KeyEventResult.handled;
                                            }
                                            if (key ==
                                                LogicalKeyboardKey.arrowDown) {
                                              if (index <
                                                  resultFocusNodes.length - 1) {
                                                resultFocusNodes[index + 1]
                                                    .requestFocus();
                                              }
                                              return KeyEventResult.handled;
                                            }
                                            return KeyEventResult.ignored;
                                          },
                                          child: ListenableBuilder(
                                            listenable: resultFocusNodes[index],
                                            builder: (context, child) {
                                              final hasFocus =
                                                  resultFocusNodes[index]
                                                      .hasFocus;
                                              return AnimatedScale(
                                                scale: hasFocus ? 1.01 : 1.0,
                                                duration: const Duration(
                                                  milliseconds: 140,
                                                ),
                                                curve: Curves.easeOutCubic,
                                                child: InkWell(
                                                  onTap: () => selectCity(city),
                                                  borderRadius:
                                                      BorderRadius.circular(
                                                    SacredRadii.md,
                                                  ),
                                                  child: AnimatedContainer(
                                                    duration: const Duration(
                                                      milliseconds: 140,
                                                    ),
                                                    curve:
                                                        Curves.easeOutCubic,
                                                    padding:
                                                        EdgeInsets.symmetric(
                                                      horizontal: 24 * s,
                                                      vertical: 16 * s,
                                                    ),
                                                    decoration: BoxDecoration(
                                                      color: hasFocus
                                                          ? SacredColors
                                                              .surfaceContainerLow
                                                          : SacredColors
                                                              .surfaceContainerLowest,
                                                      borderRadius:
                                                          BorderRadius.circular(
                                                        SacredRadii.md,
                                                      ),
                                                      border: Border.all(
                                                        color: hasFocus
                                                            ? SacredColors
                                                                .primary
                                                                .withValues(
                                                                  alpha: 0.95,
                                                                )
                                                            : SacredColors
                                                                .outlineVariant
                                                                .withValues(
                                                                  alpha: 0.35,
                                                                ),
                                                        width: hasFocus ? 3 : 1,
                                                      ),
                                                      boxShadow: hasFocus
                                                          ? [
                                                              BoxShadow(
                                                                color: SacredColors
                                                                    .primary
                                                                    .withValues(
                                                                      alpha:
                                                                          0.28,
                                                                    ),
                                                                blurRadius:
                                                                    24 * s,
                                                                spreadRadius:
                                                                    2 * s,
                                                              ),
                                                            ]
                                                          : null,
                                                    ),
                                                    child: Column(
                                                      crossAxisAlignment:
                                                          CrossAxisAlignment
                                                              .start,
                                                      children: [
                                                        Text(
                                                          city['lokasi'] ?? '',
                                                          style: GoogleFonts
                                                              .plusJakartaSans(
                                                            fontSize: 24 * s,
                                                            fontWeight:
                                                                FontWeight.w700,
                                                            color: SacredColors
                                                                .onSurface,
                                                          ),
                                                        ),
                                                        SizedBox(
                                                          height: 6 * s,
                                                        ),
                                                        Text(
                                                          'ID: ${city['id']}',
                                                          style: GoogleFonts
                                                              .manrope(
                                                            fontSize: 18 * s,
                                                            color: hasFocus
                                                                ? SacredColors
                                                                    .primary
                                                                : SacredColors
                                                                    .onSurfaceVariant,
                                                          ),
                                                        ),
                                                      ],
                                                    ),
                                                  ),
                                                ),
                                              );
                                            },
                                          ),
                                        ),
                                      );
                                    },
                                  ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
              );
            },
          );
        },
      );
    } finally {
      queryCtrl.dispose();
      queryFocusNode.dispose();
      searchFocusNode.dispose();
      resultsScrollController.dispose();
      for (final node in resultFocusNodes) {
        node.dispose();
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;
    final s = size.width / 1920;

    return Scaffold(
      backgroundColor: SacredColors.background,
      appBar: AppBar(
        backgroundColor: SacredColors.surfaceContainerLowest,
        title: Text(
          'PENGATURAN SISTEM',
          style: GoogleFonts.plusJakartaSans(
            fontSize: 24 * s,
            fontWeight: FontWeight.w700,
            color: SacredColors.onSurface,
            letterSpacing: 2 * s,
          ),
        ),
        iconTheme: const IconThemeData(color: SacredColors.primary),
        actions: [
          Padding(
            padding: EdgeInsets.only(right: 24 * s),
            child: AnimatedSwitcher(
              duration: const Duration(milliseconds: 180),
              child: _statusBadgeMessage == null
                  ? const SizedBox.shrink()
                  : Container(
                      key: ValueKey(_statusBadgeMessage),
                      padding: EdgeInsets.symmetric(
                        horizontal: 16 * s,
                        vertical: 8 * s,
                      ),
                      decoration: BoxDecoration(
                        color: _statusBadgeIsError
                            ? SacredColors.errorContainer
                            : SacredColors.primaryContainer,
                        borderRadius: BorderRadius.circular(SacredRadii.full),
                        border: Border.all(
                          color: _statusBadgeIsError
                              ? SacredColors.error
                              : SacredColors.primary.withValues(alpha: 0.85),
                          width: 1.5,
                        ),
                      ),
                      child: Row(
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          Icon(
                            _statusBadgeIsError
                                ? Icons.error_outline_rounded
                                : Icons.check_circle_outline_rounded,
                            color: Colors.white,
                            size: 16 * s,
                          ),
                          SizedBox(width: 8 * s),
                          Text(
                            _statusBadgeMessage!,
                            style: GoogleFonts.manrope(
                              fontSize: 13 * s,
                              fontWeight: FontWeight.w700,
                              color: Colors.white,
                            ),
                          ),
                        ],
                      ),
                    ),
            ),
          ),
        ],
      ),
      body: FocusTraversalGroup(
        policy: ReadingOrderTraversalPolicy(),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
          // Nav rail area
          Container(
            width: 350 * s,
            color: SacredColors.surfaceContainerLow,
            padding: EdgeInsets.all(32 * s),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                _NavButton(
                  title: 'IDENTITAS MASJID',
                  icon: HugeIcons.strokeRoundedHome01,
                  isActive: _selectedTab == 0,
                  scale: s,
                  focusNode: _navFocusNodes[0],
                  onFocusChange: (focused) {
                    if (focused) _setSelectedTab(0);
                  },
                  onKeyEvent: (node, event) => _handleNavKey(0, event),
                  onTap: () => setState(() => _selectedTab = 0),
                ),
                SizedBox(height: 16 * s),
                _NavButton(
                  title: 'JADWAL & SINKRONISASI',
                  icon: HugeIcons.strokeRoundedCalendar01,
                  isActive: _selectedTab == 1,
                  scale: s,
                  focusNode: _navFocusNodes[1],
                  onFocusChange: (focused) {
                    if (focused) _setSelectedTab(1);
                  },
                  onKeyEvent: (node, event) => _handleNavKey(1, event),
                  onTap: () => setState(() => _selectedTab = 1),
                ),
                SizedBox(height: 16 * s),
                _NavButton(
                  title: 'TAMPILAN & MEDIA',
                  icon: HugeIcons.strokeRoundedImage01,
                  isActive: _selectedTab == 2,
                  scale: s,
                  focusNode: _navFocusNodes[2],
                  onFocusChange: (focused) {
                    if (focused) _setSelectedTab(2);
                  },
                  onKeyEvent: (node, event) => _handleNavKey(2, event),
                  onTap: () => setState(() => _selectedTab = 2),
                ),
                SizedBox(height: 16 * s),
                _NavButton(
                  title: 'PENGATURAN JUMAT',
                  icon: HugeIcons.strokeRoundedCalendar01,
                  isActive: _selectedTab == 3,
                  scale: s,
                  focusNode: _navFocusNodes[3],
                  onFocusChange: (focused) {
                    if (focused) _setSelectedTab(3);
                  },
                  onKeyEvent: (node, event) => _handleNavKey(3, event),
                  onTap: () => setState(() => _selectedTab = 3),
                ),
                SizedBox(height: 16 * s),
                _NavButton(
                  title: 'SIMULASI',
                  icon: HugeIcons.strokeRoundedClock01,
                  isActive: _selectedTab == 4,
                  scale: s,
                  focusNode: _navFocusNodes[4],
                  onFocusChange: (focused) {
                    if (focused) _setSelectedTab(4);
                  },
                  onKeyEvent: (node, event) => _handleNavKey(4, event),
                  onTap: () => setState(() => _selectedTab = 4),
                ),
              ],
            ),
          ),

          // Content area
          Expanded(
            child: Padding(
              padding: EdgeInsets.all(64 * s),
              child: _selectedTab == 0
                  ? _buildIdentityTab(s)
                  : _selectedTab == 1
                      ? _buildJadwalTab(s)
                      : _selectedTab == 2
                          ? _buildTampilanTab(s)
                          : _selectedTab == 3
                              ? _buildJumatTab(s)
                              : _buildSimulasiTab(s),
            ),
          ),
        ],
        ),
      ),
    );
  }

  void _setSelectedTab(int index) {
    if (_selectedTab == index) return;
    setState(() => _selectedTab = index);
  }

  void _focusNavTab(int index) {
    if (index < 0 || index >= _navFocusNodes.length) return;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) {
        _navFocusNodes[index].requestFocus();
      }
    });
  }

  void _focusIdentityRow(int index) {
    if (_selectedTab != 0) return;
    if (index < 0 || index >= _identityFocusNodes.length) return;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) {
        _identityFocusNodes[index].requestFocus();
      }
    });
  }

  void _focusJumatRow(int index) {
    if (_selectedTab != 3) return;
    if (index < 0 || index >= _jumatFocusNodes.length) return;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) {
        _jumatFocusNodes[index].requestFocus();
      }
    });
  }

  void _focusSimulasiRow(int index) {
    if (_selectedTab != 4) return;
    if (index < 0 || index >= _simulasiFocusNodes.length) return;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) {
        _simulasiFocusNodes[index].requestFocus();
      }
    });
  }

  void _focusJadwalRow(int index) {
    if (_selectedTab != 1) return;
    if (index < 0 || index >= _jadwalFocusNodes.length) return;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) {
        _jadwalFocusNodes[index].requestFocus();
      }
    });
  }

  FocusNode _tampilanFocusNode(int index) {
    if (index == 0) {
      return _tampilanEntryFocusNode;
    }
    return _tampilanFocusNodes.putIfAbsent(
      index,
      () => FocusNode(debugLabel: 'tampilan_row_$index'),
    );
  }

  int _tampilanRowCount() {
    var count = 0;
    count += 7;
    if (_useUnsplash) {
      count += 2;
    }
    if (_brandedBgImage != null && _brandedBgImage!.isNotEmpty) {
      count += 1;
    }
    count += 1;
    count += 1;
    count += _slideshowImages.length;
    count += 1;
    count += _runningTexts.length * 3;
    count += 1;
    return count;
  }

  void _focusTampilanRow(int index) {
    if (_selectedTab != 2) return;
    final max = _tampilanRowCount();
    if (index < 0 || index >= max) return;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) {
        _tampilanFocusNode(index).requestFocus();
      }
    });
  }

  void _focusEntryForTab(int index) {
    final FocusNode? target;
    switch (index) {
      case 0:
        _focusIdentityRow(0);
        return;
      case 1:
        _focusJadwalRow(0);
        return;
      case 2:
        _focusTampilanRow(0);
        return;
      case 3:
        _focusJumatRow(0);
        return;
      case 4:
        _focusSimulasiRow(0);
        return;
      default:
        target = null;
    }
    if (target == null) return;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) {
        target!.requestFocus();
      }
    });
  }

  KeyEventResult _handleNavKey(int index, KeyEvent event) {
    if (event is! KeyDownEvent && event is! KeyRepeatEvent) {
      return KeyEventResult.ignored;
    }

    final key = event.logicalKey;
    if (key == LogicalKeyboardKey.arrowUp) {
      _focusNavTab(index - 1);
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.arrowDown) {
      _focusNavTab(index + 1);
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.arrowRight ||
        key == LogicalKeyboardKey.select ||
        key == LogicalKeyboardKey.enter) {
      _focusEntryForTab(index);
      return KeyEventResult.handled;
    }

    return KeyEventResult.ignored;
  }

  KeyEventResult _handleJadwalActionKey(
    int index,
    KeyEvent event, {
    required VoidCallback onActivate,
  }) {
    if (event is! KeyDownEvent && event is! KeyRepeatEvent) {
      return KeyEventResult.ignored;
    }

    final key = event.logicalKey;
    if (key == LogicalKeyboardKey.arrowUp) {
      _focusJadwalRow(index - 1);
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.arrowDown) {
      _focusJadwalRow(index + 1);
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.arrowLeft) {
      _focusNavTab(_selectedTab);
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.arrowRight) {
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.select || key == LogicalKeyboardKey.enter) {
      onActivate();
      return KeyEventResult.handled;
    }

    return KeyEventResult.ignored;
  }

  KeyEventResult _handleSimpleTabKey(KeyEvent event) {
    if (event is! KeyDownEvent && event is! KeyRepeatEvent) {
      return KeyEventResult.ignored;
    }
    if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
      _focusNavTab(_selectedTab);
      return KeyEventResult.handled;
    }
    return KeyEventResult.ignored;
  }

  KeyEventResult _handleIdentityActionKey(
    int index,
    KeyEvent event, {
    required VoidCallback onActivate,
  }) {
    if (event is! KeyDownEvent && event is! KeyRepeatEvent) {
      return KeyEventResult.ignored;
    }
    final key = event.logicalKey;
    if (key == LogicalKeyboardKey.arrowUp) {
      _focusIdentityRow(index - 1);
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.arrowDown) {
      _focusIdentityRow(index + 1);
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.arrowLeft) {
      _focusNavTab(_selectedTab);
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.arrowRight) {
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.select || key == LogicalKeyboardKey.enter) {
      onActivate();
      return KeyEventResult.handled;
    }
    return KeyEventResult.ignored;
  }

  KeyEventResult _handleTampilanActionKey(
    int index,
    KeyEvent event, {
    required VoidCallback onActivate,
  }) {
    if (event is! KeyDownEvent && event is! KeyRepeatEvent) {
      return KeyEventResult.ignored;
    }

    final key = event.logicalKey;
    if (key == LogicalKeyboardKey.arrowUp) {
      _focusTampilanRow(index - 1);
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.arrowDown) {
      _focusTampilanRow(index + 1);
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.arrowLeft) {
      _focusNavTab(_selectedTab);
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.arrowRight) {
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.select || key == LogicalKeyboardKey.enter) {
      onActivate();
      return KeyEventResult.handled;
    }
    return KeyEventResult.ignored;
  }

  KeyEventResult _handleSimulasiActionKey(
    int index,
    KeyEvent event, {
    required VoidCallback onActivate,
  }) {
    if (event is! KeyDownEvent && event is! KeyRepeatEvent) {
      return KeyEventResult.ignored;
    }
    final key = event.logicalKey;
    if (key == LogicalKeyboardKey.arrowUp) {
      _focusSimulasiRow(index - 1);
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.arrowDown) {
      _focusSimulasiRow(index + 1);
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.arrowLeft) {
      _focusNavTab(_selectedTab);
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.arrowRight) {
      return KeyEventResult.handled;
    }
    if (key == LogicalKeyboardKey.select || key == LogicalKeyboardKey.enter) {
      onActivate();
      return KeyEventResult.handled;
    }
    return KeyEventResult.ignored;
  }

  Widget _buildJumatTab(double s) {
    return FocusTraversalGroup(
      policy: WidgetOrderTraversalPolicy(),
      child: Focus(
        canRequestFocus: false,
        onKeyEvent: (node, event) => _handleSimpleTabKey(event),
        child: SingleChildScrollView(
          controller: _jumatScrollController,
          child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            'Pengaturan Jumat',
            style: GoogleFonts.plusJakartaSans(
              fontSize: 48 * s, fontWeight: FontWeight.w700, color: SacredColors.secondary),
          ),
          SizedBox(height: 8 * s),
          Text(
            'Data di bawah akan tampil setiap hari Jumat: pada layar utama (banner bawah jam) dan layar Persiapan Khutbah.',
            style: GoogleFonts.manrope(fontSize: 16 * s, color: SacredColors.onSurfaceVariant),
          ),
          SizedBox(height: 40 * s),

          _adminCard(s, child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              _sectionLabel('Petugas Shalat Jumat', s),
              SizedBox(height: 8 * s),
              Text(
                'Nama Khatib dan Imam tampil di layar utama setiap Jumat dan di layar Persiapan Khutbah.',
                style: GoogleFonts.manrope(fontSize: 14 * s, color: SacredColors.onSurfaceVariant),
              ),
              SizedBox(height: 24 * s),
                _buildTextField(
                  'Nama Khatib Minggu Ini',
                  _khatibCtrl,
                  s,
                  focusNode: _jumatFocusNodes[0],
                  onMoveLeft: () => _focusNavTab(_selectedTab),
                  onMoveDown: () => _focusJumatRow(1),
                ),
              SizedBox(height: 16 * s),
                _buildTextField(
                  'Nama Imam Minggu Ini',
                  _imamCtrl,
                  s,
                  focusNode: _jumatFocusNodes[1],
                  onMoveLeft: () => _focusNavTab(_selectedTab),
                  onMoveUp: () => _focusJumatRow(0),
                ),
              SizedBox(height: 32 * s),

              // Preview chip
              if (_khatibCtrl.text.isNotEmpty || _imamCtrl.text.isNotEmpty) ...[
                Text('Preview tampilan:', style: GoogleFonts.manrope(fontSize: 14 * s, color: SacredColors.onSurfaceVariant)),
                SizedBox(height: 10 * s),
                Container(
                  padding: EdgeInsets.all(20 * s),
                  decoration: BoxDecoration(
                    color: SacredColors.background,
                    borderRadius: BorderRadius.circular(SacredRadii.lg),
                    border: Border.all(color: SacredColors.secondary.withValues(alpha: 0.2)),
                  ),
                  child: Row(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Icon(Icons.star_rounded, color: SacredColors.secondary, size: 16 * s),
                      SizedBox(width: 8 * s),
                      Text('JUMAT MUBARAK', style: GoogleFonts.plusJakartaSans(
                        fontSize: 14 * s, fontWeight: FontWeight.w800, color: SacredColors.secondary, letterSpacing: 2)),
                      SizedBox(width: 8 * s),
                      Icon(Icons.star_rounded, color: SacredColors.secondary, size: 16 * s),
                      SizedBox(width: 24 * s),
                      if (_khatibCtrl.text.isNotEmpty)
                        Text('KHATIB  ${_khatibCtrl.text}', style: GoogleFonts.manrope(
                          fontSize: 14 * s, color: SacredColors.onSurface)),
                      if (_khatibCtrl.text.isNotEmpty && _imamCtrl.text.isNotEmpty)
                        Text('  |  ', style: GoogleFonts.manrope(fontSize: 14 * s, color: SacredColors.onSurfaceVariant)),
                      if (_imamCtrl.text.isNotEmpty)
                        Text('IMAM  ${_imamCtrl.text}', style: GoogleFonts.manrope(
                          fontSize: 14 * s, color: SacredColors.onSurface)),
                    ],
                  ),
                ),
                SizedBox(height: 24 * s),
              ],
            ],
          )),

          SizedBox(height: 32 * s),

          // Info box
          _adminCard(s, child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              _sectionLabel('Kapan Digunakan?', s),
              SizedBox(height: 16 * s),
              _infoRow(Icons.tv, 'Layar Utama (Jumat)', 'Banner bawah jam berubah ke JUMAT MUBARAK, nama khatib & imam tampil di bawahnya.', s),
              SizedBox(height: 12 * s),
              _infoRow(Icons.timer_outlined, 'Layar Persiapan Khutbah', 'Saat menuju iqomah Dzuhur di hari Jumat, layar menampilkan judul PERSIAPAN KHUTBAH beserta nama petugas.', s),
              SizedBox(height: 12 * s),
              _infoRow(Icons.info_outline, 'Durasi Blank Screen', 'Durasi Black Screen setelah shalat Jumat dapat diatur di tab Jadwal & Sinkronisasi.', s),
            ],
          )),
        ],
      ),
        ),
      ),
    );
  }

  Widget _infoRow(IconData icon, String title, String desc, double s) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Icon(icon, color: SacredColors.secondary, size: 22 * s),
        SizedBox(width: 12 * s),
        Expanded(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(title, style: GoogleFonts.manrope(fontSize: 15 * s, fontWeight: FontWeight.w700, color: SacredColors.onSurface)),
              SizedBox(height: 4 * s),
              Text(desc, style: GoogleFonts.manrope(fontSize: 13 * s, color: SacredColors.onSurfaceVariant)),
            ],
          ),
        ),
      ],
    );
  }

  Widget _buildTampilanTab(double s) {
    var row = 0;
    final textScaleRow = row++;
    final mainDurationRow = row++;
    final slideDurationRow = row++;
    final scaleLabelRow = row++;
    final scaleBodyRow = row++;
    final scaleRunningRow = row++;
    final useUnsplashRow = row++;
    int? unsplashKeywordRow;
    int? unsplashRotationRow;
    if (_useUnsplash) {
      unsplashKeywordRow = row++;
      unsplashRotationRow = row++;
    }
    int? removeBrandedBgRow;
    if (_brandedBgImage != null && _brandedBgImage!.isNotEmpty) {
      removeBrandedBgRow = row++;
    }
    final pickBrandedBgRow = row++;
    final addSlideshowImageRow = row++;
    final slideshowDeleteRows = List<int>.generate(
      _slideshowImages.length,
      (_) => row++,
    );
    final marqueeModeRow = row++;
    final runningTextTextRows = <int>[];
    final runningTextDurationRows = <int>[];
    final runningTextDeleteRows = <int>[];
    for (var i = 0; i < _runningTexts.length; i++) {
      runningTextTextRows.add(row++);
      runningTextDurationRows.add(row++);
      runningTextDeleteRows.add(row++);
    }
    final addRunningTextRow = row++;

    return FocusTraversalGroup(
      policy: WidgetOrderTraversalPolicy(),
      child: Focus(
        canRequestFocus: false,
        onKeyEvent: (node, event) => _handleSimpleTabKey(event),
        child: SingleChildScrollView(
          controller: _tampilanScrollController,
          child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            'Pengaturan Tampilan & Media',
            style: GoogleFonts.plusJakartaSans(
              fontSize: 48 * s,
              fontWeight: FontWeight.w700,
              color: SacredColors.primary,
            ),
          ),
          SizedBox(height: 48 * s),
          _adminCard(
            s,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                _sectionLabel('Tipografi & Skala Teks', s),
                SizedBox(height: 12 * s),
                _buildTvChoiceField(
                  s: s,
                  rowIndex: textScaleRow,
                  label: 'Skala Teks Global',
                  options: const ['Kecil', 'Normal', 'Besar'],
                  selectedIndex: _textScaleIndex,
                  onChanged: (index) {
                    setState(() => _textScaleIndex = index);
                    _queueTampilanAutoSave();
                  },
                ),
                SizedBox(height: 28 * s),
                _buildTvIntStepperField(
                  s: s,
                  label: 'Durasi Layar Utama',
                  focusNode: _tampilanFocusNode(mainDurationRow),
                  controller: _mainDurCtrl,
                  fallback: 15,
                  min: 5,
                  max: 120,
                  suffix: 'detik',
                  onMoveLeft: () => _focusNavTab(_selectedTab),
                  onMoveUp: () => _focusTampilanRow(textScaleRow),
                  onMoveDown: () => _focusTampilanRow(slideDurationRow),
                ),
                SizedBox(height: 24 * s),
                _buildTvIntStepperField(
                  s: s,
                  label: 'Durasi Tiap Slideshow',
                  focusNode: _tampilanFocusNode(slideDurationRow),
                  controller: _slideDurCtrl,
                  fallback: 10,
                  min: 5,
                  max: 120,
                  suffix: 'detik',
                  onMoveLeft: () => _focusNavTab(_selectedTab),
                  onMoveUp: () => _focusTampilanRow(mainDurationRow),
                  onMoveDown: () => _focusTampilanRow(scaleLabelRow),
                ),
                SizedBox(height: 40 * s),
                _sectionLabel('Ukuran Teks Per Kelompok', s),
                SizedBox(height: 8 * s),
                Text(
                  'Kontrol ukuran teks secara spesifik per kelompok, terlepas dari skala global di atas.',
                  style: GoogleFonts.manrope(fontSize: 14 * s, color: SacredColors.onSurfaceVariant),
                ),
                SizedBox(height: 20 * s),
                _scaleSlider(
                  s: s,
                  label: 'Label Shalat (Nama: SUBUH, DZUHUR…)',
                  focusNode: _tampilanFocusNode(scaleLabelRow),
                  value: _scaleCardLabel,
                  onChanged: (v) {
                    setState(() => _scaleCardLabel = v);
                    _queueTampilanAutoSave();
                  },
                  onMoveLeft: () => _focusNavTab(_selectedTab),
                  onMoveUp: () => _focusTampilanRow(slideDurationRow),
                  onMoveDown: () => _focusTampilanRow(scaleBodyRow),
                ),
                SizedBox(height: 16 * s),
                _scaleSlider(
                  s: s,
                  label: 'Waktu & Iqamah pada kartu jadwal',
                  focusNode: _tampilanFocusNode(scaleBodyRow),
                  value: _scaleCardBody,
                  onChanged: (v) {
                    setState(() => _scaleCardBody = v);
                    _queueTampilanAutoSave();
                  },
                  onMoveLeft: () => _focusNavTab(_selectedTab),
                  onMoveUp: () => _focusTampilanRow(scaleLabelRow),
                  onMoveDown: () => _focusTampilanRow(scaleRunningRow),
                ),
                SizedBox(height: 16 * s),
                _scaleSlider(
                  s: s,
                  label: 'Teks Berjalan (Running Text)',
                  focusNode: _tampilanFocusNode(scaleRunningRow),
                  value: _scaleRunningText,
                  onChanged: (v) {
                    setState(() => _scaleRunningText = v);
                    _queueTampilanAutoSave();
                  },
                  onMoveLeft: () => _focusNavTab(_selectedTab),
                  onMoveUp: () => _focusTampilanRow(scaleBodyRow),
                  onMoveDown: () => _focusTampilanRow(useUnsplashRow),
                ),
                SizedBox(height: 40 * s),
                _sectionLabel('Background Layar Utama (Unsplash)', s),
                SizedBox(height: 12 * s),
                _buildTvBoolField(
                  s: s,
                  rowIndex: useUnsplashRow,
                  label: 'Gunakan Foto Unsplash API',
                  value: _useUnsplash,
                  onChanged: (val) {
                    setState(() => _useUnsplash = val);
                    _queueTampilanAutoSave();
                  },
                  trueLabel: 'Aktif',
                  falseLabel: 'Nonaktif',
                ),
                if (_useUnsplash) ...[
                  SizedBox(height: 12 * s),
                  _buildTextField(
                    'Kata Kunci (Contoh: mosque, architecture)',
                    _unsplashKeywordCtrl,
                    s,
                    focusNode: _tampilanFocusNode(unsplashKeywordRow!),
                    onMoveLeft: () => _focusNavTab(_selectedTab),
                    onMoveUp: () => _focusTampilanRow(useUnsplashRow),
                    onMoveDown: () => _focusTampilanRow(unsplashRotationRow!),
                  ),
                  SizedBox(height: 12 * s),
                  _buildTvIntStepperField(
                    s: s,
                    label: 'Rotasi Foto',
                    focusNode: _tampilanFocusNode(unsplashRotationRow!),
                    controller: _unsplashRotationCtrl,
                    fallback: 6,
                    min: 1,
                    max: 24,
                    suffix: 'jam',
                    onMoveLeft: () => _focusNavTab(_selectedTab),
                    onMoveUp: () => _focusTampilanRow(unsplashKeywordRow!),
                    onMoveDown: () => _focusTampilanRow(
                      removeBrandedBgRow ?? pickBrandedBgRow,
                    ),
                  ),
                ],
              ],
            ),
          ),
          SizedBox(height: 24 * s),
          _adminCard(
            s,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                _sectionLabel('Foto Latar Utama (Branding Masjid)', s),
                SizedBox(height: 16 * s),
                if (_brandedBgImage != null && _brandedBgImage!.isNotEmpty) ...[
                  ClipRRect(
                    borderRadius: BorderRadius.circular(SacredRadii.md),
                    child: Image.file(
                      File(_brandedBgImage!),
                      height: 180 * s,
                      width: double.infinity,
                      fit: BoxFit.cover,
                      errorBuilder: (_, __, ___) => Container(
                        height: 180 * s,
                        width: double.infinity,
                        color: SacredColors.surfaceContainerLowest,
                        alignment: Alignment.center,
                        child: Icon(
                          Icons.broken_image,
                          size: 36 * s,
                          color: SacredColors.onSurfaceVariant,
                        ),
                      ),
                    ),
                  ),
                  SizedBox(height: 12 * s),
                  Text(
                    _brandedBgImage!.split('/').last,
                    style: GoogleFonts.manrope(fontSize: 14 * s, color: SacredColors.onSurfaceVariant),
                    maxLines: 1,
                    overflow: TextOverflow.ellipsis,
                  ),
                  SizedBox(height: 12 * s),
                  _buildTampilanActionButton(
                    rowIndex: removeBrandedBgRow!,
                    s: s,
                    onActivate: () {
                      setState(() => _brandedBgImage = null);
                      _queueTampilanAutoSave(
                        message: 'Foto latar otomatis dihapus dan tersimpan',
                      );
                    },
                    child: OutlinedButton.icon(
                      onPressed: () {
                        setState(() => _brandedBgImage = null);
                        _queueTampilanAutoSave(
                          message: 'Foto latar otomatis dihapus dan tersimpan',
                        );
                      },
                      icon: HugeIcon(icon: HugeIcons.strokeRoundedDelete01, color: SacredColors.error, size: 20 * s),
                      label: Text(
                        'HAPUS FOTO LATAR',
                        style: GoogleFonts.plusJakartaSans(
                          fontSize: 14 * s,
                          fontWeight: FontWeight.w700,
                          color: SacredColors.error,
                        ),
                      ),
                    ),
                  ),
                ] else
                  Text('Belum ada foto latar masjid.', style: GoogleFonts.manrope(fontSize: 16 * s, color: SacredColors.onSurfaceVariant)),
                SizedBox(height: 16 * s),
                _buildTampilanActionButton(
                  rowIndex: pickBrandedBgRow,
                  s: s,
                  onActivate: () async {
                    final res = await FilePicker.platform.pickFiles(type: FileType.image);
                    final selectedPath = res?.files.single.path;
                    if (selectedPath != null && File(selectedPath).existsSync()) {
                      setState(() => _brandedBgImage = selectedPath);
                      _queueTampilanAutoSave(
                        message: 'Foto latar otomatis tersimpan',
                      );
                    }
                  },
                  child: ElevatedButton.icon(
                    onPressed: () async {
                      final res = await FilePicker.platform.pickFiles(type: FileType.image);
                      final selectedPath = res?.files.single.path;
                      if (selectedPath != null &&
                          File(selectedPath).existsSync()) {
                        setState(() => _brandedBgImage = selectedPath);
                        _queueTampilanAutoSave(
                          message: 'Foto latar otomatis tersimpan',
                        );
                      }
                    },
                    icon: HugeIcon(icon: HugeIcons.strokeRoundedImage01, color: SacredColors.onPrimary, size: 20 * s),
                    label: Text('PILIH FOTO MASJID', style: TextStyle(fontSize: 16 * s)),
                    style: _tvElevatedActionStyle(
                      s: s,
                      normalBackground: SacredColors.secondary,
                      normalForeground: SacredColors.onPrimary,
                      padding: EdgeInsets.symmetric(horizontal: 24 * s, vertical: 16 * s),
                      fontSize: 16 * s,
                    ),
                  ),
                ),
              ],
            ),
          ),
          SizedBox(height: 24 * s),
          _adminCard(
            s,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                _sectionLabel('Galeri Gambar Slideshow', s),
                SizedBox(height: 16 * s),
                _buildTampilanActionButton(
                  rowIndex: addSlideshowImageRow,
                  s: s,
                  onActivate: () async {
                    final res = await FilePicker.platform.pickFiles(type: FileType.image, allowMultiple: true);
                    if (res != null) {
                      setState(() {
                        for (var path in res.paths) {
                          if (path != null &&
                              File(path).existsSync() &&
                              !_slideshowImages.contains(path)) {
                            _slideshowImages.add(path);
                          }
                        }
                      });
                      _queueTampilanAutoSave(
                        message: 'Galeri slideshow otomatis tersimpan',
                      );
                    }
                  },
                  child: ElevatedButton.icon(
                    onPressed: () async {
                      final res = await FilePicker.platform.pickFiles(type: FileType.image, allowMultiple: true);
                      if (res != null) {
                        setState(() {
                          for (var path in res.paths) {
                            if (path != null &&
                                File(path).existsSync() &&
                                !_slideshowImages.contains(path)) {
                              _slideshowImages.add(path);
                            }
                          }
                        });
                        _queueTampilanAutoSave(
                          message: 'Galeri slideshow otomatis tersimpan',
                        );
                      }
                    },
                    icon: HugeIcon(icon: HugeIcons.strokeRoundedPlusSign, color: SacredColors.onPrimary, size: 18 * s),
                    label: Text('TAMBAH FOTO', style: TextStyle(fontSize: 14 * s)),
                    style: _tvElevatedActionStyle(
                      s: s,
                      normalBackground: SacredColors.secondary,
                      normalForeground: SacredColors.onPrimary,
                      padding: EdgeInsets.symmetric(horizontal: 20 * s, vertical: 14 * s),
                      fontSize: 14 * s,
                    ),
                  ),
                ),
                SizedBox(height: 16 * s),
                if (_slideshowImages.isEmpty)
                  Text('Belum ada gambar slideshow.', style: GoogleFonts.manrope(fontSize: 16 * s, color: SacredColors.onSurfaceVariant))
                else
                  ListView.separated(
                    shrinkWrap: true,
                    physics: const NeverScrollableScrollPhysics(),
                    itemCount: _slideshowImages.length,
                    separatorBuilder: (_, __) => SizedBox(height: 12 * s),
                    itemBuilder: (context, idx) {
                      final path = _slideshowImages[idx];
                      return Container(
                        padding: EdgeInsets.all(16 * s),
                        decoration: BoxDecoration(
                          color: SacredColors.surfaceContainerLowest,
                          borderRadius: BorderRadius.circular(SacredRadii.md),
                          border: Border.all(color: SacredColors.outlineVariant.withValues(alpha: 0.3)),
                        ),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            ClipRRect(
                              borderRadius: BorderRadius.circular(SacredRadii.sm),
                              child: Image.file(
                                File(path),
                                width: double.infinity,
                                height: 120 * s,
                                fit: BoxFit.cover,
                                errorBuilder: (_, __, ___) => Container(
                                  width: double.infinity,
                                  height: 120 * s,
                                  color: SacredColors.surfaceContainerHigh,
                                  alignment: Alignment.center,
                                  child: Icon(
                                    Icons.broken_image,
                                    size: 32 * s,
                                    color: SacredColors.onSurfaceVariant,
                                  ),
                                ),
                              ),
                            ),
                            SizedBox(height: 10 * s),
                            Text(
                              path.split('/').last,
                              maxLines: 1,
                              overflow: TextOverflow.ellipsis,
                              style: GoogleFonts.manrope(fontSize: 14 * s, color: SacredColors.onSurface),
                            ),
                            SizedBox(height: 10 * s),
                            _buildTampilanActionButton(
                              rowIndex: slideshowDeleteRows[idx],
                              s: s,
                              onActivate: () {
                                setState(() => _slideshowImages.removeAt(idx));
                                _queueTampilanAutoSave(
                                  message: 'Galeri slideshow otomatis tersimpan',
                                );
                              },
                              child: OutlinedButton.icon(
                                onPressed: () {
                                  setState(() => _slideshowImages.removeAt(idx));
                                  _queueTampilanAutoSave(
                                    message: 'Galeri slideshow otomatis tersimpan',
                                  );
                                },
                                icon: HugeIcon(icon: HugeIcons.strokeRoundedDelete01, color: SacredColors.error, size: 18 * s),
                                label: Text(
                                  'HAPUS FOTO',
                                  style: GoogleFonts.plusJakartaSans(
                                    fontSize: 13 * s,
                                    fontWeight: FontWeight.w700,
                                    color: SacredColors.error,
                                  ),
                                ),
                              ),
                            ),
                          ],
                        ),
                      );
                    },
                  ),
              ],
            ),
          ),
          SizedBox(height: 24 * s),
          _adminCard(s, child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              _sectionLabel('Running Text / Pengumuman', s),
              SizedBox(height: 12 * s),
              _buildTvChoiceField(
                s: s,
                rowIndex: marqueeModeRow,
                label: 'Mode Animasi Running Text',
                options: const ['Marquee', 'Fade In-Out'],
                selectedIndex: _marqueeAnimType == 'fade' ? 1 : 0,
                onChanged: (index) {
                  setState(() => _marqueeAnimType = index == 1 ? 'fade' : 'marquee');
                  _queueTampilanAutoSave();
                },
              ),
              SizedBox(height: 24 * s),
              if (_runningTexts.isEmpty)
                Padding(
                  padding: EdgeInsets.symmetric(vertical: 16 * s),
                  child: Text('Belum ada teks. Klik TAMBAH untuk menambah baris.', style: GoogleFonts.manrope(fontSize: 16 * s, color: SacredColors.onSurfaceVariant)),
                )
              else
                ListView.separated(
                  shrinkWrap: true,
                  physics: const NeverScrollableScrollPhysics(),
                  itemCount: _runningTexts.length,
                  separatorBuilder: (_, __) => SizedBox(height: 12 * s),
                  itemBuilder: (context, idx) {
                    final textCtrl = TextEditingController(text: _runningTexts[idx])
                      ..selection = TextSelection.fromPosition(TextPosition(offset: _runningTexts[idx].length));
                    final durCtrl = TextEditingController(text: _runningTextDurations[idx].toString());
                    return Container(
                      padding: EdgeInsets.all(20 * s),
                      decoration: BoxDecoration(
                        color: SacredColors.surfaceContainerLowest,
                        borderRadius: BorderRadius.circular(SacredRadii.md),
                        border: Border.all(color: SacredColors.outlineVariant.withValues(alpha: 0.3)),
                      ),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Container(
                            width: 32 * s,
                            height: 32 * s,
                            alignment: Alignment.center,
                            decoration: BoxDecoration(
                              color: SacredColors.surfaceContainerHighest,
                              shape: BoxShape.circle,
                            ),
                            child: Text('${idx + 1}', style: GoogleFonts.manrope(fontSize: 14 * s, fontWeight: FontWeight.w700, color: SacredColors.primary)),
                          ),
                          SizedBox(height: 12 * s),
                          _TvEditableTextTile(
                            scale: s,
                            label: 'Teks Pengumuman',
                            focusNode: _tampilanFocusNode(runningTextTextRows[idx]),
                            controller: textCtrl,
                            onMoveLeft: () => _focusNavTab(_selectedTab),
                            onMoveUp: () => _focusTampilanRow(
                              idx == 0 ? marqueeModeRow : runningTextDeleteRows[idx - 1],
                            ),
                            onMoveDown: () => _focusTampilanRow(runningTextDurationRows[idx]),
                            onChanged: (val) {
                              _runningTexts[idx] = val;
                            },
                            onEditComplete: () {
                              _queueTampilanAutoSave(
                                message: 'Teks berjalan otomatis tersimpan',
                              );
                            },
                          ),
                          SizedBox(height: 12 * s),
                          SizedBox(
                            width: 180 * s,
                            child: _TvEditableTextTile(
                              scale: s,
                              label: 'Durasi (detik)',
                              focusNode: _tampilanFocusNode(runningTextDurationRows[idx]),
                              controller: durCtrl,
                              keyboardType: TextInputType.number,
                              onMoveLeft: () => _focusNavTab(_selectedTab),
                              onMoveUp: () => _focusTampilanRow(runningTextTextRows[idx]),
                              onMoveDown: () => _focusTampilanRow(runningTextDeleteRows[idx]),
                              onChanged: (val) {
                                _runningTextDurations[idx] = int.tryParse(val) ?? 12;
                              },
                              onEditComplete: () {
                                _queueTampilanAutoSave(
                                  message: 'Teks berjalan otomatis tersimpan',
                                );
                              },
                            ),
                          ),
                          SizedBox(height: 10 * s),
                          _buildTampilanActionButton(
                            rowIndex: runningTextDeleteRows[idx],
                            s: s,
                            onActivate: () {
                              setState(() {
                                _runningTexts.removeAt(idx);
                                _runningTextDurations.removeAt(idx);
                              });
                              _queueTampilanAutoSave(
                                message: 'Teks berjalan otomatis tersimpan',
                              );
                            },
                            child: OutlinedButton.icon(
                              onPressed: () {
                                setState(() {
                                  _runningTexts.removeAt(idx);
                                  _runningTextDurations.removeAt(idx);
                                });
                                _queueTampilanAutoSave(
                                  message: 'Teks berjalan otomatis tersimpan',
                                );
                              },
                              icon: HugeIcon(icon: HugeIcons.strokeRoundedDelete01, color: SacredColors.error, size: 18 * s),
                              label: Text(
                                'HAPUS BARIS',
                                style: GoogleFonts.plusJakartaSans(
                                  fontSize: 13 * s,
                                  fontWeight: FontWeight.w700,
                                  color: SacredColors.error,
                                ),
                              ),
                            ),
                          ),
                        ],
                      ),
                    );
                  },
                ),
              SizedBox(height: 20 * s),
              _buildTampilanActionButton(
                rowIndex: addRunningTextRow,
                s: s,
                onActivate: () {
                  setState(() {
                    _runningTexts.add('');
                    _runningTextDurations.add(12);
                  });
                  _queueTampilanAutoSave(
                    message: 'Baris teks otomatis ditambahkan',
                  );
                },
                child: OutlinedButton.icon(
                  onPressed: () {
                    setState(() {
                      _runningTexts.add('');
                      _runningTextDurations.add(12);
                    });
                    _queueTampilanAutoSave(
                      message: 'Baris teks otomatis ditambahkan',
                    );
                  },
                  icon: HugeIcon(icon: HugeIcons.strokeRoundedPlusSign, color: SacredColors.primary, size: 20 * s),
                  label: Text('TAMBAH BARIS', style: GoogleFonts.plusJakartaSans(fontSize: 16 * s, color: SacredColors.primary)),
                  style: OutlinedButton.styleFrom(
                    side: BorderSide(color: SacredColors.primary.withValues(alpha: 0.5)),
                    padding: EdgeInsets.symmetric(horizontal: 24 * s, vertical: 16 * s),
                  ),
                ),
              ),
            ],
          )),
          SizedBox(height: 40 * s),
        ],
      ),
        ),
      ),
    );
  }

  Widget _adminCard(double s, {required Widget child}) {
    return _scrollAware(
      controller: _scrollControllerForTab(_selectedTab),
      child: _TvFocusFrame(
        scale: s,
        borderRadius: BorderRadius.circular(SacredRadii.xl),
        child: Container(
          width: double.infinity,
          padding: EdgeInsets.all(36 * s),
          decoration: BoxDecoration(
            color: SacredColors.surfaceContainerHighest.withValues(alpha: 0.3),
            borderRadius: BorderRadius.circular(SacredRadii.xl),
            border: Border.all(color: SacredColors.outlineVariant.withValues(alpha: 0.2)),
          ),
          child: child,
        ),
      ),
    );
  }

  Widget _tvFocusable({
    required Widget child,
    required double s,
    double radius = SacredRadii.md,
    bool scrollAware = true,
  }) {
    final framed = _TvFocusFrame(
      scale: s,
      borderRadius: BorderRadius.circular(radius),
      child: child,
    );

    if (!scrollAware) return framed;

    return _scrollAware(
      controller: _scrollControllerForTab(_selectedTab),
      child: framed,
    );
  }

  ButtonStyle _tvElevatedActionStyle({
    required double s,
    required Color normalBackground,
    required Color normalForeground,
    EdgeInsetsGeometry? padding,
    double radius = SacredRadii.lg,
    double fontSize = 16,
    FontWeight fontWeight = FontWeight.bold,
  }) {
    return ButtonStyle(
      backgroundColor: WidgetStateProperty.resolveWith((states) {
        if (states.contains(WidgetState.disabled)) {
          return normalBackground.withValues(alpha: 0.45);
        }
        if (states.contains(WidgetState.focused)) {
          return SacredColors.primary;
        }
        return normalBackground;
      }),
      foregroundColor: WidgetStateProperty.resolveWith((states) {
        if (states.contains(WidgetState.disabled)) {
          return normalForeground.withValues(alpha: 0.6);
        }
        if (states.contains(WidgetState.focused)) {
          return SacredColors.onPrimary;
        }
        return normalForeground;
      }),
      textStyle: WidgetStatePropertyAll(
        TextStyle(fontSize: fontSize, fontWeight: fontWeight),
      ),
      padding: WidgetStatePropertyAll(
        padding ?? EdgeInsets.symmetric(horizontal: 24 * s, vertical: 16 * s),
      ),
      shape: WidgetStatePropertyAll(
        RoundedRectangleBorder(borderRadius: BorderRadius.circular(radius)),
      ),
    );
  }

  Widget _buildReadonlyField(
    TextEditingController controller,
    double s, {
    bool focusable = true,
    FocusNode? focusNode,
    VoidCallback? onMoveLeft,
    VoidCallback? onMoveUp,
    VoidCallback? onMoveDown,
  }) {
    final content = Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          'Lokasi Saat Ini',
          style: GoogleFonts.manrope(
            fontSize: 16 * s,
            fontWeight: FontWeight.w600,
            color: SacredColors.onSurfaceVariant,
          ),
        ),
        SizedBox(height: 12 * s),
        Container(
          width: double.infinity,
          padding: EdgeInsets.symmetric(horizontal: 16 * s, vertical: 18 * s),
          decoration: BoxDecoration(
            color: SacredColors.surfaceContainerLowest,
            borderRadius: BorderRadius.circular(SacredRadii.md),
            border: Border.all(
              color: SacredColors.outlineVariant.withValues(alpha: 0.35),
            ),
          ),
          child: Text(
            controller.text,
            style: GoogleFonts.plusJakartaSans(
              fontSize: 24 * s,
              color: SacredColors.onSurface,
            ),
          ),
        ),
      ],
    );

    if (!focusable) {
      return content;
    }

    return _scrollAware(
      controller: _scrollControllerForTab(_selectedTab),
      child: Focus(
        focusNode: focusNode,
        onKeyEvent: (node, event) {
          if (event is! KeyDownEvent && event is! KeyRepeatEvent) {
            return KeyEventResult.ignored;
          }
          final key = event.logicalKey;
          if (key == LogicalKeyboardKey.arrowLeft) {
            onMoveLeft?.call();
            return KeyEventResult.handled;
          }
          if (key == LogicalKeyboardKey.arrowUp) {
            onMoveUp?.call();
            return KeyEventResult.handled;
          }
          if (key == LogicalKeyboardKey.arrowDown) {
            onMoveDown?.call();
            return KeyEventResult.handled;
          }
          if (key == LogicalKeyboardKey.arrowRight) {
            return KeyEventResult.handled;
          }
          return KeyEventResult.ignored;
        },
        child: _tvFocusable(
          s: s,
          scrollAware: false,
          child: content,
        ),
      ),
    );
  }

  Widget _buildJadwalActionButton({
    required int rowIndex,
    required double s,
    required VoidCallback onActivate,
    Widget? child,
    Widget Function(bool isFocused)? builder,
  }) {
    assert(child != null || builder != null);
    final focusNode = _jadwalFocusNodes[rowIndex];

    return _scrollAware(
      controller: _jadwalScrollController,
      child: Focus(
        focusNode: focusNode,
        onKeyEvent: (node, event) =>
            _handleJadwalActionKey(rowIndex, event, onActivate: onActivate),
        child: ListenableBuilder(
          listenable: focusNode,
          builder: (context, _) {
            final isFocused = focusNode.hasFocus;
            return AnimatedScale(
              scale: isFocused ? 1.01 : 1.0,
              duration: const Duration(milliseconds: 140),
              curve: Curves.easeOutCubic,
              child: AnimatedContainer(
                duration: const Duration(milliseconds: 140),
                curve: Curves.easeOutCubic,
                padding: EdgeInsets.all(isFocused ? 5 * s : 0),
                decoration: BoxDecoration(
                  color: isFocused
                      ? SacredColors.surfaceContainerLow.withValues(alpha: 0.96)
                      : Colors.transparent,
                  borderRadius: BorderRadius.circular(SacredRadii.lg),
                  border: Border.all(
                    color: isFocused
                        ? SacredColors.primary.withValues(alpha: 0.95)
                        : Colors.transparent,
                    width: isFocused ? 3 : 0,
                  ),
                  boxShadow: isFocused
                      ? [
                          BoxShadow(
                            color: SacredColors.primary.withValues(alpha: 0.28),
                            blurRadius: 24 * s,
                            spreadRadius: 2 * s,
                          ),
                        ]
                      : null,
                ),
                child: ExcludeFocus(
                  child: builder?.call(isFocused) ?? child!,
                ),
              ),
            );
          },
        ),
      ),
    );
  }

  Widget _buildTampilanActionButton({
    required int rowIndex,
    required double s,
    required VoidCallback onActivate,
    Widget? child,
    Widget Function(bool isFocused)? builder,
  }) {
    assert(child != null || builder != null);
    final focusNode = _tampilanFocusNode(rowIndex);

    return _scrollAware(
      controller: _tampilanScrollController,
      child: Focus(
        focusNode: focusNode,
        onKeyEvent: (node, event) => _handleTampilanActionKey(
          rowIndex,
          event,
          onActivate: onActivate,
        ),
        child: ListenableBuilder(
          listenable: focusNode,
          builder: (context, _) {
            final isFocused = focusNode.hasFocus;
            return AnimatedScale(
              scale: isFocused ? 1.01 : 1.0,
              duration: const Duration(milliseconds: 140),
              curve: Curves.easeOutCubic,
              child: AnimatedContainer(
                duration: const Duration(milliseconds: 140),
                curve: Curves.easeOutCubic,
                padding: EdgeInsets.all(isFocused ? 5 * s : 0),
                decoration: BoxDecoration(
                  color: isFocused
                      ? SacredColors.surfaceContainerLow.withValues(alpha: 0.96)
                      : Colors.transparent,
                  borderRadius: BorderRadius.circular(SacredRadii.lg),
                  border: Border.all(
                    color: isFocused
                        ? SacredColors.primary.withValues(alpha: 0.95)
                        : Colors.transparent,
                    width: isFocused ? 3 : 0,
                  ),
                  boxShadow: isFocused
                      ? [
                          BoxShadow(
                            color: SacredColors.primary.withValues(alpha: 0.28),
                            blurRadius: 24 * s,
                            spreadRadius: 2 * s,
                          ),
                        ]
                      : null,
                ),
                child: builder != null ? builder(isFocused) : child!,
              ),
            );
          },
        ),
      ),
    );
  }

  Widget _buildTvChoiceField({
    required double s,
    required int rowIndex,
    required String label,
    required List<String> options,
    required int selectedIndex,
    required ValueChanged<int> onChanged,
  }) {
    final maxIndex = options.length - 1;
    return _buildTvAdjustTile(
      s: s,
      focusNode: _tampilanFocusNode(rowIndex),
      label: label,
      valueLabel: options[selectedIndex],
      progress: maxIndex <= 0 ? 1 : selectedIndex / maxIndex,
      helperText:
          'Tekan OK untuk mulai ubah. Saat aktif, gunakan ← → untuk memilih.',
      onMoveLeft: () => _focusNavTab(_selectedTab),
      onMoveUp: rowIndex > 0 ? () => _focusTampilanRow(rowIndex - 1) : null,
      onMoveDown: rowIndex + 1 < _tampilanRowCount()
          ? () => _focusTampilanRow(rowIndex + 1)
          : null,
      onIncrement: () {
        if (selectedIndex < maxIndex) {
          onChanged(selectedIndex + 1);
        }
      },
      onDecrement: () {
        if (selectedIndex > 0) {
          onChanged(selectedIndex - 1);
        }
      },
    );
  }

  Widget _buildTvBoolField({
    required double s,
    required int rowIndex,
    required String label,
    required bool value,
    required ValueChanged<bool> onChanged,
    String trueLabel = 'Aktif',
    String falseLabel = 'Nonaktif',
  }) {
    return _buildTvAdjustTile(
      s: s,
      focusNode: _tampilanFocusNode(rowIndex),
      label: label,
      valueLabel: value ? trueLabel : falseLabel,
      progress: value ? 1 : 0,
      helperText:
          'Tekan OK untuk mulai ubah. Saat aktif, gunakan ← → untuk mengganti status.',
      onMoveLeft: () => _focusNavTab(_selectedTab),
      onMoveUp: rowIndex > 0 ? () => _focusTampilanRow(rowIndex - 1) : null,
      onMoveDown: rowIndex + 1 < _tampilanRowCount()
          ? () => _focusTampilanRow(rowIndex + 1)
          : null,
      onIncrement: () {
        if (!value) onChanged(true);
      },
      onDecrement: () {
        if (value) onChanged(false);
      },
    );
  }

  Widget _buildTvPrimaryActionSurface({
    required double s,
    required Widget icon,
    required String label,
    required bool isFocused,
  }) {
    final backgroundColor =
        isFocused ? SacredColors.primary : SacredColors.secondary;
    final foregroundColor = SacredColors.onPrimary;

    return AnimatedContainer(
      duration: const Duration(milliseconds: 140),
      curve: Curves.easeOutCubic,
      padding: EdgeInsets.symmetric(horizontal: 48 * s, vertical: 28 * s),
      decoration: BoxDecoration(
        color: backgroundColor,
        borderRadius: BorderRadius.circular(SacredRadii.lg),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          IconTheme(
            data: IconThemeData(color: foregroundColor, size: 24 * s),
            child: DefaultTextStyle(
              style: GoogleFonts.plusJakartaSans(
                fontSize: 20 * s,
                fontWeight: FontWeight.bold,
                color: foregroundColor,
              ),
              child: Row(
                mainAxisSize: MainAxisSize.min,
                children: [
                  icon,
                  SizedBox(width: 16 * s),
                  Text(label),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget _sectionLabel(String label, double s) {
    return Text(
      label,
      style: GoogleFonts.plusJakartaSans(
        fontSize: 20 * s,
        fontWeight: FontWeight.w700,
        color: SacredColors.primary,
      ),
    );
  }



  Widget _buildIdentityTab(double s) {
    final nameRow = 0;
    final addressRow = 1;
    final searchRow = 2;

    return FocusTraversalGroup(
      policy: WidgetOrderTraversalPolicy(),
      child: Focus(
        canRequestFocus: false,
        onKeyEvent: (node, event) => _handleSimpleTabKey(event),
        child: SingleChildScrollView(
          controller: _identityScrollController,
          child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            'Identitas & Lokasi Masjid',
            style: GoogleFonts.plusJakartaSans(
              fontSize: 48 * s,
              fontWeight: FontWeight.w700,
              color: SacredColors.primary,
            ),
          ),
          SizedBox(height: 48 * s),
          _adminCard(
            s,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                _buildTextField(
                  'Nama Masjid',
                  _masjidNameCtrl,
                  s,
                  focusNode: _identityFocusNodes[nameRow],
                  onMoveLeft: () => _focusNavTab(_selectedTab),
                  onMoveDown: () => _focusIdentityRow(addressRow),
                ),
                SizedBox(height: 32 * s),
                _buildTextField(
                  'Alamat Lengkap',
                  _masjidAddressCtrl,
                  s,
                  maxLines: 2,
                  focusNode: _identityFocusNodes[addressRow],
                  onMoveLeft: () => _focusNavTab(_selectedTab),
                  onMoveUp: () => _focusIdentityRow(nameRow),
                  onMoveDown: () => _focusIdentityRow(searchRow),
                ),
                SizedBox(height: 32 * s),
                Text(
                  'Lokasi Jadwal Shalat (MyQuran API)',
                  style: GoogleFonts.manrope(
                    fontSize: 16 * s,
                    fontWeight: FontWeight.w600,
                    color: SacredColors.onSurfaceVariant,
                  ),
                ),
                SizedBox(height: 12 * s),
                _buildReadonlyField(
                  _cityCtrl,
                  s,
                  focusable: false,
                ),
                SizedBox(height: 16 * s),
                _scrollAware(
                  controller: _identityScrollController,
                  child: Focus(
                    focusNode: _identityFocusNodes[searchRow],
                    onKeyEvent: (node, event) => _handleIdentityActionKey(
                      searchRow,
                      event,
                      onActivate: () => _showCitySearchDialog(s),
                    ),
                    child: ListenableBuilder(
                      listenable: _identityFocusNodes[searchRow],
                      builder: (context, _) {
                        final isFocused =
                            _identityFocusNodes[searchRow].hasFocus;
                        return AnimatedScale(
                          scale: isFocused ? 1.01 : 1.0,
                          duration: const Duration(milliseconds: 140),
                          curve: Curves.easeOutCubic,
                          child: AnimatedContainer(
                            duration: const Duration(milliseconds: 140),
                            curve: Curves.easeOutCubic,
                            padding: EdgeInsets.all(isFocused ? 5 * s : 0),
                            decoration: BoxDecoration(
                              color: isFocused
                                  ? SacredColors.surfaceContainerLow
                                      .withValues(alpha: 0.96)
                                  : Colors.transparent,
                              borderRadius:
                                  BorderRadius.circular(SacredRadii.lg),
                              border: Border.all(
                                color: isFocused
                                    ? SacredColors.primary
                                        .withValues(alpha: 0.95)
                                    : Colors.transparent,
                                width: isFocused ? 3 : 0,
                              ),
                              boxShadow: isFocused
                                  ? [
                                      BoxShadow(
                                        color: SacredColors.primary
                                            .withValues(alpha: 0.28),
                                        blurRadius: 24 * s,
                                        spreadRadius: 2 * s,
                                      ),
                                    ]
                                  : null,
                            ),
                            child: ElevatedButton.icon(
                              onPressed: () => _showCitySearchDialog(s),
                              icon: HugeIcon(
                                icon: HugeIcons.strokeRoundedSearch01,
                                color: isFocused
                                    ? SacredColors.onPrimary
                                    : SacredColors.onPrimary,
                              ),
                              label: Text(
                                'CARI KOTA',
                                style: TextStyle(fontSize: 16 * s),
                              ),
                              style: _tvElevatedActionStyle(
                                s: s,
                                normalBackground: SacredColors.secondary,
                                normalForeground: SacredColors.onPrimary,
                                padding: EdgeInsets.symmetric(
                                  horizontal: 24 * s,
                                  vertical: 24 * s,
                                ),
                                fontSize: 16 * s,
                              ),
                            ),
                          ),
                        );
                      },
                    ),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
        ),
      ),
    );
  }

  Widget _buildJadwalTab(double s) {
    final settings = ref.watch(settingsProvider);
    final todayScheduleOption = ref.watch(todayScheduleProvider);
    final cacheStatus = ref.watch(scheduleCacheStatusProvider);
    final displayedHijri = ref.watch(hijriDateProvider).valueOrNull;
    final cacheRangeLabel = cacheStatus.hasData
        ? '${_formatCacheDate(cacheStatus.startDate)} - ${_formatCacheDate(cacheStatus.endDate)}'
        : 'Belum ada data';
    
    return SingleChildScrollView(
      controller: _jadwalScrollController,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
        Text(
          'Jadwal & Sinkronisasi',
          style: GoogleFonts.plusJakartaSans(
            fontSize: 48 * s,
            fontWeight: FontWeight.w700,
            color: SacredColors.primary,
          ),
        ),
        SizedBox(height: 48 * s),
        
        // Sync Card
        Container(
          width: double.infinity,
          padding: EdgeInsets.all(40 * s),
          decoration: BoxDecoration(
            color: SacredColors.surfaceContainerLow,
            borderRadius: BorderRadius.circular(SacredRadii.xl),
            border: Border.all(color: SacredColors.outlineVariant.withValues(alpha: 0.4)),
          ),
          child: Row(
            children: [
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Status Data Jadwal',
                      style: GoogleFonts.manrope(fontSize: 20 * s, fontWeight: FontWeight.w700, color: SacredColors.onSurfaceVariant, letterSpacing: 1 * s),
                    ),
                    SizedBox(height: 24 * s),
                    Wrap(
                      spacing: 48 * s,
                      runSpacing: 20 * s,
                      children: [
                        _buildStatusRow('Terakhir Sync', settings.lastSyncDate ?? 'Belum pernah', HugeIcons.strokeRoundedClock01, s),
                        _buildStatusRow('Sumber Data', 'api.myquran.com', HugeIcons.strokeRoundedDatabase01, s),
                        _buildStatusRow('Lokasi Data', settings.cityDisplayName, HugeIcons.strokeRoundedLocation01, s),
                        _buildStatusRow('Cache Tersimpan', cacheRangeLabel, HugeIcons.strokeRoundedCalendar03, s),
                        _buildStatusRow('Jumlah Hari', cacheStatus.hasData ? '${cacheStatus.cachedDays} hari' : '0 hari', HugeIcons.strokeRoundedTaskDaily01, s),
                        _buildStatusRow('Status Update', _buildCacheUpdateLabel(cacheStatus, todayScheduleOption != null), HugeIcons.strokeRoundedAlert02, s),
                      ],
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
        
        SizedBox(height: 20 * s),
        _buildJadwalActionButton(
          rowIndex: 0,
          s: s,
          onActivate: _isSyncing ? () {} : _syncData,
          builder: (isFocused) => _buildTvPrimaryActionSurface(
            s: s,
            isFocused: isFocused,
            icon: _isSyncing
                ? SizedBox(
                    width: 24 * s,
                    height: 24 * s,
                    child: CircularProgressIndicator(
                      color: isFocused
                          ? SacredColors.onPrimary
                          : SacredColors.onSecondary,
                      strokeWidth: 3,
                    ),
                  )
                : HugeIcon(
                    icon: HugeIcons.strokeRoundedCloudDownload,
                    color: isFocused
                        ? SacredColors.onPrimary
                        : SacredColors.onSecondary,
                  ),
            label: _isSyncing
                ? 'MENYINKRONKAN...'
                : 'SINKRONKAN DATA BULAN INI',
          ),
        ),
        
        SizedBox(height: 64 * s),

        _adminCard(
          s,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              _sectionLabel('Kalender Hijriah', s),
              SizedBox(height: 8 * s),
              Text(
                'Sesuaikan tampilan tanggal Hijriah jika hasil rukyat lokal masjid berbeda dari nilai default API.',
                style: GoogleFonts.manrope(
                  fontSize: 14 * s,
                  color: SacredColors.onSurfaceVariant,
                ),
              ),
              SizedBox(height: 24 * s),
              Container(
                width: double.infinity,
                padding: EdgeInsets.all(24 * s),
                decoration: BoxDecoration(
                  color: SacredColors.surfaceContainerHighest.withValues(alpha: 0.3),
                  borderRadius: BorderRadius.circular(SacredRadii.lg),
                  border: Border.all(
                    color: SacredColors.outlineVariant.withValues(alpha: 0.2),
                  ),
                ),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          'Tanggal tampil saat ini',
                          style: GoogleFonts.manrope(
                            fontSize: 14 * s,
                            fontWeight: FontWeight.w600,
                            color: SacredColors.onSurfaceVariant,
                          ),
                        ),
                        SizedBox(height: 8 * s),
                        Text(
                          displayedHijri ?? 'Memuat tanggal Hijriah...',
                          style: GoogleFonts.plusJakartaSans(
                            fontSize: 28 * s,
                            fontWeight: FontWeight.w700,
                            color: SacredColors.onSurface,
                          ),
                        ),
                      ],
                    ),
                    Container(
                      padding: EdgeInsets.symmetric(
                        horizontal: 16 * s,
                        vertical: 10 * s,
                      ),
                      decoration: BoxDecoration(
                        color: SacredColors.primary.withValues(alpha: 0.12),
                        borderRadius: BorderRadius.circular(SacredRadii.full),
                      ),
                      child: Text(
                        'Offset ${_hijriOffsetDays >= 0 ? '+' : ''}$_hijriOffsetDays hari',
                        style: GoogleFonts.plusJakartaSans(
                          fontSize: 16 * s,
                          fontWeight: FontWeight.w700,
                          color: SacredColors.primary,
                        ),
                      ),
                    ),
                  ],
                ),
              ),
              SizedBox(height: 20 * s),
              _buildHijriOffsetControl(
                s,
                focusNode: _jadwalFocusNodes[1],
                onMoveLeft: () => _focusNavTab(_selectedTab),
                onMoveUp: () => _focusJadwalRow(0),
                onMoveDown: () => _focusJadwalRow(2),
              ),
              SizedBox(height: 16 * s),
              _buildJadwalActionButton(
                rowIndex: 2,
                s: s,
                onActivate: () {
                  setState(() {
                    _hijriOffsetDays = 0;
                  });
                  _queueJadwalAutoSave(
                    message: 'Offset Hijriah direset dan otomatis tersimpan',
                  );
                },
                child: OutlinedButton.icon(
                  onPressed: () {
                    setState(() {
                      _hijriOffsetDays = 0;
                    });
                    _queueJadwalAutoSave(
                      message: 'Offset Hijriah direset dan otomatis tersimpan',
                    );
                  },
                  icon: const Icon(Icons.refresh),
                  label: const Text('RESET OFFSET'),
                ),
              ),
            ],
          ),
        ),

        SizedBox(height: 64 * s),

        // Waktu & Durasi Card
        _adminCard(s, child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            _sectionLabel('Waktu & Durasi', s),
            SizedBox(height: 8 * s),
            Text(
              'Seluruh pengaturan angka utama untuk alur jadwal ditangani dengan stepper agar nyaman dipakai dengan remote Android TV.',
              style: GoogleFonts.manrope(fontSize: 14 * s, color: SacredColors.onSurfaceVariant),
            ),
            SizedBox(height: 32 * s),
            _buildTvIntStepperField(
              s: s,
              label: 'Pra-Adzan',
              focusNode: _jadwalFocusNodes[3],
              controller: _preAdzanLeadCtrl,
              fallback: 10,
              min: 0,
              max: 60,
              suffix: 'menit',
              onMoveLeft: () => _focusNavTab(_selectedTab),
              onMoveUp: () => _focusJadwalRow(2),
              onMoveDown: () => _focusJadwalRow(4),
              onValueChanged: _queueJadwalAutoSave,
            ),
            SizedBox(height: 16 * s),
            _buildTvIntStepperField(
              s: s,
              label: 'Blank Screen Normal',
              focusNode: _jadwalFocusNodes[4],
              controller: _blankNormalCtrl,
              fallback: 15,
              min: 0,
              max: 120,
              suffix: 'menit',
              onMoveLeft: () => _focusNavTab(_selectedTab),
              onMoveUp: () => _focusJadwalRow(3),
              onMoveDown: () => _focusJadwalRow(5),
              onValueChanged: _queueJadwalAutoSave,
            ),
            SizedBox(height: 16 * s),
            _buildTvIntStepperField(
              s: s,
              label: 'Blank Screen Jumat',
              focusNode: _jadwalFocusNodes[5],
              controller: _blankJumatCtrl,
              fallback: 45,
              min: 0,
              max: 180,
              suffix: 'menit',
              onMoveLeft: () => _focusNavTab(_selectedTab),
              onMoveUp: () => _focusJadwalRow(4),
              onMoveDown: () => _focusJadwalRow(6),
              onValueChanged: _queueJadwalAutoSave,
            ),
            SizedBox(height: 28 * s),
            Text(
              'Jeda Waktu Iqamah (Menit)',
              style: GoogleFonts.manrope(
                fontSize: 16 * s,
                fontWeight: FontWeight.w700,
                color: SacredColors.onSurface,
              ),
            ),
            SizedBox(height: 8 * s),
            Text(
              'Tentukan durasi hitung mundur dari selesai Adzan hingga iqamah untuk tiap shalat fardhu.',
              style: GoogleFonts.manrope(fontSize: 14 * s, color: SacredColors.onSurfaceVariant),
            ),
            SizedBox(height: 24 * s),
            _buildTvIntStepperField(
              s: s,
              label: 'Iqamah Subuh',
              focusNode: _jadwalFocusNodes[6],
              controller: _iqomahSubuhCtrl,
              fallback: 15,
              min: 0,
              max: 60,
              suffix: 'menit',
              onMoveLeft: () => _focusNavTab(_selectedTab),
              onMoveUp: () => _focusJadwalRow(5),
              onMoveDown: () => _focusJadwalRow(7),
              onValueChanged: _queueJadwalAutoSave,
            ),
            SizedBox(height: 16 * s),
            _buildTvIntStepperField(
              s: s,
              label: 'Iqamah Dzuhur',
              focusNode: _jadwalFocusNodes[7],
              controller: _iqomahDzuhurCtrl,
              fallback: 10,
              min: 0,
              max: 60,
              suffix: 'menit',
              onMoveLeft: () => _focusNavTab(_selectedTab),
              onMoveUp: () => _focusJadwalRow(6),
              onMoveDown: () => _focusJadwalRow(8),
              onValueChanged: _queueJadwalAutoSave,
            ),
            SizedBox(height: 16 * s),
            _buildTvIntStepperField(
              s: s,
              label: 'Iqamah Ashar',
              focusNode: _jadwalFocusNodes[8],
              controller: _iqomahAsharCtrl,
              fallback: 10,
              min: 0,
              max: 60,
              suffix: 'menit',
              onMoveLeft: () => _focusNavTab(_selectedTab),
              onMoveUp: () => _focusJadwalRow(7),
              onMoveDown: () => _focusJadwalRow(9),
              onValueChanged: _queueJadwalAutoSave,
            ),
            SizedBox(height: 16 * s),
            _buildTvIntStepperField(
              s: s,
              label: 'Iqamah Maghrib',
              focusNode: _jadwalFocusNodes[9],
              controller: _iqomahMaghribCtrl,
              fallback: 7,
              min: 0,
              max: 60,
              suffix: 'menit',
              onMoveLeft: () => _focusNavTab(_selectedTab),
              onMoveUp: () => _focusJadwalRow(8),
              onMoveDown: () => _focusJadwalRow(10),
              onValueChanged: _queueJadwalAutoSave,
            ),
            SizedBox(height: 16 * s),
            _buildTvIntStepperField(
              s: s,
              label: 'Iqamah Isya',
              focusNode: _jadwalFocusNodes[10],
              controller: _iqomahIsyaCtrl,
              fallback: 10,
              min: 0,
              max: 60,
              suffix: 'menit',
              onMoveLeft: () => _focusNavTab(_selectedTab),
              onMoveUp: () => _focusJadwalRow(9),
              onValueChanged: _queueJadwalAutoSave,
            ),
          ],
        )),

        SizedBox(height: 64 * s),
        
        Text(
          'Pratinjau Jadwal Hari Ini',
          style: GoogleFonts.plusJakartaSans(
            fontSize: 32 * s,
            fontWeight: FontWeight.w700,
            color: SacredColors.onSurface,
          ),
        ),
        SizedBox(height: 32 * s),
        
        // Schedule Grid
        Builder(
          builder: (context) {
            if (todayScheduleOption == null) {
              return Padding(
                padding: EdgeInsets.symmetric(vertical: 24 * s),
                child: Center(
                  child: Text('Data jadwal kosong. Silakan lakukan sinkronisasi.', style: GoogleFonts.manrope(fontSize: 24 * s, color: SacredColors.error)),
                ),
              );
            }
            
            final prayerMap = {
              'IMSAK': todayScheduleOption.imsak,
              'SUBUH': todayScheduleOption.subuh,
              'TERBIT': todayScheduleOption.terbit,
              'DHUHA': todayScheduleOption.dhuha,
              'DZUHUR': todayScheduleOption.dzuhur,
              'ASHAR': todayScheduleOption.ashar,
              'MAGHRIB': todayScheduleOption.maghrib,
              'ISYA': todayScheduleOption.isya,
            };
            
            return GridView.builder(
              shrinkWrap: true,
              physics: const NeverScrollableScrollPhysics(),
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 4,
                crossAxisSpacing: 24 * s,
                mainAxisSpacing: 24 * s,
                childAspectRatio: 2.2, // wide rectangular Google Stitch cards
              ),
              itemCount: prayerMap.length,
              itemBuilder: (context, index) {
                final key = prayerMap.keys.elementAt(index);
                final time = prayerMap[key]!;
                return _buildPrayerCard(key, time, s);
              },
            );
          },
        ),
        SizedBox(height: 32 * s),
      ],
      ),
    );
  }

  Widget _buildHijriOffsetControl(
    double s, {
    FocusNode? focusNode,
    VoidCallback? onMoveLeft,
    VoidCallback? onMoveUp,
    VoidCallback? onMoveDown,
  }) {
    const minOffset = -3;
    const maxOffset = 3;
    return _buildTvAdjustTile(
      s: s,
      focusNode: focusNode,
      label: 'Offset Hari Hijriah',
      valueLabel: '${_hijriOffsetDays >= 0 ? '+' : ''}$_hijriOffsetDays hari',
      progress: (_hijriOffsetDays - minOffset) / (maxOffset - minOffset),
      helperText: 'Tekan OK untuk masuk mode ubah. Saat aktif, gunakan ← → untuk geser 1 hari.',
      onMoveLeft: onMoveLeft,
      onMoveUp: onMoveUp,
      onMoveDown: onMoveDown,
      onIncrement: () {
        setState(() {
          _hijriOffsetDays = (_hijriOffsetDays + 1).clamp(minOffset, maxOffset);
        });
        _queueJadwalAutoSave(
          message:
              'Offset Hijriah ${_hijriOffsetDays >= 0 ? '+' : ''}$_hijriOffsetDays hari tersimpan',
        );
      },
      onDecrement: () {
        setState(() {
          _hijriOffsetDays = (_hijriOffsetDays - 1).clamp(minOffset, maxOffset);
        });
        _queueJadwalAutoSave(
          message:
              'Offset Hijriah ${_hijriOffsetDays >= 0 ? '+' : ''}$_hijriOffsetDays hari tersimpan',
        );
      },
    );
  }

  Widget _buildPrayerCard(String name, String time, double s) {
    return Container(
      decoration: BoxDecoration(
        color: SacredColors.surfaceContainerLowest.withValues(alpha: 0.5),
        borderRadius: BorderRadius.circular(SacredRadii.lg),
        border: Border.all(color: SacredColors.outlineVariant.withValues(alpha: 0.3)),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withValues(alpha: 0.2),
            blurRadius: 10 * s,
            offset: Offset(0, 4 * s),
          )
        ]
      ),
      padding: EdgeInsets.symmetric(horizontal: 32 * s, vertical: 24 * s),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text(
            name,
            style: GoogleFonts.manrope(
              fontSize: 18 * s,
              fontWeight: FontWeight.w600,
              color: SacredColors.onSurfaceVariant,
              letterSpacing: 2 * s,
            ),
          ),
          SizedBox(height: 8 * s),
          Text(
            time,
            style: GoogleFonts.plusJakartaSans(
              fontSize: 42 * s,
              fontWeight: FontWeight.w800,
              color: SacredColors.primary,
            ),
          ),
        ],
      ),
    );
  }

  ScrollController _scrollControllerForTab(int tabIndex) {
    switch (tabIndex) {
      case 0:
        return _identityScrollController;
      case 1:
        return _jadwalScrollController;
      case 2:
        return _tampilanScrollController;
      case 3:
        return _jumatScrollController;
      case 4:
      default:
        return _simulasiScrollController;
    }
  }

  Widget _scrollAware({
    required ScrollController controller,
    required Widget child,
  }) {
    return Builder(
      builder: (context) {
        return Focus(
          onFocusChange: (hasFocus) {
            if (!hasFocus || !controller.hasClients) return;
            WidgetsBinding.instance.addPostFrameCallback((_) {
              if (context.mounted) {
                Scrollable.ensureVisible(
                  context,
                  duration: const Duration(milliseconds: 220),
                  curve: Curves.easeOutCubic,
                  alignment: 0.18,
                );
              }
            });
          },
          child: child,
        );
      },
    );
  }

  int _parseCtrlInt(TextEditingController ctrl, int fallback) {
    return int.tryParse(ctrl.text.trim()) ?? fallback;
  }

  void _bumpCtrlInt(
    TextEditingController ctrl, {
    required int delta,
    required int min,
    required int max,
    required int fallback,
  }) {
    final next = (_parseCtrlInt(ctrl, fallback) + delta).clamp(min, max);
    setState(() {
      ctrl.text = next.toString();
    });
  }

  Widget _buildTvIntStepperField({
    required double s,
    required String label,
    FocusNode? focusNode,
    required TextEditingController controller,
    required int fallback,
    required int min,
    required int max,
    String suffix = '',
    VoidCallback? onMoveLeft,
    VoidCallback? onMoveUp,
    VoidCallback? onMoveDown,
    VoidCallback? onValueChanged,
  }) {
    final value = _parseCtrlInt(controller, fallback);
    final valueLabel = suffix.isEmpty ? '$value' : '$value $suffix';

    return _scrollAware(
      controller: _scrollControllerForTab(_selectedTab),
      child: _buildTvAdjustTile(
        s: s,
        focusNode: focusNode,
        label: label,
        valueLabel: valueLabel,
        progress: ((value - min) / (max - min)).clamp(0.0, 1.0),
        helperText: 'Tekan OK untuk mulai ubah. Saat aktif, gunakan ← → untuk menyesuaikan nilai.',
        onMoveLeft: onMoveLeft,
        onMoveUp: onMoveUp,
        onMoveDown: onMoveDown,
        onIncrement: () {
          _bumpCtrlInt(
            controller,
            delta: 1,
            min: min,
            max: max,
            fallback: fallback,
          );
          onValueChanged?.call();
        },
        onDecrement: () {
          _bumpCtrlInt(
            controller,
            delta: -1,
            min: min,
            max: max,
            fallback: fallback,
          );
          onValueChanged?.call();
        },
      ),
    );
  }

  Widget _buildTvAdjustTile({
    required double s,
    FocusNode? focusNode,
    required String label,
    required String valueLabel,
    required double progress,
    required String helperText,
    VoidCallback? onMoveLeft,
    VoidCallback? onMoveUp,
    VoidCallback? onMoveDown,
    required VoidCallback onIncrement,
    required VoidCallback onDecrement,
  }) {
    return _TvAdjustTile(
      scale: s,
      focusNode: focusNode,
      label: label,
      valueLabel: valueLabel,
      progress: progress,
      helperText: helperText,
      onMoveLeft: onMoveLeft,
      onMoveUp: onMoveUp,
      onMoveDown: onMoveDown,
      onIncrement: onIncrement,
      onDecrement: onDecrement,
    );
  }

  Widget _buildTextField(
    String label,
    TextEditingController ctrl,
    double s, {
    int maxLines = 1,
    FocusNode? focusNode,
    TextInputType? keyboardType,
    ValueChanged<String>? onChanged,
    VoidCallback? onEditComplete,
    VoidCallback? onMoveLeft,
    VoidCallback? onMoveUp,
    VoidCallback? onMoveDown,
  }) {
    return _scrollAware(
      controller: _scrollControllerForTab(_selectedTab),
      child: _TvEditableTextTile(
        scale: s,
        label: label,
        controller: ctrl,
        focusNode: focusNode,
        maxLines: maxLines,
        keyboardType: keyboardType,
        onChanged: onChanged,
        onEditComplete: onEditComplete,
        onMoveLeft: onMoveLeft,
        onMoveUp: onMoveUp,
        onMoveDown: onMoveDown,
      ),
    );
  }

  Widget _buildStatusRow(String label, String value, dynamic icon, double s) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Container(
          padding: EdgeInsets.all(12 * s),
          decoration: BoxDecoration(
            color: SacredColors.surfaceContainerHighest,
            borderRadius: BorderRadius.circular(SacredRadii.sm),
          ),
          child: HugeIcon(icon: icon, color: SacredColors.secondary, size: 24 * s),
        ),
        SizedBox(width: 16 * s),
        Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(label, style: GoogleFonts.manrope(fontSize: 12 * s, color: SacredColors.onSurfaceVariant)),
            Text(value, style: GoogleFonts.plusJakartaSans(fontSize: 18 * s, fontWeight: FontWeight.w600, color: SacredColors.onSurface)),
          ],
        ),
      ],
    );
  }

  String _formatCacheDate(DateTime? date) {
    if (date == null) return 'Belum ada';
    return DateFormat('dd MMM yyyy').format(date);
  }

  String _buildCacheUpdateLabel(
    ScheduleCacheStatus status,
    bool hasTodayData,
  ) {
    if (!status.hasData) return 'Belum ada cache';
    if (!hasTodayData) return 'Hari ini belum tersimpan';
    if (status.daysUntilRefresh < 0) {
      return 'Lewat ${-status.daysUntilRefresh} hari';
    }
    if (status.daysUntilRefresh == 0) return 'Update hari ini';
    if (status.daysUntilRefresh == 1) return '1 hari lagi';
    return '${status.daysUntilRefresh} hari lagi';
  }

  Widget _scaleSlider({
    required double s,
    required String label,
    required double value,
    required ValueChanged<double> onChanged,
    FocusNode? focusNode,
    VoidCallback? onMoveLeft,
    VoidCallback? onMoveUp,
    VoidCallback? onMoveDown,
  }) {
    final pct = (value * 100).round();
    const step = 0.05;
    return _buildTvAdjustTile(
      s: s,
      focusNode: focusNode,
      label: label,
      valueLabel: '$pct%',
      progress: ((value - 0.5) / 1.5).clamp(0.0, 1.0),
      helperText: 'Tekan OK untuk mulai ubah. Saat aktif, gunakan ← → untuk mengubah skala 5%.',
      onMoveLeft: onMoveLeft,
      onMoveUp: onMoveUp,
      onMoveDown: onMoveDown,
      onIncrement: () => onChanged((value + step).clamp(0.5, 2.0)),
      onDecrement: () => onChanged((value - step).clamp(0.5, 2.0)),
    );
  }

  Widget _buildSimulasiTab(double s) {
    final simulationOffset = ref.watch(mockTimeOffsetProvider);
    final isSimulating = simulationOffset != Duration.zero;
    final simulatedMinutes = simulationOffset.inMinutes;

    return FocusTraversalGroup(
      policy: WidgetOrderTraversalPolicy(),
      child: Focus(
        canRequestFocus: false,
        onKeyEvent: (node, event) => _handleSimpleTabKey(event),
        child: SingleChildScrollView(
          controller: _simulasiScrollController,
          child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            'Mode Simulasi Pengembang',
            style: GoogleFonts.plusJakartaSans(
              fontSize: 48 * s,
              fontWeight: FontWeight.w700,
              color: SacredColors.primary,
            ),
          ),
          SizedBox(height: 16 * s),
          Text(
            'Gunakan tombol di bawah ini untuk melihat pratinjau bagaimana aplikasi bereaksi terhadap berbagai waktu dan status tanpa harus menunggu waktu sebenarnya.\nFitur ini bekerja dengan menggeser waktu aplikasi (Time Travel).',
            style: GoogleFonts.manrope(fontSize: 18 * s, color: SacredColors.onSurfaceVariant),
          ),
          SizedBox(height: 48 * s),
          Container(
            width: double.infinity,
            padding: EdgeInsets.all(20 * s),
            decoration: BoxDecoration(
              color: isSimulating
                  ? SacredColors.error.withValues(alpha: 0.12)
                  : SacredColors.surfaceContainerLowest,
              borderRadius: BorderRadius.circular(SacredRadii.lg),
              border: Border.all(
                color: isSimulating
                    ? SacredColors.error.withValues(alpha: 0.45)
                    : SacredColors.outlineVariant.withValues(alpha: 0.3),
              ),
            ),
            child: Row(
              children: [
                HugeIcon(
                  icon: isSimulating
                      ? HugeIcons.strokeRoundedAlert02
                      : HugeIcons.strokeRoundedCheckmarkCircle02,
                  color: isSimulating
                      ? SacredColors.error
                      : SacredColors.primary,
                  size: 28 * s,
                ),
                SizedBox(width: 16 * s),
                Expanded(
                  child: Text(
                    isSimulating
                        ? 'Simulasi aktif (${simulatedMinutes >= 0 ? '+' : ''}$simulatedMinutes menit). Gunakan kartu pertama untuk keluar dan kembali ke waktu asli.'
                        : 'Simulasi tidak aktif. Pilih salah satu skenario di bawah untuk mulai menguji tampilan layar.',
                    style: GoogleFonts.manrope(
                      fontSize: 16 * s,
                      fontWeight: FontWeight.w700,
                      color: SacredColors.onSurface,
                    ),
                  ),
                ),
              ],
            ),
          ),
          SizedBox(height: 24 * s),
          _simulasiCard(
            s: s,
            title: isSimulating ? 'Keluar dari Simulasi' : 'Gunakan Waktu Asli',
            icon: isSimulating
                ? HugeIcons.strokeRoundedCancelCircle
                : HugeIcons.strokeRoundedHome01,
            desc: isSimulating
                ? 'Matikan mode simulasi dan kembali ke waktu sistem saat ini.'
                : 'Pastikan aplikasi berjalan menggunakan waktu asli perangkat.',
            onTap: () => _activateSimulation(
              () => _simulateTimeOffset(Duration.zero),
            ),
            focusNode: _simulasiFocusNodes[0],
            rowIndex: 0,
          ),
          SizedBox(height: 16 * s),
          _simulasiCard(
            s: s,
            title: '15 Detik Sebelum Adzan',
            icon: HugeIcons.strokeRoundedNotification03,
            desc: 'Melompat ke 15 detik sebelum Adzan Dzuhur untuk memeriksa transisi terakhir menuju Adzan.',
            onTap: () => _activateSimulation(
              () => _simulateEvent('pre_adzan_15'),
            ),
            focusNode: _simulasiFocusNodes[1],
            rowIndex: 1,
          ),
          SizedBox(height: 16 * s),
          _simulasiCard(
            s: s,
            title: 'Menuju Adzan',
            icon: HugeIcons.strokeRoundedClock01,
            desc: 'Melompat ke 2 menit sebelum Adzan Dzuhur hari ini.',
            onTap: () => _activateSimulation(
              () => _simulateEvent('pre_adzan'),
            ),
            focusNode: _simulasiFocusNodes[2],
            rowIndex: 2,
          ),
          SizedBox(height: 16 * s),
          _simulasiCard(
            s: s,
            title: 'Selama Adzan',
            icon: HugeIcons.strokeRoundedMegaphone01,
            desc: 'Melompat ke tepat waktu Adzan Dzuhur berkumandang.',
            onTap: () => _activateSimulation(
              () => _simulateEvent('adzan'),
            ),
            focusNode: _simulasiFocusNodes[3],
            rowIndex: 3,
          ),
          SizedBox(height: 16 * s),
          _simulasiCard(
            s: s,
            title: '15 Detik Sebelum Iqamah',
            icon: HugeIcons.strokeRoundedTimer02,
            desc: 'Melompat ke 15 detik sebelum Iqamah Dzuhur untuk memeriksa hitungan mundur terakhir.',
            onTap: () => _activateSimulation(
              () => _simulateEvent('pre_iqomah_15'),
            ),
            focusNode: _simulasiFocusNodes[4],
            rowIndex: 4,
          ),
          SizedBox(height: 16 * s),
          _simulasiCard(
            s: s,
            title: 'Menuju Iqomah',
            icon: HugeIcons.strokeRoundedTimer02,
            desc: 'Melompat ke saat waktu iqomah sedang menghitung mundur (1 menit setelah Adzan).',
            onTap: () => _activateSimulation(
              () => _simulateEvent('iqomah'),
            ),
            focusNode: _simulasiFocusNodes[5],
            rowIndex: 5,
          ),
          SizedBox(height: 16 * s),
          _simulasiCard(
            s: s,
            title: 'Persiapan Jumat',
            icon: HugeIcons.strokeRoundedCalendar03,
            desc: 'Menyimulasikan layar khusus persiapan Jumat (30 menit sebelum Adzan Dzuhur).',
            onTap: () => _activateSimulation(
              () => _simulateEvent('jumat_incoming'),
            ),
            focusNode: _simulasiFocusNodes[6],
            rowIndex: 6,
          ),
          SizedBox(height: 16 * s),
          _simulasiCard(
            s: s,
            title: 'Khutbah Berlangsung',
            icon: HugeIcons.strokeRoundedUserGroup,
            desc: 'Menyimulasikan layar saat Khutbah sedang berlangsung tanpa hitungan mundur (2 menit setelah Adzan Dzuhur).',
            onTap: () => _activateSimulation(
              () => _simulateEvent('jumat_khutbah'),
            ),
            focusNode: _simulasiFocusNodes[7],
            rowIndex: 7,
          ),
          SizedBox(height: 16 * s),
          _simulasiCard(
            s: s,
            title: 'Mode Shalat',
            icon: HugeIcons.strokeRoundedMoon02,
            desc: 'Layar menjadi hitam atau gelap selama shalat berlangsung.',
            onTap: () => _activateSimulation(
              () => _simulateEvent('shalat'),
            ),
            focusNode: _simulasiFocusNodes[8],
            rowIndex: 8,
          ),
        ],
      ),
        ),
      ),
    );
  }

  Widget _simulasiCard({
    required double s,
    required String title,
    required dynamic icon,
    required String desc,
    required VoidCallback onTap,
    required int rowIndex,
    FocusNode? focusNode,
  }) {
    final node = focusNode ?? _simulasiFocusNodes[rowIndex];
    return _scrollAware(
      controller: _simulasiScrollController,
      child: Focus(
        focusNode: node,
        onKeyEvent: (focusNode, event) => _handleSimulasiActionKey(
          rowIndex,
          event,
          onActivate: onTap,
        ),
        child: ListenableBuilder(
          listenable: node,
          builder: (context, _) {
            final isFocused = node.hasFocus;
            return AnimatedScale(
              scale: isFocused ? 1.01 : 1.0,
              duration: const Duration(milliseconds: 140),
              curve: Curves.easeOutCubic,
              child: AnimatedContainer(
                duration: const Duration(milliseconds: 140),
                curve: Curves.easeOutCubic,
                padding: EdgeInsets.all(isFocused ? 5 * s : 0),
                decoration: BoxDecoration(
                  color: isFocused
                      ? SacredColors.surfaceContainerLow.withValues(alpha: 0.96)
                      : Colors.transparent,
                  borderRadius: BorderRadius.circular(SacredRadii.lg),
                  border: Border.all(
                    color: isFocused
                        ? SacredColors.primary.withValues(alpha: 0.95)
                        : Colors.transparent,
                    width: isFocused ? 3 : 0,
                  ),
                  boxShadow: isFocused
                      ? [
                          BoxShadow(
                            color: SacredColors.primary.withValues(alpha: 0.28),
                            blurRadius: 24 * s,
                            spreadRadius: 2 * s,
                          ),
                        ]
                      : null,
                ),
                child: InkWell(
                  onTap: onTap,
                  borderRadius: BorderRadius.circular(SacredRadii.lg),
                  child: Container(
                    width: double.infinity,
                    padding: EdgeInsets.all(24 * s),
                    decoration: BoxDecoration(
                      color: SacredColors.surfaceContainerLowest,
                      borderRadius: BorderRadius.circular(SacredRadii.lg),
                      border: Border.all(
                        color: SacredColors.outlineVariant.withValues(alpha: 0.5),
                      ),
                      boxShadow: [
                        BoxShadow(
                          color: Colors.black.withValues(alpha: 0.05),
                          blurRadius: 10 * s,
                          offset: Offset(0, 4 * s),
                        ),
                      ],
                    ),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        HugeIcon(
                          icon: icon,
                          color: SacredColors.primary,
                          size: 40 * s,
                        ),
                        SizedBox(height: 16 * s),
                        Text(
                          title,
                          style: GoogleFonts.plusJakartaSans(
                            fontSize: 20 * s,
                            fontWeight: FontWeight.bold,
                            color: SacredColors.onSurface,
                          ),
                        ),
                        SizedBox(height: 8 * s),
                        Text(
                          desc,
                          style: GoogleFonts.manrope(
                            fontSize: 14 * s,
                            color: SacredColors.onSurfaceVariant,
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ),
            );
          },
        ),
      ),
    );
  }

  void _simulateTimeOffset(Duration offset) {
    ref.read(mockTimeOffsetProvider.notifier).state = offset;
  }

  void _simulateEvent(String eventType) {
    final schedule = ref.read(todayScheduleProvider);
    if (schedule == null) return;
    // We simulate using schedule.dzuhur
    final dzuhurStr = schedule.dzuhur;
    
    final parts = dzuhurStr.split(':');
    final realNow = DateTime.now();
    final dzuhurTime = DateTime(realNow.year, realNow.month, realNow.day, int.parse(parts[0]), int.parse(parts[1]));
    
    DateTime targetTime;
    
    switch (eventType) {
      case 'pre_adzan_15':
        targetTime = dzuhurTime.subtract(const Duration(seconds: 15));
        break;
      case 'pre_adzan':
        targetTime = dzuhurTime.subtract(const Duration(minutes: 2));
        break;
      case 'adzan':
        targetTime = dzuhurTime;
        break;
      case 'pre_iqomah_15':
        final settings = ref.read(settingsProvider);
        targetTime = dzuhurTime
            .add(Duration(minutes: settings.iqomahDzuhur))
            .subtract(const Duration(seconds: 15));
        break;
      case 'iqomah':
        targetTime = dzuhurTime.add(const Duration(seconds: 45)); // During iqomah
        break;
      case 'jumat_incoming':
        int diff = DateTime.friday - realNow.weekday;
        DateTime nextFriday = realNow.add(Duration(days: diff));
        // Target: next Friday at dzuhur time - 30 minutes
        targetTime = DateTime(nextFriday.year, nextFriday.month, nextFriday.day, dzuhurTime.hour, dzuhurTime.minute).subtract(const Duration(minutes: 30));
        break;
      case 'jumat_khutbah':
        int diff = DateTime.friday - realNow.weekday;
        DateTime nextFriday = realNow.add(Duration(days: diff));
        // Target: next Friday at dzuhur time + 3 minutes (safely past 2-min Adzan)
        targetTime = DateTime(nextFriday.year, nextFriday.month, nextFriday.day, dzuhurTime.hour, dzuhurTime.minute).add(const Duration(minutes: 3));
        break;
      case 'shalat':
        // Shalat mode usually happens after iqomah ends
        final settings = ref.read(settingsProvider);
        targetTime = dzuhurTime.add(Duration(minutes: settings.iqomahDzuhur + 1));
        break;
      default:
        targetTime = realNow;
    }
    
    final offset = targetTime.difference(realNow);
    _simulateTimeOffset(offset);

    switch (eventType) {
      case 'adzan':
        unawaited(SoundService.instance.playAdzanBeep());
        break;
      case 'iqomah':
        unawaited(SoundService.instance.playIqomahCountdown());
        break;
      default:
        break;
    }
  }

  void _activateSimulation(VoidCallback action) {
    action();
    if (!mounted) return;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted && Navigator.of(context).canPop()) {
        Navigator.of(context).pop();
      }
    });
  }
}

class _NavButton extends StatefulWidget {
  final String title;
  final dynamic icon;
  final bool isActive;
  final double scale;
  final FocusNode? focusNode;
  final ValueChanged<bool>? onFocusChange;
  final FocusOnKeyEventCallback? onKeyEvent;
  final VoidCallback onTap;

  const _NavButton({
    required this.title,
    required this.icon,
    required this.isActive,
    required this.scale,
    this.focusNode,
    this.onFocusChange,
    this.onKeyEvent,
    required this.onTap,
  });

  @override
  State<_NavButton> createState() => _NavButtonState();
}

class _TvAdjustTile extends StatefulWidget {
  final double scale;
  final FocusNode? focusNode;
  final String label;
  final String valueLabel;
  final double progress;
  final String helperText;
  final VoidCallback? onMoveLeft;
  final VoidCallback? onMoveUp;
  final VoidCallback? onMoveDown;
  final VoidCallback onIncrement;
  final VoidCallback onDecrement;

  const _TvAdjustTile({
    required this.scale,
    this.focusNode,
    required this.label,
    required this.valueLabel,
    required this.progress,
    required this.helperText,
    this.onMoveLeft,
    this.onMoveUp,
    this.onMoveDown,
    required this.onIncrement,
    required this.onDecrement,
  });

  @override
  State<_TvAdjustTile> createState() => _TvAdjustTileState();
}

class _TvEditableTextTile extends StatefulWidget {
  final double scale;
  final String label;
  final TextEditingController controller;
  final FocusNode? focusNode;
  final int maxLines;
  final TextInputType? keyboardType;
  final ValueChanged<String>? onChanged;
  final VoidCallback? onEditComplete;
  final VoidCallback? onMoveLeft;
  final VoidCallback? onMoveUp;
  final VoidCallback? onMoveDown;

  const _TvEditableTextTile({
    required this.scale,
    required this.label,
    required this.controller,
    this.focusNode,
    this.maxLines = 1,
    this.keyboardType,
    this.onChanged,
    this.onEditComplete,
    this.onMoveLeft,
    this.onMoveUp,
    this.onMoveDown,
  });

  @override
  State<_TvEditableTextTile> createState() => _TvEditableTextTileState();
}

class _TvAdjustTileState extends State<_TvAdjustTile> {
  late final FocusNode _fallbackFocusNode =
      FocusNode(debugLabel: 'tv_adjust_tile');
  bool _isFocused = false;
  bool _isEditing = false;

  FocusNode get _focusNode => widget.focusNode ?? _fallbackFocusNode;

  @override
  void dispose() {
    if (widget.focusNode == null) {
      _fallbackFocusNode.dispose();
    }
    super.dispose();
  }

  KeyEventResult _handleKey(FocusNode node, KeyEvent event) {
    if (event is! KeyDownEvent && event is! KeyRepeatEvent) {
      return KeyEventResult.ignored;
    }

    final key = event.logicalKey;
    if (key == LogicalKeyboardKey.select || key == LogicalKeyboardKey.enter) {
      setState(() => _isEditing = !_isEditing);
      return KeyEventResult.handled;
    }

    if (!_isEditing && key == LogicalKeyboardKey.arrowUp) {
      widget.onMoveUp?.call();
      return KeyEventResult.handled;
    }
    if (!_isEditing && key == LogicalKeyboardKey.arrowDown) {
      widget.onMoveDown?.call();
      return KeyEventResult.handled;
    }
    if (!_isEditing && key == LogicalKeyboardKey.arrowLeft) {
      widget.onMoveLeft?.call();
      return KeyEventResult.handled;
    }
    if (!_isEditing && key == LogicalKeyboardKey.arrowRight) {
      return KeyEventResult.handled;
    }

    if (!_isEditing) return KeyEventResult.ignored;

    if (key == LogicalKeyboardKey.arrowLeft) {
      widget.onDecrement();
      return KeyEventResult.handled;
    }

    if (key == LogicalKeyboardKey.arrowRight) {
      widget.onIncrement();
      return KeyEventResult.handled;
    }

    if (key == LogicalKeyboardKey.escape) {
      setState(() => _isEditing = false);
      return KeyEventResult.handled;
    }

    return KeyEventResult.ignored;
  }

  @override
  Widget build(BuildContext context) {
    final s = widget.scale;
    final highlight = _isFocused || _isEditing;

    return Focus(
      focusNode: _focusNode,
      onKeyEvent: _handleKey,
      onFocusChange: (value) {
        setState(() {
          _isFocused = value;
          if (!value) _isEditing = false;
        });
      },
      child: InkWell(
        onTap: _focusNode.requestFocus,
        borderRadius: BorderRadius.circular(SacredRadii.md),
        child: AnimatedScale(
          scale: highlight ? 1.01 : 1.0,
          duration: const Duration(milliseconds: 140),
          curve: Curves.easeOutCubic,
          child: AnimatedContainer(
            duration: const Duration(milliseconds: 140),
            curve: Curves.easeOutCubic,
            padding: EdgeInsets.all(18 * s),
            decoration: BoxDecoration(
              color: highlight
                  ? SacredColors.surfaceContainerLow
                  : SacredColors.surfaceContainerLowest,
              borderRadius: BorderRadius.circular(SacredRadii.md),
              border: Border.all(
                color: highlight
                    ? SacredColors.primary.withValues(alpha: 0.95)
                    : SacredColors.outlineVariant.withValues(alpha: 0.25),
                width: highlight ? 3 : 1,
              ),
              boxShadow: highlight
                  ? [
                      BoxShadow(
                        color: SacredColors.primary.withValues(alpha: 0.28),
                        blurRadius: 24 * s,
                        spreadRadius: 2 * s,
                      ),
                    ]
                  : null,
            ),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
              Row(
                children: [
                  Expanded(
                    child: Text(
                      widget.label,
                      style: GoogleFonts.manrope(
                        fontSize: 16 * s,
                        fontWeight: FontWeight.w600,
                        color: SacredColors.onSurface,
                      ),
                    ),
                  ),
                  Container(
                    padding: EdgeInsets.symmetric(
                      horizontal: 14 * s,
                      vertical: 6 * s,
                    ),
                    decoration: BoxDecoration(
                      color: SacredColors.surfaceContainerHighest,
                      borderRadius: BorderRadius.circular(SacredRadii.sm),
                      border: Border.all(
                        color: SacredColors.primary.withValues(alpha: 0.35),
                      ),
                    ),
                    child: Text(
                      widget.valueLabel,
                      style: GoogleFonts.manrope(
                        fontSize: 16 * s,
                        fontWeight: FontWeight.w800,
                        color: SacredColors.primary,
                      ),
                    ),
                  ),
                ],
              ),
              SizedBox(height: 14 * s),
              Row(
                children: [
                  Container(
                    width: 36 * s,
                    height: 36 * s,
                    alignment: Alignment.center,
                    decoration: BoxDecoration(
                      color: _isEditing
                          ? SacredColors.surfaceContainerHigh
                          : SacredColors.surfaceContainerHighest,
                      borderRadius: BorderRadius.circular(SacredRadii.sm),
                      border: Border.all(
                        color: _isEditing
                            ? SacredColors.primary.withValues(alpha: 0.8)
                            : SacredColors.outlineVariant.withValues(alpha: 0.35),
                      ),
                    ),
                    child: Text(
                      '←',
                      style: GoogleFonts.manrope(
                        fontSize: 16 * s,
                        fontWeight: FontWeight.w800,
                        color: SacredColors.onSurface,
                      ),
                    ),
                  ),
                  SizedBox(width: 12 * s),
                  Expanded(
                    child: Container(
                      height: 6 * s,
                      decoration: BoxDecoration(
                        color: SacredColors.outlineVariant.withValues(alpha: 0.2),
                        borderRadius: BorderRadius.circular(3 * s),
                      ),
                      child: FractionallySizedBox(
                        alignment: Alignment.centerLeft,
                        widthFactor: widget.progress.clamp(0.0, 1.0),
                        child: Container(
                          decoration: BoxDecoration(
                            color: SacredColors.primary,
                            borderRadius: BorderRadius.circular(3 * s),
                          ),
                        ),
                      ),
                    ),
                  ),
                  SizedBox(width: 12 * s),
                  Container(
                    width: 36 * s,
                    height: 36 * s,
                    alignment: Alignment.center,
                    decoration: BoxDecoration(
                      color: _isEditing
                          ? SacredColors.surfaceContainerHigh
                          : SacredColors.surfaceContainerHighest,
                      borderRadius: BorderRadius.circular(SacredRadii.sm),
                      border: Border.all(
                        color: _isEditing
                            ? SacredColors.primary.withValues(alpha: 0.8)
                            : SacredColors.outlineVariant.withValues(alpha: 0.35),
                      ),
                    ),
                    child: Text(
                      '→',
                      style: GoogleFonts.manrope(
                        fontSize: 16 * s,
                        fontWeight: FontWeight.w800,
                        color: SacredColors.onSurface,
                      ),
                    ),
                  ),
                ],
              ),
              SizedBox(height: 10 * s),
              Text(
                _isEditing
                    ? 'Mode ubah aktif. Gunakan ← → lalu tekan OK untuk selesai.'
                    : widget.helperText,
                style: GoogleFonts.manrope(
                  fontSize: 11 * s,
                  color: SacredColors.onSurfaceVariant.withValues(alpha: 0.75),
                ),
              ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class _TvEditableTextTileState extends State<_TvEditableTextTile> {
  late final FocusNode _fallbackFocusNode =
      FocusNode(debugLabel: 'tv_edit_tile');
  late final FocusNode _textFocusNode =
      FocusNode(debugLabel: 'tv_edit_text');
  bool _isFocused = false;
  bool _isEditing = false;

  FocusNode get _outerFocusNode => widget.focusNode ?? _fallbackFocusNode;

  @override
  void initState() {
    super.initState();
    _textFocusNode.canRequestFocus = false;
    _textFocusNode.addListener(_handleTextFocusChange);
  }

  @override
  void dispose() {
    _textFocusNode.removeListener(_handleTextFocusChange);
    _textFocusNode.dispose();
    if (widget.focusNode == null) {
      _fallbackFocusNode.dispose();
    }
    super.dispose();
  }

  void _handleTextFocusChange() {
    if (!mounted) return;
    if (!_textFocusNode.hasFocus && _isEditing) {
      _finishEditing();
      return;
    }
    setState(() {});
  }

  void _startEditing() {
    setState(() {
      _isEditing = true;
      _textFocusNode.canRequestFocus = true;
    });
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) {
        _textFocusNode.requestFocus();
      }
    });
  }

  void _finishEditing() {
    if (!mounted) return;
    setState(() {
      _isEditing = false;
      _textFocusNode.canRequestFocus = false;
    });
    widget.onEditComplete?.call();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) {
        _outerFocusNode.requestFocus();
      }
    });
  }

  KeyEventResult _handleKey(FocusNode node, KeyEvent event) {
    if (event is! KeyDownEvent && event is! KeyRepeatEvent) {
      return KeyEventResult.ignored;
    }

    final key = event.logicalKey;
    if (!_isEditing &&
        (key == LogicalKeyboardKey.enter ||
            key == LogicalKeyboardKey.select)) {
      _startEditing();
      return KeyEventResult.handled;
    }

    if (!_isEditing && key == LogicalKeyboardKey.arrowLeft) {
      widget.onMoveLeft?.call();
      return KeyEventResult.handled;
    }

    if (!_isEditing && key == LogicalKeyboardKey.arrowUp) {
      widget.onMoveUp?.call();
      return KeyEventResult.handled;
    }

    if (!_isEditing && key == LogicalKeyboardKey.arrowDown) {
      widget.onMoveDown?.call();
      return KeyEventResult.handled;
    }

    if (_isEditing && key == LogicalKeyboardKey.escape) {
      _finishEditing();
      return KeyEventResult.handled;
    }

    if (_isEditing &&
        widget.maxLines == 1 &&
        (key == LogicalKeyboardKey.enter ||
            key == LogicalKeyboardKey.select)) {
      _finishEditing();
      return KeyEventResult.handled;
    }

    return KeyEventResult.ignored;
  }

  @override
  Widget build(BuildContext context) {
    final s = widget.scale;
    final highlight = _isFocused || _isEditing || _textFocusNode.hasFocus;

    return Focus(
      focusNode: _outerFocusNode,
      onKeyEvent: _handleKey,
      onFocusChange: (value) {
        setState(() {
          _isFocused = value;
        });
      },
      child: InkWell(
        onTap: () {
          if (_isEditing) {
            _textFocusNode.requestFocus();
          } else {
            _startEditing();
          }
        },
        borderRadius: BorderRadius.circular(SacredRadii.md),
        child: AnimatedScale(
          scale: highlight ? 1.01 : 1.0,
          duration: const Duration(milliseconds: 140),
          curve: Curves.easeOutCubic,
          child: AnimatedContainer(
            duration: const Duration(milliseconds: 140),
            curve: Curves.easeOutCubic,
            padding: EdgeInsets.all(18 * s),
            decoration: BoxDecoration(
              color: highlight
                  ? SacredColors.surfaceContainerLow
                  : SacredColors.surfaceContainerLowest,
              borderRadius: BorderRadius.circular(SacredRadii.md),
              border: Border.all(
                color: highlight
                    ? SacredColors.primary.withValues(alpha: 0.95)
                    : SacredColors.outlineVariant.withValues(alpha: 0.35),
                width: highlight ? 3 : 1,
              ),
              boxShadow: highlight
                  ? [
                      BoxShadow(
                        color: SacredColors.primary.withValues(alpha: 0.28),
                        blurRadius: 24 * s,
                        spreadRadius: 2 * s,
                      ),
                    ]
                  : null,
            ),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  widget.label,
                  style: GoogleFonts.manrope(
                    fontSize: 16 * s,
                    fontWeight: FontWeight.w600,
                    color: SacredColors.onSurfaceVariant,
                  ),
                ),
                SizedBox(height: 12 * s),
                AbsorbPointer(
                  absorbing: !_isEditing,
                  child: TextField(
                    focusNode: _textFocusNode,
                    controller: widget.controller,
                    maxLines: widget.maxLines,
                    keyboardType: widget.keyboardType,
                    readOnly: !_isEditing,
                    showCursor: _isEditing,
                    style: GoogleFonts.plusJakartaSans(
                      fontSize: 24 * s,
                      color: SacredColors.onSurface,
                    ),
                    decoration: InputDecoration(
                      filled: true,
                      fillColor: SacredColors.surfaceContainerLowest,
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(SacredRadii.md),
                        borderSide: BorderSide(
                          color: SacredColors.outlineVariant.withValues(alpha: 0.5),
                        ),
                      ),
                      focusedBorder: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(SacredRadii.md),
                        borderSide: const BorderSide(
                          color: SacredColors.primary,
                          width: 2,
                        ),
                      ),
                    ),
                    onChanged: widget.onChanged,
                    onSubmitted: (_) {
                      if (widget.maxLines == 1) {
                        _finishEditing();
                      }
                    },
                  ),
                ),
                SizedBox(height: 8 * s),
                Text(
                  _isEditing
                      ? 'Mode edit aktif. Tekan ESC untuk selesai.'
                      : 'Tekan OK untuk mulai edit.',
                  style: GoogleFonts.manrope(
                    fontSize: 11 * s,
                    color: SacredColors.onSurfaceVariant.withValues(alpha: 0.75),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class _TvFocusFrame extends StatefulWidget {
  final Widget child;
  final double scale;
  final BorderRadius borderRadius;

  const _TvFocusFrame({
    required this.child,
    required this.scale,
    required this.borderRadius,
  });

  @override
  State<_TvFocusFrame> createState() => _TvFocusFrameState();
}

class _TvFocusFrameState extends State<_TvFocusFrame> {
  bool _hasFocus = false;

  @override
  Widget build(BuildContext context) {
    final s = widget.scale;

    return Focus(
      canRequestFocus: false,
      descendantsAreFocusable: true,
      onFocusChange: (value) {
        if (_hasFocus != value) {
          setState(() => _hasFocus = value);
        }
      },
      child: AnimatedScale(
        scale: _hasFocus ? 1.01 : 1.0,
        duration: const Duration(milliseconds: 140),
        curve: Curves.easeOutCubic,
        child: AnimatedContainer(
          duration: const Duration(milliseconds: 140),
          curve: Curves.easeOutCubic,
          padding: EdgeInsets.all(_hasFocus ? 5 * s : 0),
          decoration: BoxDecoration(
            color: _hasFocus
                ? SacredColors.surfaceContainerLow.withValues(alpha: 0.96)
                : Colors.transparent,
            borderRadius: widget.borderRadius,
            border: Border.all(
              color: _hasFocus
                  ? SacredColors.primary.withValues(alpha: 0.95)
                  : Colors.transparent,
              width: _hasFocus ? 3 : 0,
            ),
            boxShadow: _hasFocus
                ? [
                    BoxShadow(
                      color: SacredColors.primary.withValues(alpha: 0.28),
                      blurRadius: 24 * s,
                      spreadRadius: 2 * s,
                    ),
                  ]
                : null,
          ),
          child: widget.child,
        ),
      ),
    );
  }
}

class _NavButtonState extends State<_NavButton> {
  bool _isFocused = false;

  @override
  Widget build(BuildContext context) {
    final s = widget.scale;
    final highlight = widget.isActive || _isFocused;

    return Focus(
      focusNode: widget.focusNode,
      onFocusChange: widget.onFocusChange,
      onKeyEvent: widget.onKeyEvent,
      child: FocusableActionDetector(
        onShowFocusHighlight: (value) => setState(() => _isFocused = value),
        child: InkWell(
          onTap: widget.onTap,
          focusColor: SacredColors.primary.withValues(alpha: 0.22),
          hoverColor: SacredColors.primary.withValues(alpha: 0.12),
          borderRadius: BorderRadius.circular(SacredRadii.lg),
          child: AnimatedScale(
            scale: highlight ? 1.01 : 1.0,
            duration: const Duration(milliseconds: 140),
            curve: Curves.easeOutCubic,
            child: AnimatedContainer(
              duration: const Duration(milliseconds: 140),
              curve: Curves.easeOutCubic,
              width: double.infinity,
              padding: EdgeInsets.symmetric(horizontal: 24 * s, vertical: 24 * s),
              decoration: BoxDecoration(
                color: highlight
                    ? SacredColors.surfaceContainerLow
                    : Colors.transparent,
                borderRadius: BorderRadius.circular(SacredRadii.lg),
                border: highlight
                    ? Border.all(
                        color: SacredColors.primary.withValues(alpha: 0.95),
                        width: 3,
                      )
                    : null,
                boxShadow: highlight
                    ? [
                        BoxShadow(
                          color: SacredColors.primary.withValues(alpha: 0.24),
                          blurRadius: 22 * s,
                          spreadRadius: 1 * s,
                        ),
                      ]
                    : null,
              ),
              child: Row(
                children: [
                HugeIcon(
                  icon: widget.icon,
                  color: highlight
                      ? SacredColors.onSurface
                      : SacredColors.onSurfaceVariant,
                  size: 28 * s,
                ),
                SizedBox(width: 20 * s),
                Expanded(
                  child: Text(
                    widget.title,
                    style: GoogleFonts.plusJakartaSans(
                      fontSize: 18 * s,
                      fontWeight: FontWeight.bold,
                      color: highlight
                          ? SacredColors.onSurface
                          : SacredColors.onSurfaceVariant,
                      letterSpacing: 1 * s,
                    ),
                  ),
                ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}
