import { MongoClient } from 'mongodb'; import bcrypt from 'bcryptjs'; const { compareSync, hashSync } = bcrypt; export function generateUUID() { if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') { return crypto.randomUUID(); } return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = (Math.random() * 16) | 0; const v = c === 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); } const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017'; const DB_NAME = process.env.DB_NAME || 'hospital'; let client; let db; export async function initDb() { try { client = new MongoClient(MONGODB_URI, { connectTimeoutMS: 10000, }); await client.connect(); db = client.db(DB_NAME); console.log(`Connected to MongoDB database: ${DB_NAME}`); // Create unique index for users and patients DNI await db.collection('usuarios').createIndex({ dni: 1 }, { unique: true }); await db.collection('pacientes').createIndex({ dni: 1 }, { unique: true }); await db.collection('areas').createIndex({ nombre: 1 }, { unique: true }); // Check if default admin exists const adminCount = await db.collection('usuarios').countDocuments(); if (adminCount === 0) { const adminDni = process.env.ADMIN_DNI || '12345678'; const adminPassword = process.env.ADMIN_PASSWORD || 'admin123'; const adminHash = hashSync(adminPassword, 10); const adminUser = { id: 'admin-default', apellido: 'Administrador', nombre: 'Sistema', dni: adminDni, fechaNacimiento: '1990-01-01', email: 'admin@hospital.local', rol: 'admin', passwordHash: adminHash, fechaCreacion: new Date().toISOString().split('T')[0] }; await db.collection('usuarios').insertOne(adminUser); console.log(`Default admin created: DNI ${adminDni} / Password ${adminPassword}`); } } catch (error) { console.error('Failed to initialize MongoDB:', error); throw error; } } // Helper to remove MongoDB's internal _id from returned objects to keep schema clean function cleanDoc(doc) { if (!doc) return null; const { _id, ...rest } = doc; return rest; } function cleanDocs(docs) { return docs.map(cleanDoc); } // ========== USUARIOS ========== export async function getUsuarioByDni(dni) { const user = await db.collection('usuarios').findOne({ dni }); return cleanDoc(user); } export async function getUsuarioById(id) { const user = await db.collection('usuarios').findOne({ id }); return cleanDoc(user); } export async function getAllUsuarios() { const users = await db.collection('usuarios').find().sort({ apellido: 1, nombre: 1 }).toArray(); return cleanDocs(users); } export async function createUsuario(usuario) { await db.collection('usuarios').insertOne(usuario); } export async function updateUsuario(id, datos) { const updateDoc = {}; for (const [key, val] of Object.entries(datos)) { if (val !== undefined) { updateDoc[key] = val; } } if (Object.keys(updateDoc).length > 0) { await db.collection('usuarios').updateOne({ id }, { $set: updateDoc }); } } export async function deleteUsuario(id) { await db.collection('usuarios').deleteOne({ id }); } export async function verifyPassword(dni, password) { const user = await db.collection('usuarios').findOne({ dni }); if (!user) return false; return compareSync(password, user.passwordHash); } export function hashPassword(password) { return hashSync(password, 10); } // ========== PACIENTES ========== export async function getAllPacientes() { const pacientes = await db.collection('pacientes').find().toArray(); return cleanDocs(pacientes); } export async function getPacienteById(id) { const paciente = await db.collection('pacientes').findOne({ id }); return cleanDoc(paciente); } export async function createPaciente(paciente) { await db.collection('pacientes').insertOne(paciente); } export async function updatePaciente(id, datos) { const updateDoc = {}; for (const [key, val] of Object.entries(datos)) { if (key !== 'id' && val !== undefined) { updateDoc[key] = val; } } if (Object.keys(updateDoc).length > 0) { await db.collection('pacientes').updateOne({ id }, { $set: updateDoc }); } } export async function deletePaciente(id) { await db.collection('pacientes').deleteOne({ id }); } // ========== AREAS ========== export async function getAllAreas() { const areas = await db.collection('areas').find().toArray(); return cleanDocs(areas); } export async function createArea(area) { await db.collection('areas').insertOne(area); } export async function updateArea(id, datos) { if (datos.nombre !== undefined) { await db.collection('areas').updateOne({ id }, { $set: { nombre: datos.nombre } }); } } export async function deleteArea(id) { await db.collection('areas').deleteOne({ id }); } // ========== CAMAS ========== export async function getAllCamas() { const camas = await db.collection('camas').find().toArray(); return cleanDocs(camas); } export async function getCamaById(id) { const cama = await db.collection('camas').findOne({ id }); return cleanDoc(cama); } export async function createCama(cama) { const id = cama.id || generateUUID(); const doc = { id, numero: cama.numero, areaId: cama.areaId, tipo: cama.tipo || 'Estándar', estado: cama.estado || 'Disponible', pacienteId: cama.pacienteId || null, internacionId: cama.internacionId || null }; await db.collection('camas').insertOne(doc); } export async function updateCama(id, updates) { const updateDoc = {}; for (const [key, val] of Object.entries(updates)) { if (val !== undefined) { updateDoc[key] = val; } } if (Object.keys(updateDoc).length > 0) { await db.collection('camas').updateOne({ id }, { $set: updateDoc }); } } export async function deleteCama(id) { await db.collection('camas').deleteOne({ id }); } // ========== INTERNACIONES ========== export async function getAllInternaciones() { const internaciones = await db.collection('internaciones').find().toArray(); return cleanDocs(internaciones).map(i => ({ ...i, activa: !!i.activa })); } export async function getInternacionById(id) { const internacion = await db.collection('internaciones').findOne({ id }); if (internacion) internacion.activa = !!internacion.activa; return cleanDoc(internacion); } export async function createInternacion(internacion) { const doc = { id: internacion.id, pacienteId: internacion.pacienteId, camaId: internacion.camaId || null, areaId: internacion.areaId || null, fechaIngresoHospital: internacion.fechaIngresoHospital || null, fechaIngresoClinica: internacion.fechaIngresoClinica || null, fechaEgreso: internacion.fechaEgreso || null, diagnosticoIngreso: internacion.diagnosticoIngreso || null, motivoConsulta: internacion.motivoConsulta || null, enfermedadActual: internacion.enfermedadActual || null, antecedentesEnfermedadActual: internacion.antecedentesEnfermedadActual || null, diagnosticoEgreso: internacion.diagnosticoEgreso || null, medicoIngresante: internacion.medicoIngresante || null, motivoEgreso: internacion.motivoEgreso || null, activa: internacion.activa ? 1 : 0, apache: internacion.apache || null, derivacion: internacion.derivacion || null }; await db.collection('internaciones').insertOne(doc); } export async function updateInternacion(id, datos) { const updateDoc = {}; for (const [key, val] of Object.entries(datos)) { if (val !== undefined) { if (key === 'activa') { updateDoc.activa = val ? 1 : 0; } else { updateDoc[key] = val; } } } if (Object.keys(updateDoc).length > 0) { await db.collection('internaciones').updateOne({ id }, { $set: updateDoc }); } } export async function deleteInternacion(id) { await db.collection('internaciones').deleteOne({ id }); } // ========== EVOLUCIONES ========== export async function getAllEvoluciones() { const evoluciones = await db.collection('evoluciones').find().toArray(); return cleanDocs(evoluciones); } export async function createEvolucion(evolucion) { const doc = { id: evolucion.id, internacionId: evolucion.internacionId, fecha: evolucion.fecha, hora: evolucion.hora || '', medico: evolucion.medico || '', signosVitales: JSON.stringify(evolucion.signosVitales || {}), examenFisico: JSON.stringify(evolucion.examenFisico || {}), novedades: evolucion.novedades || '', comentarios: evolucion.comentarios || evolucion.comentario || '', pendientes: evolucion.pendientes || '' }; await db.collection('evoluciones').insertOne(doc); } export async function updateEvolucion(id, datos) { const updateDoc = {}; for (const [key, val] of Object.entries(datos)) { if (val !== undefined) { if (key === 'comentario') { updateDoc.comentarios = val; } else if (key === 'signosVitales' || key === 'examenFisico') { updateDoc[key] = JSON.stringify(val); } else { updateDoc[key] = val; } } } if (Object.keys(updateDoc).length > 0) { await db.collection('evoluciones').updateOne({ id }, { $set: updateDoc }); } } export async function deleteEvolucion(id) { await db.collection('evoluciones').deleteOne({ id }); } // ========== LABORATORIOS ========== export async function getAllLaboratorios() { const laboratorios = await db.collection('laboratorios').find().toArray(); return cleanDocs(laboratorios); } export async function createLaboratorio(laboratorio) { const doc = { id: laboratorio.id, pacienteId: laboratorio.pacienteId, internacionId: laboratorio.internacionId || null, fecha: laboratorio.fecha, hora: laboratorio.hora || null, tipo: laboratorio.tipo, resultados: JSON.stringify(laboratorio.resultados || {}), observaciones: laboratorio.observaciones || null, medicoSolicitante: laboratorio.medicoSolicitante || null }; await db.collection('laboratorios').insertOne(doc); } export async function updateLaboratorio(id, datos) { const updateDoc = {}; for (const [key, val] of Object.entries(datos)) { if (val !== undefined) { if (key === 'resultados') { updateDoc.resultados = JSON.stringify(val); } else { updateDoc[key] = val; } } } if (Object.keys(updateDoc).length > 0) { await db.collection('laboratorios').updateOne({ id }, { $set: updateDoc }); } } export async function deleteLaboratorio(id) { await db.collection('laboratorios').deleteOne({ id }); } // ========== ACIDOS BASE ========== export async function getAllAcidosBase() { const acidos = await db.collection('acidosbase').find().toArray(); return cleanDocs(acidos); } export async function createAcidoBase(acido) { const doc = { id: acido.id, pacienteId: acido.pacienteId, internacionId: acido.internacionId || null, fecha: acido.fecha, hora: acido.hora || null, ph: acido.ph !== undefined ? Number(acido.ph) : null, pco2: acido.pco2 !== undefined ? Number(acido.pco2) : null, po2: acido.po2 !== undefined ? Number(acido.po2) : null, hco3: acido.hco3 !== undefined ? Number(acido.hco3) : null, be: acido.be !== undefined ? Number(acido.be) : null, sato2: acido.sato2 !== undefined ? Number(acido.sato2) : null, lactato: acido.lactato !== undefined ? Number(acido.lactato) : null, interpretacion: acido.interpretacion || null, fio2: acido.fio2 !== undefined ? Number(acido.fio2) : null }; await db.collection('acidosbase').insertOne(doc); } export async function deleteAcidoBase(id) { await db.collection('acidosbase').deleteOne({ id }); } // ========== CULTIVOS ========== export async function getAllCultivos() { const cultivos = await db.collection('cultivos').find().toArray(); return cleanDocs(cultivos); } export async function createCultivo(cultivo) { const doc = { id: cultivo.id, pacienteId: cultivo.pacienteId, internacionId: cultivo.internacionId, fechaToma: cultivo.fechaToma || null, protocolo: cultivo.protocolo || null, fechaResultado: cultivo.fechaResultado || null, tipoMuestra: cultivo.tipoMuestra || null, germen: cultivo.germen || null, sensible: cultivo.sensible || null, resistente: cultivo.resistente || null, estado: cultivo.estado || 'NAF/Pendiente', observaciones: cultivo.observaciones || null }; await db.collection('cultivos').insertOne(doc); } export async function updateCultivo(id, datos) { const updateDoc = {}; for (const [key, val] of Object.entries(datos)) { if (val !== undefined) { updateDoc[key] = val; } } if (Object.keys(updateDoc).length > 0) { await db.collection('cultivos').updateOne({ id }, { $set: updateDoc }); } } export async function deleteCultivo(id) { await db.collection('cultivos').deleteOne({ id }); } // ========== ESTUDIOS COMPLEMENTARIOS ========== export async function getAllEstudiosComplementarios() { const estudios = await db.collection('estudiosComplementarios').find().toArray(); return cleanDocs(estudios); } export async function createEstudioComplementario(estudio) { const doc = { id: estudio.id, pacienteId: estudio.pacienteId, internacionId: estudio.internacionId || null, fecha: estudio.fecha || null, tipo: estudio.tipo || null, resultado: estudio.resultado || null }; await db.collection('estudiosComplementarios').insertOne(doc); } export async function deleteEstudioComplementario(id) { await db.collection('estudiosComplementarios').deleteOne({ id }); } // ========== INTERCONSULTAS ========== export async function getAllInterconsultas() { const interconsultas = await db.collection('interconsultas').find().toArray(); return cleanDocs(interconsultas).map(ic => ({ ...ic, realizada: !!ic.realizada })); } export async function createInterconsulta(ic) { const doc = { id: ic.id, pacienteId: ic.pacienteId, internacionId: ic.internacionId, fecha: ic.fecha || null, servicioInterconsultado: ic.servicioInterconsultado, motivo: ic.motivo || null, respuestaInterconsulta: ic.respuestaInterconsulta || null, respuestaFecha: ic.respuestaFecha || null }; await db.collection('interconsultas').insertOne(doc); } export async function updateInterconsulta(id, datos) { const updateDoc = {}; for (const [key, val] of Object.entries(datos)) { if (val !== undefined) { updateDoc[key] = val; } } if (Object.keys(updateDoc).length > 0) { await db.collection('interconsultas').updateOne({ id }, { $set: updateDoc }); } } export async function deleteInterconsulta(id) { await db.collection('interconsultas').deleteOne({ id }); } // ========== ATB ========== export async function getAllAtb() { const atb = await db.collection('atb').find().toArray(); return cleanDocs(atb); } export async function createAtb(atb) { const doc = { id: atb.id, pacienteId: atb.pacienteId, internacionId: atb.internacionId, antibiotico: atb.antibiotico, fechaInicio: atb.fechaInicio, fechaFinalizacion: atb.fechaFinalizacion || null }; await db.collection('atb').insertOne(doc); } export async function deleteAtb(id) { await db.collection('atb').deleteOne({ id }); } // ========== INDICACIONES ========== export async function getAllIndicaciones() { const indicaciones = await db.collection('indicaciones').find().toArray(); return cleanDocs(indicaciones); } export async function createIndicacion(ind) { const doc = { id: ind.id, internacionId: ind.internacionId, tipo: ind.tipo, droga: ind.droga || null, dosis: ind.dosis || null, frecuenciaHoras: ind.frecuenciaHoras || null, via: ind.via || null, tipoPlan: ind.tipoPlan || null, tipoPlan2: ind.tipoPlan2 || null, cantidadMl: ind.cantidadMl || null, cantidadMl2: ind.cantidadMl2 || null, tiempoHoras: ind.tiempoHoras || null, estado: ind.estado || 'Activa', medicoCrea: ind.medicoCrea || null, fechaCrea: ind.fechaCrea || null, tipoInsulina: ind.tipoInsulina || null, unidadesDesayuno: ind.unidadesDesayuno || null, unidadesAlmuerzo: ind.unidadesAlmuerzo || null, unidadesNoche: ind.unidadesNoche || null, indicacionNoFco: ind.indicacionNoFco || null }; await db.collection('indicaciones').insertOne(doc); } export async function updateIndicacion(id, datos) { const updateDoc = {}; for (const [key, val] of Object.entries(datos)) { if (val !== undefined) { updateDoc[key] = val; } } if (Object.keys(updateDoc).length > 0) { await db.collection('indicaciones').updateOne({ id }, { $set: updateDoc }); } } export async function deleteIndicacion(id) { await db.collection('indicaciones').deleteOne({ id }); } // ========== MOVIMIENTOS INDICACIONES ========== export async function getAllMovimientosIndicaciones() { const movimientos = await db.collection('movimientos_indicaciones').find().toArray(); return cleanDocs(movimientos); } export async function createMovimientoIndicacion(mov) { const doc = { id: mov.id, indicacionId: mov.indicacionId, internacionId: mov.internacionId, tipo: mov.tipo, fecha: mov.fecha, profesional: mov.profesional, indicacionPrevia: mov.indicacionPrevia || null, indicacionNueva: mov.indicacionNueva || null }; await db.collection('movimientos_indicaciones').insertOne(doc); } // ========== KV STORE ========== export async function getValue(key) { const doc = await db.collection('kv').findOne({ key }); return doc?.value ?? null; } export async function setValue(key, value) { await db.collection('kv').updateOne( { key }, { $set: { key, value } }, { upsert: true } ); }