import 'package:intl/intl.dart'; import 'package:mobx/mobx.dart'; import '../../data/models/patient_model.dart'; import '../../data/services/patient_service.dart'; part 'patient_store.g.dart'; // ignore: library_private_types_in_public_api class PatientStore = _PatientStoreBase with _$PatientStore; abstract class _PatientStoreBase with Store { final PatientService service; _PatientStoreBase({PatientService? patientService}) : service = patientService ?? PatientService(); @observable int? id; @observable bool isLoading = false; @observable bool isSaving = false; @observable String? errorMessage; @observable String? successMessage; // Campos Demográficos Superiores @observable String fecReg = ''; @observable String cedula = ''; @observable String nombre = ''; @observable String apellido = ''; @observable String direccion = ''; @observable String telefono = ''; @observable String ocupacion = ''; @observable String edad = ''; @observable String sexo = 'Masculino'; @observable String seguro = 'Sí'; @observable String estCivil = 'Soltero'; // Pestañas Clínicas @observable String motCons = ''; @observable String fecUltcon = ''; @observable String hisEnfAct = ''; // Antecedentes Personales Patológicos @observable String datNi = 'Ninguna'; @observable String datAdo = 'Ninguna'; @observable String datAdu = 'Ninguna'; @observable String datAlerg = 'Ninguna'; @observable String datTran = 'ninguna'; @observable String datCir = 'ninguna'; @observable String datAc = 'ninguno'; @observable String datOtrosp = 'ninguno'; // Antecedentes No Patológicos @observable String datMad = 'Viva y sana'; @observable String datEsp = 'Viva y sana'; @observable String datPadre = 'Vivo y sano'; @observable String datHijos = 'Vivos y sanos'; @observable String datHer = 'Vivos y sanos'; @observable String datOtrosnp = 'Ningunos'; // Diagnósticos @observable String metDiagnRad = ''; @observable String diagnDesc = ''; @observable String diagnDef = ''; // Laboratorios y Tratamiento @observable String datLab = ''; @observable String tratamiento = ''; // Próxima Cita @observable String fecProxcita = ''; // Estado de Sala de Espera @observable String estadoEspera = 'no_presente'; @computed bool get isEditing => id != null; @computed bool get isValid => nombre.trim().isNotEmpty && apellido.trim().isNotEmpty && sexo.trim().isNotEmpty && seguro.trim().isNotEmpty; @computed int? get diasParaProximaCita { if (fecProxcita.isEmpty) return null; try { DateTime? target; if (fecProxcita.contains('-')) { target = DateTime.tryParse(fecProxcita); } else if (fecProxcita.contains('/')) { final parts = fecProxcita.split('/'); if (parts.length == 3) { final day = int.parse(parts[0]); final month = int.parse(parts[1]); final year = int.parse(parts[2]); target = DateTime(year, month, day); } } if (target == null) return null; final now = DateTime.now(); final today = DateTime(now.year, now.month, now.day); final cleanTarget = DateTime(target.year, target.month, target.day); return cleanTarget.difference(today).inDays; } catch (_) { return null; } } @action void initForCreate() { id = null; errorMessage = null; successMessage = null; isLoading = false; isSaving = false; final now = DateTime.now(); fecReg = DateFormat('dd/MM/yyyy').format(now); fecUltcon = DateFormat('dd/MM/yyyy').format(now); cedula = ''; nombre = ''; apellido = ''; direccion = ''; telefono = ''; ocupacion = ''; edad = ''; sexo = 'Masculino'; seguro = 'Sí'; estCivil = 'Soltero'; motCons = ''; hisEnfAct = ''; datNi = 'Ninguna'; datAdo = 'Ninguna'; datAdu = 'Ninguna'; datAlerg = 'Ninguna'; datTran = 'ninguna'; datCir = 'ninguna'; datAc = 'ninguno'; datOtrosp = 'ninguno'; datMad = 'Viva y sana'; datEsp = 'Viva y sana'; datPadre = 'Vivo y sano'; datHijos = 'Vivos y sanos'; datHer = 'Vivos y sanos'; datOtrosnp = 'Ningunos'; metDiagnRad = ''; diagnDesc = ''; diagnDef = ''; datLab = ''; tratamiento = ''; fecProxcita = ''; estadoEspera = 'no_presente'; } @action void populateFromModel(PatientModel p) { id = p.id; fecReg = p.fecReg; fecUltcon = p.fecUltcon; cedula = p.cedula; nombre = p.nombre; apellido = p.apellido; direccion = p.direccion; telefono = p.telefono; ocupacion = p.ocupacion; edad = p.edad; sexo = p.sexo.isNotEmpty ? p.sexo : 'Masculino'; seguro = p.seguro.isNotEmpty ? p.seguro : 'Sí'; estCivil = p.estCivil.isNotEmpty ? p.estCivil : 'Soltero'; motCons = p.motCons; hisEnfAct = p.hisEnfAct; datNi = p.datNi.isNotEmpty ? p.datNi : 'Ninguna'; datAdo = p.datAdo.isNotEmpty ? p.datAdo : 'Ninguna'; datAdu = p.datAdu.isNotEmpty ? p.datAdu : 'Ninguna'; datAlerg = p.datAlerg.isNotEmpty ? p.datAlerg : 'Ninguna'; datTran = p.datTran.isNotEmpty ? p.datTran : 'ninguna'; datCir = p.datCir.isNotEmpty ? p.datCir : 'ninguna'; datAc = p.datAc.isNotEmpty ? p.datAc : 'ninguno'; datOtrosp = p.datOtrosp.isNotEmpty ? p.datOtrosp : 'ninguno'; datMad = p.datMad.isNotEmpty ? p.datMad : 'Viva y sana'; datEsp = p.datEsp.isNotEmpty ? p.datEsp : 'Viva y sana'; datPadre = p.datPadre.isNotEmpty ? p.datPadre : 'Vivo y sano'; datHijos = p.datHijos.isNotEmpty ? p.datHijos : 'Vivos y sanos'; datHer = p.datHer.isNotEmpty ? p.datHer : 'Vivos y sanos'; datOtrosnp = p.datOtrosnp.isNotEmpty ? p.datOtrosnp : 'Ningunos'; metDiagnRad = p.metDiagnRad; diagnDesc = p.diagnDesc; diagnDef = p.diagnDef; datLab = p.datLab; tratamiento = p.tratamiento; fecProxcita = p.fecProxcita; estadoEspera = p.estadoEspera.isNotEmpty ? p.estadoEspera : 'no_presente'; } @action Future loadPatient(int patientId) async { isLoading = true; errorMessage = null; try { final p = await service.getPatientById(patientId); runInAction(() { populateFromModel(p); isLoading = false; }); } catch (e) { runInAction(() { errorMessage = e.toString().replaceAll('Exception: ', ''); isLoading = false; }); } } @action void appendCurrentDateToConsultas() { final dateStr = DateFormat('dd/MM/yyyy').format(DateTime.now()); if (motCons.isEmpty) { motCons = '$dateStr: '; } else { motCons = '$motCons\n$dateStr: '; } } @action void appendCurrentDateToHistorial() { final dateStr = DateFormat('dd/MM/yyyy').format(DateTime.now()); if (hisEnfAct.isEmpty) { hisEnfAct = '$dateStr: '; } else { hisEnfAct = '$hisEnfAct\n$dateStr: '; } } PatientModel toModel() { return PatientModel( id: id, nombre: nombre.trim(), apellido: apellido.trim(), telefono: telefono.trim(), direccion: direccion.trim(), cedula: cedula.trim(), ocupacion: ocupacion.trim(), edad: edad.trim(), fecUltcon: fecUltcon.trim(), fecReg: fecReg.trim(), sexo: sexo.trim(), seguro: seguro.trim(), estCivil: estCivil.trim(), motCons: motCons, hisEnfAct: hisEnfAct, datPadre: datPadre, datEsp: datEsp, datHijos: datHijos, datOtrosnp: datOtrosnp, datAlerg: datAlerg, datTran: datTran, datOtrosp: datOtrosp, metDiagnRad: metDiagnRad, datLab: datLab, diagnDesc: diagnDesc, diagnDef: diagnDef, fecProxcita: fecProxcita.trim(), tratamiento: tratamiento, datHer: datHer, datMad: datMad, datNi: datNi, datAdo: datAdo, datAdu: datAdu, datAc: datAc, datCir: datCir, estadoEspera: estadoEspera, ); } @action Future savePatient() async { if (!isValid) { errorMessage = 'Faltan campos obligatorios: Nombre, Apellido, Sexo y Seguro.'; return false; } // Si el paciente estaba en consulta o en espera y el médico guarda los cambios de la consulta médica, // la atención concluye formalmente y su estado de sala de espera pasa a 'atendido'. if (estadoEspera == 'en_consulta' || estadoEspera == 'en_espera') { estadoEspera = 'atendido'; } isSaving = true; errorMessage = null; successMessage = null; try { final model = toModel(); if (isEditing) { await service.updatePatient(id!, model.toJson(includeId: false)); runInAction(() { successMessage = 'Paciente ${model.fullName} actualizado correctamente'; isSaving = false; }); } else { final created = await service.createPatient(model); runInAction(() { id = created.id; successMessage = 'Paciente ${model.fullName} guardado correctamente'; isSaving = false; }); } return true; } catch (e) { runInAction(() { errorMessage = e.toString().replaceAll('Exception: ', ''); isSaving = false; }); return false; } } }