import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; import 'package:medora/data/models/consultation_center.dart'; import 'package:medora/data/models/doctor.dart'; import 'package:medora/data/models/patient.dart'; import 'package:medora/data/services/consultation_booking_service.dart'; import 'package:medora/data/services/patient_registration_service.dart'; import 'package:medora/route/route_names.dart'; import 'package:medora/widgets/alert_screen.dart'; class ConsultationBookingScreen extends StatefulWidget { final Doctor doctor; final ConsultationCenter selectedConsultation; final DateTime selectedDate; final String selectedTime; const ConsultationBookingScreen({ super.key, required this.doctor, required this.selectedConsultation, required this.selectedDate, required this.selectedTime, }); @override State createState() => _ConsultationBookingScreenState(); } class _ConsultationBookingScreenState extends State { PatientModel? selectedPatient; List familyMembers = []; FamilyMember? selectedFamilyMember; bool isLoading = true; final TextEditingController _nameController = TextEditingController(); final TextEditingController _relationController = TextEditingController(); DateTime? _selectedDateOfBirth; String _selectedGender = 'Male'; @override void dispose() { _nameController.dispose(); _relationController.dispose(); super.dispose(); } @override void initState() { super.initState(); _loadPatientProfile(); } Future _loadPatientProfile() async { setState(() => isLoading = true); try { final currentPatient = await PatientProfileService.getPatientProfile(); if (currentPatient != null) { setState(() { selectedPatient = currentPatient; }); } } catch (e) { print('Error loading patient data: $e'); } finally { setState(() => isLoading = false); } } String get formattedAddress { final parts = [ widget.selectedConsultation.floorBuilding, widget.selectedConsultation.street, widget.selectedConsultation.city, widget.selectedConsultation.state, widget.selectedConsultation.postalCode ].where((part) => part != null && part.isNotEmpty).toList(); return parts.join(', '); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF5F7FF), appBar: _buildAppBar(context), body: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildAppointmentCard(), const SizedBox(height: 24), _buildDoctorDetails(), const SizedBox(height: 24), _buildLocationDetails(), const SizedBox(height: 24), _buildPaymentDetails(), const SizedBox(height: 24), _buildInClinicAppointmentText(), const SizedBox(height: 24), _buildConfirmButton(context), ], ), ), ), ); } Widget _buildInClinicAppointmentText() { String patientName = selectedFamilyMember?.name ?? selectedPatient?.name ?? 'Select Patient'; String relation = selectedFamilyMember?.relation != null ? ' (${selectedFamilyMember!.relation})' : ''; return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.1), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: RichText( text: TextSpan( style: GoogleFonts.poppins( fontSize: 16, color: Colors.black87, ), children: [ const TextSpan(text: 'In-clinic appointment for '), TextSpan( text: '$patientName$relation', style: const TextStyle( fontWeight: FontWeight.w600, ), ), ], ), ), ), TextButton( onPressed: _showPatientSelectionDialog, child: Text( 'Change', style: GoogleFonts.poppins( color: Colors.blue, fontWeight: FontWeight.w500, ), ), ), ], ), ); } PreferredSizeWidget _buildAppBar(BuildContext context) { return AppBar( backgroundColor: Colors.white, elevation: 0, leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.black87), onPressed: () => Navigator.pop(context), ), title: Text( 'Booking Overview', style: GoogleFonts.poppins( color: Colors.black87, fontWeight: FontWeight.w600, fontSize: 20, ), ), centerTitle: true, ); } Widget _buildAppointmentCard() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.blue.withOpacity(0.3), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( children: [ Row( children: [ const Icon(Icons.calendar_today, color: Colors.white), const SizedBox(width: 12), Text( DateFormat('EEEE, MMMM d').format(widget.selectedDate), style: GoogleFonts.poppins( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500, ), ), ], ), const SizedBox(height: 12), Row( children: [ const Icon(Icons.access_time, color: Colors.white), const SizedBox(width: 12), Text( widget.selectedTime, style: GoogleFonts.poppins( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500, ), ), ], ), ], ), ); } Widget _buildDoctorDetails() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.1), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Row( children: [ ClipRRect( borderRadius: BorderRadius.circular(12), child: Image.network( widget.doctor.profileImage!, width: 80, height: 80, fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) { return Container( width: 80, height: 80, color: Colors.grey[300], child: Icon(Icons.person, size: 40, color: Colors.grey[600]), ); }, ), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( widget.doctor.firstName ?? '', style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.w600, ), ), Text( widget.doctor.speciality!, style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey[600], ), ), Text( '${widget.doctor.yearsOfExperience} years experience', style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey[600], ), ), ], ), ), ], ), ); } Widget _buildLocationDetails() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.1), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Location', style: GoogleFonts.poppins( fontSize: 16, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 8), Text( formattedAddress, style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey[600], ), ), const SizedBox(height: 8), Text( 'Average consultation time: ${widget.selectedConsultation.averageDurationMinutes} minutes', style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey[600], ), ), ], ), ); } Widget _buildPaymentDetails() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.1), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Payment Details', style: GoogleFonts.poppins( fontSize: 16, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Consultation Fee', style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey[600], ), ), Text( '₹${widget.selectedConsultation.consultationFee ?? "500"}', style: GoogleFonts.poppins( fontSize: 14, fontWeight: FontWeight.w500, ), ), ], ), ], ), ); } Widget _buildConfirmButton(BuildContext context) { return SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () { // Handle payment and booking confirmation _showConfirmationDialog(context); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: Text( 'Confirm & Pay', style: GoogleFonts.poppins( fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white, ), ), ), ); } void _showConfirmationDialog(BuildContext context) async { if (selectedPatient == null) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Please select a patient for the appointment'), backgroundColor: Colors.red, ), ); return; } final bookingService = BookingService(); final currentUser = FirebaseAuth.instance.currentUser; // Get the correct patient name based on selection final patientName = selectedFamilyMember != null ? selectedFamilyMember!.name : selectedPatient!.name; try { if (context.mounted) { showDialog( context: context, barrierDismissible: false, builder: (context) => const Center( child: CircularProgressIndicator(), ), ); } final bookingId = await bookingService.createBooking( doctorName: widget.doctor.firstName ?? 'Doctor', patientId: currentUser!.uid, patientName: patientName ?? 'Patient', location: formattedAddress, appointmentDate: widget.selectedDate, appointmentTime: widget.selectedTime, consultationFee: int.parse(widget.selectedConsultation.consultationFee ?? "500"), specialization: widget.doctor.speciality!, ); if (context.mounted) { Navigator.pop(context); Navigator.push( context, MaterialPageRoute( builder: (context) => AlertScreen( arguments: AlertArguments( title: 'Booking Confirmed', message: 'Your in-clinic appointment has been successfully booked for $patientName. Booking ID: ${bookingId.substring(0, 8)}\n\nPlease complete the payment to confirm your appointment.', actionTitle: 'View Appointments', type: AlertType.success, onActionPressed: () { Navigator.pushReplacementNamed( context, RouteNames.patientDashboardScreen); }, ), ), ), ); } } catch (e) { if (context.mounted) { Navigator.pop(context); Navigator.push( context, MaterialPageRoute( builder: (context) => AlertScreen( arguments: AlertArguments( title: 'Booking Failed', message: 'Unable to create booking. ${e.toString()}', actionTitle: 'Try Again', type: AlertType.error, onActionPressed: () { Navigator.of(context).pop(); }, ), ), ), ); } } } Future _showAddFamilyMemberDialog() async { _nameController.clear(); _relationController.clear(); setState(() { _selectedDateOfBirth = null; _selectedGender = 'Male'; }); return showDialog( context: context, barrierDismissible: false, builder: (BuildContext dialogContext) => StatefulBuilder( builder: (BuildContext context, StateSetter setDialogState) { return AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), title: Text( 'Add Family Member', style: GoogleFonts.poppins(fontWeight: FontWeight.w600), ), content: AnimatedContainer( duration: const Duration(milliseconds: 300), child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ TextFormField( controller: _nameController, decoration: InputDecoration( labelText: 'Full Name', labelStyle: GoogleFonts.poppins(), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), ), prefixIcon: const Icon( Icons.person_outline, color: Colors.blue, ), ), ), const SizedBox(height: 16), TextFormField( controller: _relationController, decoration: InputDecoration( labelText: 'Relation', labelStyle: GoogleFonts.poppins(), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), ), prefixIcon: const Icon( Icons.family_restroom, color: Colors.blue, ), ), ), const SizedBox(height: 16), InkWell( onTap: () async { final DateTime? picked = await showDatePicker( context: context, initialDate: DateTime.now(), firstDate: DateTime(1900), lastDate: DateTime.now(), builder: (context, child) { return Theme( data: Theme.of(context).copyWith( colorScheme: ColorScheme.light( primary: Colors.blue, onPrimary: Colors.white, surface: Colors.grey[100]!, ), ), child: child!, ); }, ); if (picked != null) { setDialogState(() { _selectedDateOfBirth = picked; }); } }, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( border: Border.all(color: Colors.grey[300]!), borderRadius: BorderRadius.circular(12), ), child: Row( children: [ const Icon(Icons.calendar_today, color: Colors.blue), const SizedBox(width: 12), Text( _selectedDateOfBirth != null ? DateFormat('dd/MM/yyyy') .format(_selectedDateOfBirth!) : 'Select Date of Birth', style: GoogleFonts.poppins(), ), ], ), ), ), const SizedBox(height: 16), Container( padding: const EdgeInsets.symmetric(horizontal: 12), decoration: BoxDecoration( border: Border.all(color: Colors.grey[300]!), borderRadius: BorderRadius.circular(12), ), child: DropdownButtonHideUnderline( child: DropdownButtonFormField( value: _selectedGender, decoration: InputDecoration( prefixIcon: const Icon(Icons.person_outline, color: Colors.blue), border: InputBorder.none, labelStyle: GoogleFonts.poppins(), ), items: ['Male', 'Female', 'Other'] .map((gender) => DropdownMenuItem( value: gender, child: Text(gender, style: GoogleFonts.poppins()), )) .toList(), onChanged: (value) { if (value != null) { setDialogState(() => _selectedGender = value); } }, ), ), ), ], ), ), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text( 'Cancel', style: GoogleFonts.poppins(color: Colors.grey), ), ), ElevatedButton( onPressed: () => _addFamilyMember(context), style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: Text( 'Add Member', style: GoogleFonts.poppins(color: Colors.white), ), ), ], ); }, ), ); } Future _addFamilyMember(BuildContext context) async { if (_nameController.text.isEmpty || _relationController.text.isEmpty || _selectedDateOfBirth == null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Please fill in all fields', style: GoogleFonts.poppins(), ), backgroundColor: Colors.red, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), ); return; } try { final newFamilyMember = FamilyMember( name: _nameController.text, relation: _relationController.text, gender: _selectedGender, dateOfBirth: _selectedDateOfBirth, ); if (selectedPatient != null) { selectedPatient!.familyMembers.add(newFamilyMember); await PatientProfileService.updatePatientProfile(selectedPatient!); setState(() { selectedFamilyMember = newFamilyMember; }); } if (context.mounted) { Navigator.pop(context); _showPatientSelectionDialog(); } } catch (e) { if (context.mounted) { Navigator.pop(context); // Pop add family member dialog } } } void _showPatientSelectionDialog() { showDialog( context: context, builder: (context) => AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), title: Text( 'Select Patient', style: GoogleFonts.poppins(fontWeight: FontWeight.w600), ), content: SizedBox( width: double.maxFinite, child: ListView( shrinkWrap: true, children: [ // Main patient _buildPatientTile( name: selectedPatient?.name ?? '', subtitle: 'Primary Patient', isSelected: selectedFamilyMember == null, onTap: () { setState(() { selectedFamilyMember = null; }); Navigator.pop(context); }, ), const Divider(), // Family members ...selectedPatient?.familyMembers.map( (member) => _buildPatientTile( name: member.name ?? '', subtitle: member.relation ?? '', isSelected: selectedFamilyMember == member, onTap: () { setState(() { selectedFamilyMember = member; }); Navigator.pop(context); }, ), ) ?? [], const Divider(), ListTile( leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.blue.withOpacity(0.1), shape: BoxShape.circle, ), child: const Icon(Icons.person_add, color: Colors.blue), ), title: Text( 'Add Family Member', style: GoogleFonts.poppins( color: Colors.blue, fontWeight: FontWeight.w500, ), ), onTap: () { Navigator.pop(context); _showAddFamilyMemberDialog(); }, ), ], ), ), ), ); } Widget _buildPatientTile({ required String name, required String subtitle, required bool isSelected, required VoidCallback onTap, }) { return ListTile( leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: isSelected ? Colors.blue.withOpacity(0.1) : Colors.grey.withOpacity(0.1), shape: BoxShape.circle, ), child: Icon( Icons.person, color: isSelected ? Colors.blue : Colors.grey, ), ), title: Text( name, style: GoogleFonts.poppins( fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, color: isSelected ? Colors.blue : Colors.black87, ), ), subtitle: Text( subtitle, style: GoogleFonts.poppins( color: Colors.grey[600], ), ), trailing: isSelected ? const Icon(Icons.check_circle, color: Colors.blue) : null, onTap: onTap, ); } }