import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:google_fonts/google_fonts.dart'; import '../../models/cycle_entry.dart'; import '../../providers/navigation_provider.dart'; import '../../providers/user_provider.dart'; import '../../theme/app_theme.dart'; import 'package:uuid/uuid.dart'; class LogScreen extends ConsumerStatefulWidget { final DateTime? initialDate; const LogScreen({super.key, this.initialDate}); @override ConsumerState createState() => _LogScreenState(); } class _LogScreenState extends ConsumerState { late DateTime _selectedDate; String? _existingEntryId; bool _isPeriodDay = false; FlowIntensity? _flowIntensity; MoodLevel? _mood; int? _energyLevel; int _crampIntensity = 0; bool _hasHeadache = false; bool _hasBloating = false; bool _hasBreastTenderness = false; bool _hasFatigue = false; bool _hasAcne = false; bool _hasLowerBackPain = false; bool _hasConstipation = false; bool _hasDiarrhea = false; bool _hasInsomnia = false; int? _stressLevel; final TextEditingController _notesController = TextEditingController(); final TextEditingController _cravingsController = TextEditingController(); // Intimacy tracking bool _hadIntimacy = false; bool? _intimacyProtected; // null = no selection, true = protected, false = unprotected // Hidden field to preserve husband's notes String? _husbandNotes; @override void initState() { super.initState(); _selectedDate = widget.initialDate ?? DateTime.now(); // Defer data loading to avoid build-time ref.read WidgetsBinding.instance.addPostFrameCallback((_) { _loadExistingData(); }); } void _loadExistingData() { final entries = ref.read(cycleEntriesProvider); try { final entry = entries.firstWhere( (e) => DateUtils.isSameDay(e.date, _selectedDate), ); setState(() { _existingEntryId = entry.id; _isPeriodDay = entry.isPeriodDay; _flowIntensity = entry.flowIntensity; _mood = entry.mood; _energyLevel = entry.energyLevel; _crampIntensity = entry.crampIntensity ?? 0; _hasHeadache = entry.hasHeadache; _hasBloating = entry.hasBloating; _hasBreastTenderness = entry.hasBreastTenderness; _hasFatigue = entry.hasFatigue; _hasAcne = entry.hasAcne; _hasLowerBackPain = entry.hasLowerBackPain; _hasConstipation = entry.hasConstipation; _hasDiarrhea = entry.hasDiarrhea; _hasInsomnia = entry.hasInsomnia; _stressLevel = entry.stressLevel; _notesController.text = entry.notes ?? ''; _cravingsController.text = entry.cravings?.join(', ') ?? ''; _husbandNotes = entry.husbandNotes; _hadIntimacy = entry.hadIntimacy; _intimacyProtected = entry.intimacyProtected; }); } catch (_) { // No existing entry for this day } } @override void dispose() { _notesController.dispose(); _cravingsController.dispose(); super.dispose(); } Future _saveEntry() async { List? cravings; if (_cravingsController.text.isNotEmpty) { cravings = _cravingsController.text .split(',') .map((e) => e.trim()) .where((e) => e.isNotEmpty) .toList(); } final entry = CycleEntry( id: _existingEntryId ?? const Uuid().v4(), date: _selectedDate, isPeriodDay: _isPeriodDay, flowIntensity: _isPeriodDay ? _flowIntensity : null, mood: _mood, energyLevel: _energyLevel, crampIntensity: _crampIntensity > 0 ? _crampIntensity : null, hasHeadache: _hasHeadache, hasBloating: _hasBloating, hasBreastTenderness: _hasBreastTenderness, hasFatigue: _hasFatigue, hasAcne: _hasAcne, hasLowerBackPain: _hasLowerBackPain, hasConstipation: _hasConstipation, hasDiarrhea: _hasDiarrhea, hasInsomnia: _hasInsomnia, stressLevel: _stressLevel, notes: _notesController.text.isNotEmpty ? _notesController.text : null, cravings: cravings, husbandNotes: _husbandNotes, hadIntimacy: _hadIntimacy, intimacyProtected: _hadIntimacy ? _intimacyProtected : null, createdAt: DateTime.now(), updatedAt: DateTime.now(), ); if (_existingEntryId != null) { await ref.read(cycleEntriesProvider.notifier).updateEntry(entry); } else { await ref.read(cycleEntriesProvider.notifier).addEntry(entry); } if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Entry saved!', style: GoogleFonts.outfit()), backgroundColor: AppColors.success, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), ); if (widget.initialDate != null) { Navigator.pop(context); } else { _resetForm(); } } } void _resetForm() { setState(() { _existingEntryId = null; _isPeriodDay = false; _flowIntensity = null; _mood = null; _energyLevel = 3; _crampIntensity = 0; _hasHeadache = false; _hasBloating = false; _hasBreastTenderness = false; _hasFatigue = false; _hasAcne = false; _hasLowerBackPain = false; _hasConstipation = false; _hasDiarrhea = false; _hasInsomnia = false; _stressLevel = 1; _notesController.clear(); _cravingsController.clear(); _husbandNotes = null; _hadIntimacy = false; _intimacyProtected = null; }); } @override Widget build(BuildContext context) { final theme = Theme.of(context); final isDark = theme.brightness == Brightness.dark; return SafeArea( child: SingleChildScrollView( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'How are you feeling?', style: GoogleFonts.outfit( fontSize: 28, fontWeight: FontWeight.w600, color: theme.colorScheme.onSurface, ), ), Text( _formatDate(_selectedDate), style: GoogleFonts.outfit( fontSize: 14, color: theme.colorScheme.onSurfaceVariant, ), ), ], ), if (widget.initialDate == null) IconButton( onPressed: () => ref.read(navigationProvider.notifier).setIndex(0), icon: const Icon(Icons.close), style: IconButton.styleFrom( backgroundColor: theme.colorScheme.surfaceVariant.withOpacity(0.5), ), ), ], ), const SizedBox(height: 24), // Period Toggle _buildSectionCard( context, title: 'Period', child: Row( children: [ Expanded( child: Text( 'Is today a period day?', style: GoogleFonts.outfit( fontSize: 16, color: theme.colorScheme.onSurface, ), ), ), Switch( value: _isPeriodDay, onChanged: (value) => setState(() => _isPeriodDay = value), activeColor: AppColors.menstrualPhase, ), ], ), ), // Flow Intensity (only if period day) if (_isPeriodDay) ...[ const SizedBox(height: 16), _buildSectionCard( context, title: 'Flow Intensity', child: Row( children: FlowIntensity.values.map((flow) { final isSelected = _flowIntensity == flow; return Expanded( child: GestureDetector( onTap: () => setState(() => _flowIntensity = flow), child: AnimatedContainer( duration: const Duration(milliseconds: 200), margin: const EdgeInsets.symmetric(horizontal: 4), padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( color: isSelected ? AppColors.menstrualPhase .withOpacity(isDark ? 0.3 : 0.2) : theme.colorScheme.surfaceVariant .withOpacity(0.3), borderRadius: BorderRadius.circular(10), border: isSelected ? Border.all(color: AppColors.menstrualPhase) : Border.all(color: Colors.transparent), ), child: Column( children: [ Icon( Icons.water_drop, color: isSelected ? AppColors.menstrualPhase : theme.colorScheme.onSurfaceVariant, size: 20, ), const SizedBox(height: 4), Text( flow.label, style: GoogleFonts.outfit( fontSize: 11, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, color: isSelected ? AppColors.menstrualPhase : theme.colorScheme.onSurfaceVariant, ), ), ], ), ), ), ); }).toList(), ), ), ], const SizedBox(height: 16), // Mood _buildSectionCard( context, title: 'Mood', child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: MoodLevel.values.map((mood) { final isSelected = _mood == mood; return GestureDetector( onTap: () => setState(() => _mood = mood), child: AnimatedContainer( duration: const Duration(milliseconds: 200), padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: isSelected ? AppColors.softGold .withOpacity(isDark ? 0.3 : 0.2) : Colors.transparent, borderRadius: BorderRadius.circular(12), border: isSelected ? Border.all(color: AppColors.softGold) : Border.all(color: Colors.transparent), ), child: Column( children: [ Text( mood.emoji, style: TextStyle( fontSize: isSelected ? 32 : 28, ), ), const SizedBox(height: 4), Text( mood.label, style: GoogleFonts.outfit( fontSize: 10, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, color: isSelected ? AppColors.softGold : theme.colorScheme.onSurfaceVariant, ), ), ], ), ), ); }).toList(), ), ), const SizedBox(height: 16), // Energy & Stress Levels _buildSectionCard( context, title: 'Daily Levels', child: Column( children: [ // Energy Level Row( children: [ SizedBox( width: 80, child: Text( 'Energy', style: GoogleFonts.outfit( fontSize: 14, color: theme.colorScheme.onSurface, ), ), ), Expanded( child: Slider( value: (_energyLevel ?? 3).toDouble(), min: 1, max: 5, divisions: 4, activeColor: AppColors.sageGreen, onChanged: (value) { setState(() => _energyLevel = value.round()); }, ), ), SizedBox( width: 50, child: Text( _getEnergyLabel(_energyLevel), textAlign: TextAlign.end, style: GoogleFonts.outfit( fontSize: 11, color: theme.colorScheme.onSurfaceVariant, ), ), ), ], ), const SizedBox(height: 12), // Stress Level Row( children: [ SizedBox( width: 80, child: Text( 'Stress', style: GoogleFonts.outfit( fontSize: 14, color: theme.colorScheme.onSurface, ), ), ), Expanded( child: Slider( value: (_stressLevel ?? 1).toDouble(), min: 1, max: 5, divisions: 4, activeColor: AppColors.ovulationPhase, onChanged: (value) { setState(() => _stressLevel = value.round()); }, ), ), SizedBox( width: 50, child: Text( '${_stressLevel ?? 1}/5', textAlign: TextAlign.end, style: GoogleFonts.outfit( fontSize: 12, color: theme.colorScheme.onSurfaceVariant, ), ), ), ], ), ], ), ), const SizedBox(height: 16), // Symptoms _buildSectionCard( context, title: 'Symptoms', child: Column( children: [ // Cramps Slider Row( children: [ SizedBox( width: 80, child: Text( 'Cramps', style: GoogleFonts.outfit( fontSize: 14, color: theme.colorScheme.onSurface, ), ), ), Expanded( child: Slider( value: _crampIntensity.toDouble(), min: 0, max: 5, divisions: 5, activeColor: AppColors.rose, onChanged: (value) { setState(() => _crampIntensity = value.round()); }, ), ), SizedBox( width: 50, child: Text( _crampIntensity == 0 ? 'None' : '$_crampIntensity/5', textAlign: TextAlign.end, style: GoogleFonts.outfit( fontSize: 11, color: theme.colorScheme.onSurfaceVariant, ), ), ), ], ), const SizedBox(height: 12), // Symptom Toggles Wrap( spacing: 8, runSpacing: 8, children: [ _buildSymptomChip(context, 'Headache', _hasHeadache, (v) => setState(() => _hasHeadache = v)), _buildSymptomChip(context, 'Bloating', _hasBloating, (v) => setState(() => _hasBloating = v)), _buildSymptomChip(context, 'Breast Tenderness', _hasBreastTenderness, (v) => setState(() => _hasBreastTenderness = v)), _buildSymptomChip(context, 'Fatigue', _hasFatigue, (v) => setState(() => _hasFatigue = v)), _buildSymptomChip(context, 'Acne', _hasAcne, (v) => setState(() => _hasAcne = v)), _buildSymptomChip(context, 'Back Pain', _hasLowerBackPain, (v) => setState(() => _hasLowerBackPain = v)), _buildSymptomChip( context, 'Constipation', _hasConstipation, (v) => setState(() => _hasConstipation = v)), _buildSymptomChip(context, 'Diarrhea', _hasDiarrhea, (v) => setState(() => _hasDiarrhea = v)), _buildSymptomChip(context, 'Insomnia', _hasInsomnia, (v) => setState(() => _hasInsomnia = v)), ], ), ], ), ), const SizedBox(height: 16), // Cravings _buildSectionCard( context, title: 'Cravings', child: TextField( controller: _cravingsController, decoration: InputDecoration( hintText: 'e.g., Chocolate, salty chips (comma separated)', filled: true, fillColor: isDark ? theme.colorScheme.surface : theme.colorScheme.surfaceVariant.withOpacity(0.1), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), ), style: GoogleFonts.outfit( fontSize: 14, color: theme.colorScheme.onSurface, ), ), ), const SizedBox(height: 16), // Intimacy Tracking (for married users) _buildSectionCard( context, title: 'Intimacy', child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SwitchListTile( title: Text('Had Intimacy Today', style: GoogleFonts.outfit(fontSize: 14)), value: _hadIntimacy, onChanged: (val) => setState(() { _hadIntimacy = val; if (!val) _intimacyProtected = null; }), activeColor: AppColors.sageGreen, contentPadding: EdgeInsets.zero, ), if (_hadIntimacy) ...[ const SizedBox(height: 8), Text('Protection:', style: GoogleFonts.outfit(fontSize: 13, color: AppColors.warmGray)), const SizedBox(height: 8), Row( children: [ Expanded( child: GestureDetector( onTap: () => setState(() => _intimacyProtected = true), child: Container( padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( color: _intimacyProtected == true ? AppColors.sageGreen.withOpacity(0.2) : Colors.grey.withOpacity(0.1), borderRadius: BorderRadius.circular(8), border: Border.all( color: _intimacyProtected == true ? AppColors.sageGreen : Colors.grey.withOpacity(0.3), ), ), child: Center( child: Text( 'Protected', style: GoogleFonts.outfit( fontWeight: FontWeight.w500, color: _intimacyProtected == true ? AppColors.sageGreen : AppColors.warmGray, ), ), ), ), ), ), const SizedBox(width: 12), Expanded( child: GestureDetector( onTap: () => setState(() => _intimacyProtected = false), child: Container( padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( color: _intimacyProtected == false ? AppColors.rose.withOpacity(0.15) : Colors.grey.withOpacity(0.1), borderRadius: BorderRadius.circular(8), border: Border.all( color: _intimacyProtected == false ? AppColors.rose : Colors.grey.withOpacity(0.3), ), ), child: Center( child: Text( 'Unprotected', style: GoogleFonts.outfit( fontWeight: FontWeight.w500, color: _intimacyProtected == false ? AppColors.rose : AppColors.warmGray, ), ), ), ), ), ), ], ), ], ], ), ), const SizedBox(height: 16), // Notes _buildSectionCard( context, title: 'Notes', child: TextField( controller: _notesController, maxLines: 3, decoration: InputDecoration( hintText: 'Add any notes about how you\'re feeling...', filled: true, fillColor: isDark ? theme.colorScheme.surface : theme.colorScheme.surfaceVariant.withOpacity(0.1), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), ), style: GoogleFonts.outfit( fontSize: 14, color: theme.colorScheme.onSurface, ), ), ), const SizedBox(height: 24), // Save Button SizedBox( width: double.infinity, height: 54, child: ElevatedButton( onPressed: _saveEntry, child: const Text('Save Entry'), ), ), const SizedBox(height: 40), ], ), ), ); } Widget _buildSectionCard(BuildContext context, {required String title, required Widget child}) { final theme = Theme.of(context); final isDark = theme.brightness == Brightness.dark; return Container( width: double.infinity, padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: theme.cardTheme.color, borderRadius: BorderRadius.circular(16), border: Border.all(color: theme.colorScheme.outline.withOpacity(0.05)), boxShadow: isDark ? null : [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: GoogleFonts.outfit( fontSize: 16, fontWeight: FontWeight.w600, color: theme.colorScheme.onSurface, ), ), const SizedBox(height: 12), child, ], ), ); } Widget _buildSymptomChip(BuildContext context, String label, bool isSelected, ValueChanged onChanged) { final theme = Theme.of(context); final isDark = theme.brightness == Brightness.dark; return Material( color: Colors.transparent, child: InkWell( onTap: () => onChanged(!isSelected), borderRadius: BorderRadius.circular(20), child: AnimatedContainer( duration: const Duration(milliseconds: 200), padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), decoration: BoxDecoration( color: isSelected ? theme.colorScheme.tertiary.withOpacity(isDark ? 0.3 : 0.2) : theme.colorScheme.surfaceVariant.withOpacity(0.3), borderRadius: BorderRadius.circular(20), border: isSelected ? Border.all(color: theme.colorScheme.tertiary) : Border.all(color: Colors.transparent), ), child: Text( label, style: GoogleFonts.outfit( fontSize: 13, color: isSelected ? theme.colorScheme.onSurface : theme.colorScheme.onSurfaceVariant, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, ), ), ), ), ); } String _formatDate(DateTime date) { final now = DateTime.now(); if (DateUtils.isSameDay(date, now)) { return 'Today, ${_getMonth(date.month)} ${date.day}'; } const days = [ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ]; return '${days[date.weekday - 1]}, ${_getMonth(date.month)} ${date.day}'; } String _getMonth(int month) { const months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]; return months[month - 1]; } String _getEnergyLabel(int? level) { if (level == null) return 'Not logged'; switch (level) { case 1: return 'Very Low'; case 2: return 'Low'; case 3: return 'Normal'; case 4: return 'Good'; case 5: return 'Excellent'; default: return 'Normal'; } } }