import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../core/app_theme.dart'; import '../../../features/auth/auth_notifier.dart'; import '../../../features/auth/auth_state.dart'; import '../providers/control_notifier.dart'; import '../providers/monitoring_provider.dart'; import '../widgets/device_status_card.dart'; import '../widgets/device_control_section.dart'; import '../widgets/greeting_section.dart'; import '../widgets/schedule_section.dart'; import '../widgets/add_schedule_sheet.dart'; import '../widgets/operation_mode_card.dart'; class ControlPage extends ConsumerWidget { const ControlPage({super.key}); void _onAddSchedule(BuildContext context, WidgetRef ref) { showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (ctx) => AddScheduleSheet( onSave: (time, days, durationS) { ref.read(controlProvider.notifier).addSchedule(time, days, durationS); }, ), ); } void _showManualDurationDialog(BuildContext context, WidgetRef ref) { int selectedDuration = 30; // default showDialog( context: context, builder: (ctx) { return StatefulBuilder( builder: (context, setState) { return AlertDialog( title: const Text('Lama Penyiraman'), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('Pilih durasi pompa menyala secara manual:'), const SizedBox(height: 16), Wrap( spacing: 8, runSpacing: 8, children: [ {'label': '15s', 'val': 15}, {'label': '30s', 'val': 30}, {'label': '1m', 'val': 60}, {'label': '2m', 'val': 120}, {'label': '5m', 'val': 300}, ].map((opt) { final val = opt['val'] as int; final isSelected = selectedDuration == val; return ChoiceChip( label: Text(opt['label'] as String), selected: isSelected, onSelected: (bool selected) { if (selected) { setState(() => selectedDuration = val); } }, selectedColor: AppTheme.primary, labelStyle: TextStyle( color: isSelected ? Colors.white : AppTheme.textSecondary, fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, ), backgroundColor: Colors.grey.shade200, ); }).toList(), ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: const Text('Batal'), ), ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: AppTheme.primary), onPressed: () { Navigator.pop(ctx); ref.read(controlProvider.notifier).togglePump(selectedDuration); }, child: const Text('Mulai', style: TextStyle(color: Colors.white)), ), ], ); }, ); }, ); } void _showStopConfirmationDialog(BuildContext context, WidgetRef ref) { showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Hentikan Penyiraman?'), content: const Text('Apakah Anda yakin ingin mematikan pompa saat ini?'), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: const Text('Batal'), ), ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: AppTheme.statusDanger), onPressed: () { Navigator.pop(ctx); ref.read(controlProvider.notifier).togglePump(); }, child: const Text('Matikan', style: TextStyle(color: Colors.white)), ), ], ), ); } void _confirmDelete(BuildContext context, WidgetRef ref, String id) { showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Hapus Jadwal?'), content: const Text('Jadwal ini akan dihapus secara permanen.'), actions: [ TextButton( onPressed: () => Navigator.of(ctx).pop(), child: const Text('Batal'), ), TextButton( style: TextButton.styleFrom(foregroundColor: AppTheme.statusDanger), onPressed: () { Navigator.of(ctx).pop(); ref.read(controlProvider.notifier).removeSchedule(id); }, child: const Text('Hapus'), ), ], ), ); } String _getUserName(WidgetRef ref) { final authState = ref.watch(authProvider); if (authState is AuthSuccess) return authState.user.name; return 'Pengguna'; } String _getDeviceCode(WidgetRef ref) { final authState = ref.watch(authProvider); if (authState is AuthSuccess) return authState.user.deviceId ?? '-'; return '-'; } bool _checkIsOnline(WidgetRef ref) { return ref.watch(monitoringProvider).isDeviceOnline; } @override Widget build(BuildContext context, WidgetRef ref) { // ── Listener untuk Snackbar Error & Success ── ref.listen(controlProvider, (prev, next) { if (next.errorMessage != null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(next.errorMessage!), backgroundColor: AppTheme.statusDanger, ), ); ref.read(controlProvider.notifier).clearMessage(); } if (next.successMessage != null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(next.successMessage!), backgroundColor: AppTheme.statusNormal, ), ); ref.read(controlProvider.notifier).clearMessage(); } }); final control = ref.watch(controlProvider); final notifier = ref.read(controlProvider.notifier); final userName = _getUserName(ref); final deviceCode = _getDeviceCode(ref); final isOnline = _checkIsOnline(ref); final authState = ref.watch(authProvider); final hasDevice = authState is AuthSuccess && authState.user.deviceId != null; return Scaffold( backgroundColor: AppTheme.bgPage, body: SafeArea( child: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ GreetingSection( userName: userName, subtitle: hasDevice ? 'Selamat Datang di Kontrol Panel' : 'Kontrol Panel Nonaktif', ), const SizedBox(height: 20), if (!hasDevice) ...[ const SizedBox(height: 40), Container( width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 36), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(24), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.04), blurRadius: 16, offset: const Offset(0, 4), ), ], ), child: const Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.sensors_off_outlined, size: 64, color: Colors.grey, ), SizedBox(height: 24), Text( 'Kontrol Perangkat Dinonaktifkan', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppTheme.textPrimary, ), ), SizedBox(height: 12), Text( 'Silakan hubungkan perangkat kumbung jamur Anda terlebih dahulu pada halaman Monitoring (tab pertama) dengan menekan tombol + dan memasukkan Claim Code Anda.', textAlign: TextAlign.center, style: TextStyle( fontSize: 13, color: AppTheme.textSecondary, height: 1.5, ), ), ], ), ), ] else ...[ DeviceStatusCard( isOnline: isOnline, deviceCode: deviceCode, lastSeen: ref.watch(monitoringProvider).latest?.timestamp, ), const SizedBox(height: 20), const OperationModeCard(), const SizedBox(height: 16), DeviceControlSection( isPumpOn: control.isPumpOn, isOnline: isOnline, suhuMinLimit: control.suhuMinLimit, suhuMaxLimit: control.suhuMaxLimit, kelembapanLimit: control.kelembapanLimit, activePumpDuration: control.activePumpDuration, pumpTurnedOnAt: control.pumpTurnedOnAt, onPumpToggle: () { if (control.isPumpOn) { _showStopConfirmationDialog(context, ref); } else { _showManualDurationDialog(context, ref); } }, onSaveThreshold: (suhuMin, suhuMax, kelembapan) => notifier.saveThreshold(suhuMin, suhuMax, kelembapan), ), const SizedBox(height: 20), // Jika sedang loading initial data, tampilkan loading utama if (control.isLoading && control.schedules.isEmpty) const Center(child: CircularProgressIndicator()) else ...[ // Jika loading tapi schedules sudah ada (misal proses tambah jadwal), // tampilkan progress bar tipis di atas section if (control.isLoading && control.schedules.isNotEmpty) const LinearProgressIndicator(), ScheduleSection( schedules: control.schedules, onAddSchedule: () => _onAddSchedule(context, ref), onToggleSchedule: (id, _) => notifier.toggleSchedule(id), onRemoveSchedule: (id) => _confirmDelete(context, ref, id), ), ], const SizedBox(height: 20), _buildWateringReferenceCard(), ], ], ), ), ), ); } Widget _buildWateringReferenceCard() { return Container( width: double.infinity, padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.02), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: const EdgeInsets.all(6), decoration: const BoxDecoration( color: Color(0xFFE0F2F1), // Light teal background matching theme shape: BoxShape.circle, ), child: const Icon(Icons.info_outline, color: AppTheme.primary, size: 16), ), const SizedBox(width: 10), const Text( 'Panduan Penyiraman Terbaik', style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: AppTheme.textPrimary, ), ), ], ), const SizedBox(height: 12), const Text( 'Untuk menjaga kualitas tumbuh kembang Jamur Tiram, berikut adalah rekomendasi waktu & frekuensi penyiraman otomatis/manual:', style: TextStyle(fontSize: 12, color: AppTheme.textSecondary, height: 1.4), ), const SizedBox(height: 12), Row( children: [ Expanded( child: _buildWateringIndicator( icon: Icons.schedule, iconColor: Colors.orange, label: 'Waktu Terbaik', value: 'Pagi & Sore', ), ), const SizedBox(width: 12), Expanded( child: _buildWateringIndicator( icon: Icons.loop, iconColor: Colors.blue, label: 'Frekuensi Ideal', value: '2 - 3 Kali / Hari', ), ), ], ), const SizedBox(height: 12), Divider(color: Colors.grey.shade100), const SizedBox(height: 8), const Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(Icons.tips_and_updates_outlined, size: 16, color: Colors.orangeAccent), SizedBox(width: 8), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Tips Penyiraman:', style: TextStyle( fontSize: 12, fontWeight: FontWeight.bold, color: AppTheme.textPrimary, ), ), SizedBox(height: 4), Text( '• Pagi (06.00-08.00 WIB) & Sore (16.00-18.00 WIB) membantu menyeimbangkan penguapan air di siang hari.\n• Hindari penyiraman berlebih jika kelembapan kumbung sudah di atas 80% atau saat hujan lebat agar baglog tidak membusuk.', style: TextStyle(fontSize: 11, color: AppTheme.textSecondary, height: 1.5), ), ], ), ), ], ), ], ), ); } Widget _buildWateringIndicator({ required IconData icon, required Color iconColor, required String label, required String value, }) { return Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: iconColor.withValues(alpha: 0.05), borderRadius: BorderRadius.circular(12), border: Border.all(color: iconColor.withValues(alpha: 0.1)), ), child: Row( children: [ Icon(icon, color: iconColor, size: 20), const SizedBox(width: 8), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: const TextStyle(fontSize: 9, color: AppTheme.textSecondary), ), const SizedBox(height: 2), Text( value, style: TextStyle( fontSize: 12, fontWeight: FontWeight.bold, color: iconColor.withValues(alpha: 0.9), ), ), ], ), ], ), ); } }