import 'package:flutter/material.dart'; import 'package:mobile_monitoring/core/constants/constants.dart'; import 'package:mobile_monitoring/ui/widgets/growth_phase_service.dart'; import 'package:mobile_monitoring/core/utils/phase_display_utils.dart'; class GrowthPhaseCard extends StatefulWidget { const GrowthPhaseCard({super.key}); @override State createState() => _GrowthPhaseCardState(); } class _GrowthPhaseCardState extends State { final _growthPhaseService = GrowthPhaseService(); void _showSnackBar(String msg, {bool isError = false}) { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(msg), backgroundColor: isError ? AppColors.error : (msg.contains('✓') ? AppColors.success : AppColors.info), duration: const Duration(seconds: 2), ), ); } Future _setPlantingDate() async { final userId = _growthPhaseService.getCurrentUserId(); if (userId.isEmpty) return; final picked = await showDatePicker( context: context, initialDate: DateTime.now(), firstDate: DateTime(2020), lastDate: DateTime.now(), builder: (context, child) => Theme( data: Theme.of(context).copyWith( colorScheme: const ColorScheme.light(primary: AppColors.primary), ), child: child!, ), ); if (picked != null) { final result = await _growthPhaseService.savePlantingDate( userId: userId, plantingDate: picked, ); _showSnackBar( result.success ? '✓ ${result.message}!' : result.message, isError: !result.success, ); } } Future _resetCycle() async { final userId = _growthPhaseService.getCurrentUserId(); if (userId.isEmpty) return; final confirmed = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Reset Siklus?'), content: const Text('Data tanggal tanam sebelumnya akan dihapus.'), actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), child: const Text('Batal'), ), ElevatedButton( onPressed: () => Navigator.pop(ctx, true), style: ElevatedButton.styleFrom(backgroundColor: AppColors.error), child: const Text('Reset'), ), ], ), ); if (confirmed == true) { final result = await _growthPhaseService.resetCycle(userId); _showSnackBar( result.success ? '✓ ${result.message}!' : result.message, isError: !result.success, ); } } Future _markHarvest() async { final userId = _growthPhaseService.getCurrentUserId(); if (userId.isEmpty) return; final result = await _growthPhaseService.markHarvest(userId); _showSnackBar( result.success ? '✓ ${result.message}' : result.message, isError: !result.success, ); } Future _updatePhaseIfChanged( String currentPhaseInDb, String calculatedPhase, int days, DateTime startDate, ) async { final userId = _growthPhaseService.getCurrentUserId(); if (userId.isEmpty) return; try { await _growthPhaseService.updatePhaseIfChanged( userId: userId, currentPhaseInDb: currentPhaseInDb, calculatedPhase: calculatedPhase, days: days, startDate: startDate, ); _showSnackBar('✓ Fase otomatis diperbarui ke $calculatedPhase'); } catch (e) { debugPrint('✗ Error updating phase: $e'); } } @override Widget build(BuildContext context) { final user = _growthPhaseService.getCurrentUser(); if (user == null) { return _buildCard( child: const Text('Silakan login untuk melihat fase pertumbuhan.'), ); } return StreamBuilder?>( stream: _growthPhaseService.activeCycleStream(user.uid), builder: (context, snapshot) { if (snapshot.hasError) { return _buildCard(child: Text('Error: ${snapshot.error}')); } if (snapshot.connectionState == ConnectionState.waiting) { return _buildCard( child: const Center(child: CircularProgressIndicator()), ); } final data = snapshot.data; if (data == null) { return _buildEmptyState(); } final startDate = _growthPhaseService.extractStartDate(data); final currentPhaseInDb = data['growth_phase'] as String?; if (startDate != null) { final days = DateTime.now().difference(startDate).inDays; final calculatedPhase = _growthPhaseService.calculateCurrentPhase( days, ); final currentPhase = (currentPhaseInDb != null && currentPhaseInDb.isNotEmpty) ? currentPhaseInDb : calculatedPhase; if (currentPhaseInDb != null && currentPhaseInDb != calculatedPhase) { Future.microtask( () => _updatePhaseIfChanged( currentPhaseInDb, calculatedPhase, days, startDate, ), ); } return _buildActiveState( daysSincePlanting: days, startDate: startDate, currentPhase: currentPhase, ); } return _buildEmptyState(); }, ); } Widget _buildCard({required Widget child}) { return Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: AppColors.white, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: _growthPhaseService.applyAlpha(AppColors.darkGray, 0.1), spreadRadius: 2, blurRadius: 10, ), ], ), child: child, ); } Widget _buildEmptyState() { return _buildCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: _growthPhaseService.applyAlpha(AppColors.primary, 0.1), borderRadius: BorderRadius.circular(12), ), child: const Icon( Icons.eco, color: AppColors.primary, size: 24, ), ), const SizedBox(width: 12), const Expanded( child: Text( 'Fase Pertumbuhan', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), ], ), const SizedBox(height: 16), const Text( 'Belum ada siklus tanam aktif', style: TextStyle(fontSize: 14, color: Colors.grey), ), const SizedBox(height: 12), SizedBox( width: double.infinity, child: ElevatedButton.icon( onPressed: _setPlantingDate, icon: const Icon(Icons.event, size: 20), label: const Text('Mulai Tanam'), style: ElevatedButton.styleFrom( backgroundColor: AppColors.primary, foregroundColor: AppColors.white, padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), ), ), ], ), ); } Widget _buildActiveState({ required int daysSincePlanting, DateTime? startDate, required String currentPhase, }) { final phaseColor = _growthPhaseService.getPhaseColor(currentPhase); final phaseData = _growthPhaseService.getPhaseData(daysSincePlanting); final phaseDay = phaseData['day'] as int; final phaseDuration = phaseData['duration'] as int; final progress = phaseData['progress'] as double; return _buildCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: _growthPhaseService.applyAlpha(phaseColor, 0.1), borderRadius: BorderRadius.circular(12), ), child: Icon(Icons.eco, color: phaseColor, size: 24), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Fase Pertumbuhan', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), Text( 'Hari ke-$daysSincePlanting', style: TextStyle(fontSize: 12, color: Colors.grey[600]), ), ], ), ), IconButton( icon: const Icon(Icons.refresh, size: 20), onPressed: _resetCycle, padding: EdgeInsets.zero, constraints: const BoxConstraints(), ), ], ), const SizedBox(height: 16), Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: _growthPhaseService.applyAlpha(phaseColor, 0.15), borderRadius: BorderRadius.circular(20), border: Border.all(color: phaseColor, width: 1.5), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.circle, color: phaseColor, size: 12), const SizedBox(width: 8), Text( 'Fase $currentPhase', style: TextStyle( color: phaseColor, fontWeight: FontWeight.bold, ), ), Text( ' (Hari $phaseDay/$phaseDuration)', style: TextStyle(color: phaseColor, fontSize: 12), ), ], ), ), const SizedBox(height: 16), ClipRRect( borderRadius: BorderRadius.circular(10), child: LinearProgressIndicator( value: progress.clamp(0.0, 1.0), backgroundColor: Colors.grey[200], color: phaseColor, minHeight: 8, ), ), const SizedBox(height: 20), const Divider(), const SizedBox(height: 12), Row( children: List.generate(PhaseDisplayUtils.ordered.length, (index) { final phase = PhaseDisplayUtils.ordered[index]; final isActive = phase.name.toLowerCase() == currentPhase.toLowerCase(); final isPassed = daysSincePlanting >= phase.startDay; return Expanded( child: Padding( padding: EdgeInsets.only( right: index < PhaseDisplayUtils.ordered.length - 1 ? 8 : 0, ), child: _buildPhaseItem( phase.name, phase.dayRangeLabel, phase.color, isActive, isPassed, ), ), ); }), ), if (startDate != null) ...[ const SizedBox(height: 16), Row( children: [ Icon(Icons.event, size: 16, color: Colors.grey[600]), const SizedBox(width: 6), Text( 'Mulai: ${_growthPhaseService.formatDate(startDate)}', style: TextStyle(fontSize: 12, color: Colors.grey[600]), ), ], ), ], const SizedBox(height: 16), Row( children: [ Expanded( child: OutlinedButton.icon( onPressed: _resetCycle, icon: const Icon(Icons.refresh, size: 16), label: const Text('Reset'), style: OutlinedButton.styleFrom( foregroundColor: AppColors.error, side: const BorderSide(color: AppColors.error), ), ), ), const SizedBox(width: 12), Expanded( child: ElevatedButton.icon( onPressed: _markHarvest, icon: const Icon(Icons.agriculture, size: 16), label: const Text('Panen'), style: ElevatedButton.styleFrom( backgroundColor: AppColors.primary, ), ), ), ], ), ], ), ); } Widget _buildPhaseItem( String name, String range, Color color, bool isActive, bool isPassed, ) { return Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: isActive ? _growthPhaseService.applyAlpha(color, 0.15) : (isPassed ? Colors.grey[100] : Colors.grey[50]), borderRadius: BorderRadius.circular(8), border: Border.all( color: isActive ? color : (isPassed ? Colors.grey : Colors.grey[300]!), width: isActive ? 2 : 1, ), ), child: Column( children: [ Icon( isPassed ? Icons.check_circle : Icons.circle_outlined, size: 18, color: isActive ? color : (isPassed ? Colors.grey : Colors.grey[400]), ), const SizedBox(height: 4), Text( name, style: TextStyle( fontSize: 10, fontWeight: isActive ? FontWeight.bold : FontWeight.normal, color: isActive ? color : (isPassed ? Colors.grey : Colors.grey[600]), ), textAlign: TextAlign.center, ), Text( range, style: TextStyle(fontSize: 8, color: Colors.grey[500]), textAlign: TextAlign.center, ), ], ), ); } }