import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import '../../../../core/theme/app_colors.dart'; import '../../../../core/widgets/medical_modal.dart'; import '../../../insurance_auth/presentation/views/insurance_auth_modal_view.dart'; import '../../../prescription/presentation/views/prescription_modal_view.dart'; import '../../../referrals/presentation/views/department_referral_modal_view.dart'; import '../../../referrals/presentation/views/doctor_referral_modal_view.dart'; import '../../data/models/patient_model.dart'; import '../store/patient_store.dart'; import '../widgets/clinical_documents_dropdown.dart'; import '../widgets/patient_clinical_tabs.dart'; import '../widgets/patient_demographics_form.dart'; import '../widgets/secretary_appointment_section.dart'; class PatientModalView extends StatefulWidget { final PatientModel? initialPatient; final int? patientId; final ValueChanged? onSaved; final ValueChanged? onDeleted; final bool isSecretary; final PatientStore? store; const PatientModalView({ super.key, this.initialPatient, this.patientId, this.onSaved, this.onDeleted, this.isSecretary = false, this.store, }); @override State createState() => _PatientModalViewState(); } class _PatientModalViewState extends State { late final PatientStore _store; final _formKey = GlobalKey(); @override void initState() { super.initState(); _store = widget.store ?? PatientStore(); if (widget.initialPatient != null) { _store.populateFromModel(widget.initialPatient!); } else if (widget.patientId != null) { _store.loadPatient(widget.patientId!); } else if (widget.store == null) { _store.initForCreate(); } } Future _handleSave() async { if (_formKey.currentState?.saveAndValidate() ?? false) { final values = _formKey.currentState!.value; if (values['nombre'] != null) _store.nombre = values['nombre'].toString(); if (values['apellido'] != null) _store.apellido = values['apellido'].toString(); if (values['cedula'] != null) _store.cedula = values['cedula'].toString(); if (values['telefono'] != null) _store.telefono = values['telefono'].toString(); if (values['direccion'] != null) _store.direccion = values['direccion'].toString(); if (values['ocupacion'] != null) _store.ocupacion = values['ocupacion'].toString(); if (values['edad'] != null) _store.edad = values['edad'].toString(); if (values['sexo'] != null) _store.sexo = values['sexo'].toString(); if (values['seguro'] != null) _store.seguro = values['seguro'].toString(); if (values['est_civil'] != null) _store.estCivil = values['est_civil'].toString(); final success = await _store.savePatient(); if (success && mounted) { if (widget.onSaved != null) { widget.onSaved!(_store.toModel()); } ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(_store.successMessage ?? 'Operación completada exitosamente'), backgroundColor: const Color(0xFF00A65A), behavior: SnackBarBehavior.floating, ), ); Navigator.of(context).pop(_store.toModel()); } } else { _store.errorMessage = 'Por favor complete los campos obligatorios resaltados en rojo.'; } } Future _confirmDeletePatient() async { final patientId = _store.id; if (patientId == null) return; final patientName = '${_store.nombre} ${_store.apellido}'.trim(); final cedula = _store.cedula.trim().isNotEmpty ? _store.cedula.trim() : 'No registrada'; final confirmed = await showDialog( context: context, barrierDismissible: false, builder: (dialogCtx) => StatefulBuilder( builder: (builderCtx, setDialogState) { return AlertDialog( backgroundColor: Colors.white, surfaceTintColor: Colors.transparent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), side: const BorderSide(color: AppColors.border), ), titlePadding: const EdgeInsets.fromLTRB(20, 20, 20, 10), contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), actionsPadding: const EdgeInsets.fromLTRB(20, 10, 20, 16), title: Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: AppColors.error.withValues(alpha: 0.12), shape: BoxShape.circle, ), child: const Icon(Icons.delete_forever_rounded, color: AppColors.error, size: 22), ), const SizedBox(width: 12), const Expanded( child: Text( '¿Eliminar Ficha del Paciente?', style: TextStyle(fontSize: 17, fontWeight: FontWeight.w700, color: AppColors.textPrimary), ), ), ], ), content: SizedBox( width: 440, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: double.infinity, padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: AppColors.primaryContainer.withValues(alpha: 0.45), borderRadius: BorderRadius.circular(10), border: Border.all(color: AppColors.primary.withValues(alpha: 0.2)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( patientName.isNotEmpty ? patientName : 'Paciente sin nombre', style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w700, color: AppColors.primaryDark), ), const SizedBox(height: 4), Row( children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: AppColors.primary.withValues(alpha: 0.12), borderRadius: BorderRadius.circular(4), ), child: Text( 'ID: #$patientId', style: const TextStyle(fontSize: 11.5, fontWeight: FontWeight.w600, color: AppColors.primary), ), ), const SizedBox(width: 10), Text('Cédula: $cedula', style: const TextStyle(fontSize: 12, color: AppColors.textSecondary)), ], ), ], ), ), const SizedBox(height: 12), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: const Color(0xFFFEF2F2), borderRadius: BorderRadius.circular(10), border: Border.all(color: AppColors.error.withValues(alpha: 0.25)), ), child: const Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(Icons.warning_amber_rounded, color: AppColors.error, size: 20), SizedBox(width: 10), Expanded( child: Text( 'Esta acción es permanente e irreversible. Se eliminará el expediente completo, antecedentes médicos, consultas, recetas y citas asociadas.', style: TextStyle( fontSize: 12.5, color: Color(0xFF991B1B), height: 1.35, fontWeight: FontWeight.w500, ), ), ), ], ), ), ], ), ), actions: [ TextButton( onPressed: _store.isDeleting ? null : () => Navigator.of(dialogCtx).pop(false), child: const Text('Cancelar', style: TextStyle(color: AppColors.textSecondary, fontWeight: FontWeight.w600)), ), ElevatedButton.icon( onPressed: _store.isDeleting ? null : () async { setDialogState(() {}); final success = await _store.deletePatient(); if (dialogCtx.mounted) { Navigator.of(dialogCtx).pop(success); } }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.error, foregroundColor: Colors.white, elevation: 0, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), ), icon: _store.isDeleting ? const SizedBox( width: 14, height: 14, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white), ) : const Icon(Icons.delete_outline_rounded, size: 16), label: Text( _store.isDeleting ? 'Eliminando...' : 'Eliminar Paciente', style: const TextStyle(fontWeight: FontWeight.w700), ), ), ], ); }, ), ); if (!mounted) return; if (confirmed == true) { if (widget.onDeleted != null) { widget.onDeleted!(patientId); } ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Ficha del paciente $patientName eliminada exitosamente.'), backgroundColor: const Color(0xFF00A65A), behavior: SnackBarBehavior.floating, ), ); if (Navigator.canPop(context)) { Navigator.of(context).pop(); } } } @override Widget build(BuildContext context) { return Observer( builder: (_) { final title = widget.isSecretary ? (_store.isEditing ? 'Ficha de Recepción' : 'Nuevo Registro de Paciente') : (_store.isEditing ? 'Editar Paciente' : 'Registro De Paciente'); final subtitle = widget.isSecretary ? 'Recepción, datos personales y programación de citas' : (_store.isEditing ? 'Actualizando ficha clínica del paciente ID: ${_store.id ?? ''}' : 'Ingrese los datos generales y antecedentes del paciente'); final mediaQuery = MediaQuery.sizeOf(context); final modalHeight = (mediaQuery.height * 0.92).clamp(740.0, 900.0); final modalWidth = (mediaQuery.width * 0.92).clamp(980.0, 1160.0); return MedicalModalDialog( maxWidth: modalWidth, maxHeight: modalHeight, title: title, titleIcon: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: AppColors.primaryContainer, borderRadius: BorderRadius.circular(10), ), child: Icon( _store.isEditing ? Icons.edit_note_rounded : Icons.person_add_alt_1_rounded, color: AppColors.primary, size: 20, ), ), subtitle: Text( subtitle, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 12, color: AppColors.textMuted), ), actions: [ if (_store.estadoEspera == 'en_consulta') ...[ Container( height: 34, padding: const EdgeInsets.symmetric(horizontal: 10), decoration: BoxDecoration( color: const Color(0xFFE0F2FE), borderRadius: BorderRadius.circular(8), border: Border.all(color: const Color(0xFF7DD3FC)), ), alignment: Alignment.center, child: const Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.medical_services_rounded, size: 13, color: Color(0xFF0369A1)), SizedBox(width: 5), Text( 'En Consulta', style: TextStyle(fontSize: 11.5, fontWeight: FontWeight.w700, color: Color(0xFF0369A1)), ), ], ), ), const SizedBox(width: 8), ] else if (_store.estadoEspera == 'en_espera') ...[ Container( height: 34, padding: const EdgeInsets.symmetric(horizontal: 10), decoration: BoxDecoration( color: const Color(0xFFDCFCE7), borderRadius: BorderRadius.circular(8), border: Border.all(color: const Color(0xFF86EFAC)), ), alignment: Alignment.center, child: const Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.hourglass_top_rounded, size: 13, color: Color(0xFF15803D)), SizedBox(width: 5), Text( 'En Espera', style: TextStyle(fontSize: 11.5, fontWeight: FontWeight.w700, color: Color(0xFF15803D)), ), ], ), ), const SizedBox(width: 8), ] else if (_store.estadoEspera == 'atendido') ...[ Container( height: 34, padding: const EdgeInsets.symmetric(horizontal: 10), decoration: BoxDecoration( color: const Color(0xFFF1F5F9), borderRadius: BorderRadius.circular(8), border: Border.all(color: const Color(0xFFCBD5E1)), ), alignment: Alignment.center, child: const Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.check_circle_rounded, size: 13, color: Color(0xFF64748B)), SizedBox(width: 5), Text( 'Atendido', style: TextStyle(fontSize: 11.5, fontWeight: FontWeight.w600, color: Color(0xFF64748B)), ), ], ), ), const SizedBox(width: 8), ], if (!widget.isSecretary) ...[ if (_store.isEditing) ...[ OutlinedButton.icon( onPressed: _store.isDeleting || _store.isSaving ? null : () => _confirmDeletePatient(), icon: const Icon(Icons.delete_outline_rounded, size: 16, color: AppColors.error), label: const Text( 'Eliminar', style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: AppColors.error, ), ), style: OutlinedButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 11, vertical: 0), minimumSize: const Size(0, 34), side: BorderSide(color: AppColors.error.withValues(alpha: 0.35)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), backgroundColor: AppColors.error.withValues(alpha: 0.04), ), ), const SizedBox(width: 8), ], ClinicalDocumentsDropdown( onSelect: (docType) { if (docType == ClinicalDocumentType.recetaMedica) { final patientName = '${_store.nombre} ${_store.apellido}'.trim(); showMedicalModal( context: context, builder: (modalCtx) => PrescriptionModalView( patientName: patientName.isNotEmpty ? patientName : 'Sin Nombre', ), ); } else if (docType == ClinicalDocumentType.autorizacionSeguro) { final patientName = '${_store.nombre} ${_store.apellido}'.trim(); final diagnosis = _store.diagnDesc.trim().isNotEmpty ? _store.diagnDesc.trim() : (_store.diagnDef.trim().isNotEmpty ? _store.diagnDef.trim() : null); showMedicalModal( context: context, builder: (modalCtx) => InsuranceAuthModalView( patientName: patientName.isNotEmpty ? patientName : 'Sin Nombre', initialDiagnosis: diagnosis, ), ); } else if (docType == ClinicalDocumentType.referirDoctor) { final patientName = '${_store.nombre} ${_store.apellido}'.trim(); showMedicalModal( context: context, builder: (modalCtx) => DoctorReferralModalView( patientName: patientName.isNotEmpty ? patientName : 'Sin Nombre', ), ); } else if (docType == ClinicalDocumentType.referirDepartamento) { final patientName = '${_store.nombre} ${_store.apellido}'.trim(); showMedicalModal( context: context, builder: (modalCtx) => DepartmentReferralModalView( patientName: patientName.isNotEmpty ? patientName : 'Sin Nombre', ), ); } }, ), ], ], bottomBar: Container( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), decoration: const BoxDecoration( color: Colors.white, border: Border(top: BorderSide(color: AppColors.border)), ), child: Row( children: [ Container( padding: const EdgeInsets.all(4), decoration: BoxDecoration( color: _store.errorMessage != null ? AppColors.error.withValues(alpha: 0.12) : (_store.successMessage != null ? const Color(0xFF00A65A).withValues(alpha: 0.12) : AppColors.primary.withValues(alpha: 0.1)), shape: BoxShape.circle, ), child: Icon( _store.errorMessage != null ? Icons.error_outline_rounded : (_store.successMessage != null ? Icons.check_circle_outline_rounded : Icons.info_outline_rounded), size: 15, color: _store.errorMessage != null ? AppColors.error : (_store.successMessage != null ? const Color(0xFF00A65A) : AppColors.primary), ), ), const SizedBox(width: 8), Expanded( child: Text( _store.errorMessage ?? (_store.successMessage ?? (_store.isSaving ? 'Guardando datos en el servidor...' : (_store.estadoEspera == 'en_consulta' ? 'Consulta médica activa · Al guardar pasará automáticamente a Atendido' : (_store.isEditing ? 'Realizando cambios en paciente' : 'Listo para registrar')))), style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: _store.errorMessage != null ? AppColors.error : (_store.successMessage != null ? const Color(0xFF00A65A) : AppColors.textSecondary), ), ), ), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(6), border: Border.all(color: const Color(0xFFE2E8F0)), ), child: const Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.keyboard_outlined, size: 12, color: AppColors.textMuted), SizedBox(width: 4), Text( 'ESC para salir', style: TextStyle(fontSize: 11, color: AppColors.textMuted, fontWeight: FontWeight.w500), ), ], ), ), ], ), ), child: _store.isLoading ? const Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ CircularProgressIndicator(strokeWidth: 3), SizedBox(height: 16), Text('Cargando ficha del paciente...', style: TextStyle(fontSize: 13)), ], ), ) : FormBuilder( key: _formKey, child: Column( children: [ PatientDemographicsForm( store: _store, formKey: _formKey, onSave: _handleSave, ), if (widget.isSecretary) Expanded( child: SingleChildScrollView( child: SecretaryAppointmentSection(store: _store), ), ) else Expanded( child: PatientClinicalTabs(store: _store), ), ], ), ), ); }, ); } }