import { and, desc, eq, isNull, or, sql } from "drizzle-orm"; import { getDatabase } from "@/modules/core/server/db"; import { admissions, beds, elders, rooms, systemIncidents } from "@/modules/core/server/schema"; import type { Admission, FacilityBed, Room, SystemIncident } from "@/modules/core/types"; import type { Elder } from "@/modules/elders/types"; function iso(value: Date): string { return value.toISOString(); } type ActiveBedLabel = { bed: string; bedId: string; room: string; }; function toElder(row: typeof elders.$inferSelect, activeBed?: ActiveBedLabel): Elder { return { id: row.id, organizationId: row.organizationId, name: row.name, gender: row.gender, age: row.age, careLevel: row.careLevel, room: activeBed?.room ?? "", bed: activeBed?.bed ?? "", bedId: activeBed?.bedId, status: row.status, primaryContact: row.primaryContact, phone: row.phone, medicalNotes: row.medicalNotes, createdAt: iso(row.createdAt), updatedAt: iso(row.updatedAt), }; } export async function listOperationalElders(organizationId?: string): Promise { const database = getDatabase(); const [elderRows, activeAdmissionRows] = await Promise.all([ database .select() .from(elders) .where(organizationId ? eq(elders.organizationId, organizationId) : sql`true`) .orderBy(desc(elders.createdAt)), database .select({ bedCode: beds.code, bedId: admissions.bedId, elderId: admissions.elderId, roomName: rooms.name, }) .from(admissions) .innerJoin(beds, eq(beds.id, admissions.bedId)) .innerJoin(rooms, eq(rooms.id, beds.roomId)) .where( organizationId ? and(eq(admissions.organizationId, organizationId), eq(admissions.status, "active")) : eq(admissions.status, "active"), ) .orderBy(desc(admissions.admittedAt)), ]); const bedLabelByElderId = new Map(); for (const row of activeAdmissionRows) { if (bedLabelByElderId.has(row.elderId)) { continue; } bedLabelByElderId.set(row.elderId, { room: row.roomName, bed: row.bedCode, bedId: row.bedId, }); } return elderRows.map((row) => toElder(row, bedLabelByElderId.get(row.id))); } export async function listOperationalRooms(organizationId?: string): Promise { const database = getDatabase(); const [roomRows, bedRows] = await Promise.all([ database .select() .from(rooms) .where(organizationId ? eq(rooms.organizationId, organizationId) : sql`true`) .orderBy(desc(rooms.createdAt)), database .select() .from(beds) .where(organizationId ? eq(beds.organizationId, organizationId) : sql`true`), ]); const bedCounts = new Map(); for (const bed of bedRows) { const current = bedCounts.get(bed.roomId) ?? { occupied: 0, total: 0 }; current.total += 1; if (bed.status === "occupied") { current.occupied += 1; } bedCounts.set(bed.roomId, current); } return roomRows.map((room) => { const counts = bedCounts.get(room.id) ?? { occupied: 0, total: 0 }; return { id: room.id, organizationId: room.organizationId, name: room.name, code: room.code, capacity: room.capacity, status: room.status, bedCount: counts.total, occupiedBedCount: counts.occupied, createdAt: iso(room.createdAt), updatedAt: iso(room.updatedAt), }; }); } export async function listOperationalBeds(organizationId?: string): Promise { const database = getDatabase(); const bedRows = await database .select({ bed: beds, currentElderName: sql`( select ${elders.name} from ${admissions} inner join ${elders} on ${elders.id} = ${admissions.elderId} where ${admissions.bedId} = ${beds.id} and ${admissions.status} = 'active' order by ${admissions.admittedAt} desc limit 1 )`, roomName: rooms.name, }) .from(beds) .innerJoin(rooms, eq(rooms.id, beds.roomId)) .where(organizationId ? eq(beds.organizationId, organizationId) : sql`true`) .orderBy(desc(beds.createdAt)); return bedRows.map((row) => ({ id: row.bed.id, organizationId: row.bed.organizationId, roomId: row.bed.roomId, roomName: row.roomName, code: row.bed.code, status: row.bed.status, notes: row.bed.notes, currentElderName: row.currentElderName ?? undefined, createdAt: iso(row.bed.createdAt), updatedAt: iso(row.bed.updatedAt), })); } export async function listOperationalAdmissions(organizationId?: string): Promise { const database = getDatabase(); const admissionRows = await database .select({ admission: admissions, bedCode: beds.code, elderName: elders.name, roomName: rooms.name, }) .from(admissions) .innerJoin(elders, eq(elders.id, admissions.elderId)) .innerJoin(beds, eq(beds.id, admissions.bedId)) .innerJoin(rooms, eq(rooms.id, beds.roomId)) .where(organizationId ? eq(admissions.organizationId, organizationId) : sql`true`) .orderBy(desc(admissions.admittedAt)); return admissionRows.map((row) => ({ id: row.admission.id, organizationId: row.admission.organizationId, elderId: row.admission.elderId, elderName: row.elderName, bedId: row.admission.bedId, bedCode: row.bedCode, roomName: row.roomName, status: row.admission.status, admittedAt: iso(row.admission.admittedAt), dischargedAt: row.admission.dischargedAt ? iso(row.admission.dischargedAt) : undefined, notes: row.admission.notes, })); } export async function listOperationalIncidents(organizationId?: string): Promise { const database = getDatabase(); const incidentRows = await database .select() .from(systemIncidents) .where(organizationId ? or(isNull(systemIncidents.organizationId), eq(systemIncidents.organizationId, organizationId)) : sql`true`) .orderBy(desc(systemIncidents.createdAt)); return incidentRows.map((incident) => ({ id: incident.id, organizationId: incident.organizationId ?? undefined, severity: incident.severity, status: incident.status, title: incident.title, description: incident.description, source: incident.source, createdAt: iso(incident.createdAt), updatedAt: iso(incident.updatedAt), })); }