import { prisma as db } from "@repo/db/client"; import { PdfCategory } from "@repo/db/generated/prisma"; import { Appointment, Claim, ClaimWithServiceLines, InsertAppointment, InsertClaim, InsertInsuranceCredential, InsertPatient, InsertPayment, InsertUser, InsuranceCredential, Patient, Payment, PaymentWithExtras, PdfFile, PdfGroup, Staff, UpdateAppointment, UpdateClaim, UpdatePatient, UpdatePayment, User, } from "@repo/db/types"; export interface IStorage { // User methods getUser(id: number): Promise; getUserByUsername(username: string): Promise; createUser(user: InsertUser): Promise; updateUser(id: number, updates: Partial): Promise; deleteUser(id: number): Promise; // Patient methods getPatient(id: number): Promise; getPatientByInsuranceId(insuranceId: string): Promise; getPatientsByUserId(userId: number): Promise; getRecentPatients(limit: number, offset: number): Promise; getTotalPatientCount(): Promise; createPatient(patient: InsertPatient): Promise; updatePatient(id: number, patient: UpdatePatient): Promise; deletePatient(id: number): Promise; searchPatients(args: { filters: any; limit: number; offset: number; }): Promise< { id: number; firstName: string | null; lastName: string | null; phone: string | null; gender: string | null; dateOfBirth: Date; insuranceId: string | null; insuranceProvider: string | null; status: string; }[] >; countPatients(filters: any): Promise; // optional but useful // Appointment methods getAppointment(id: number): Promise; getAllAppointments(): Promise; getAppointmentsByUserId(userId: number): Promise; getAppointmentsByPatientId(patientId: number): Promise; getRecentAppointments(limit: number, offset: number): Promise; getAppointmentsOn(date: Date): Promise; createAppointment(appointment: InsertAppointment): Promise; updateAppointment( id: number, appointment: UpdateAppointment ): Promise; deleteAppointment(id: number): Promise; getPatientAppointmentByDateTime( patientId: number, date: Date, startTime: string ): Promise; getStaffAppointmentByDateTime( staffId: number, date: Date, startTime: string, excludeId?: number ): Promise; getPatientConflictAppointment( patientId: number, date: Date, startTime: string, excludeId: number ): Promise; getStaffConflictAppointment( staffId: number, date: Date, startTime: string, excludeId: number ): Promise; // Staff methods getStaff(id: number): Promise; getAllStaff(): Promise; createStaff(staff: Staff): Promise; updateStaff(id: number, updates: Partial): Promise; deleteStaff(id: number): Promise; // Claim methods getClaim(id: number): Promise; getRecentClaimsByPatientId( patientId: number, limit: number, offset: number ): Promise; getTotalClaimCountByPatient(patientId: number): Promise; getClaimsByAppointmentId(appointmentId: number): Promise; getRecentClaimsByUser( userId: number, limit: number, offset: number ): Promise; getTotalClaimCountByUser(userId: number): Promise; createClaim(claim: InsertClaim): Promise; updateClaim(id: number, updates: UpdateClaim): Promise; deleteClaim(id: number): Promise; // InsuranceCredential methods getInsuranceCredentialsByUser(userId: number): Promise; createInsuranceCredential( data: InsertInsuranceCredential ): Promise; updateInsuranceCredential( id: number, updates: Partial ): Promise; deleteInsuranceCredential(id: number): Promise; getInsuranceCredentialByUserAndSiteKey( userId: number, siteKey: string ): Promise; // General PDF Methods createPdfFile( groupId: number, filename: string, pdfData: Buffer ): Promise; getPdfFileById(id: number): Promise; getPdfFilesByGroupId(groupId: number): Promise; getRecentPdfFiles(limit: number, offset: number): Promise; deletePdfFile(id: number): Promise; updatePdfFile( id: number, updates: Partial> ): Promise; // PDF Group management createPdfGroup( patientId: number, title: string, category: PdfCategory ): Promise; findPdfGroupByPatientTitleAndCategory( patientId: number, title: string, category: PdfCategory ): Promise; getAllPdfGroups(): Promise; getPdfGroupById(id: number): Promise; getPdfGroupsByPatientId(patientId: number): Promise; updatePdfGroup( id: number, updates: Partial> ): Promise; deletePdfGroup(id: number): Promise; // Payment methods: createPayment(data: InsertPayment): Promise; updatePayment( id: number, updates: UpdatePayment, userId: number ): Promise; deletePayment(id: number, userId: number): Promise; getPaymentById(id: number, userId: number): Promise; getPaymentsByClaimId( claimId: number, userId: number ): Promise; getPaymentsByPatientId( patientId: number, userId: number ): Promise; getRecentPaymentsByUser( userId: number, limit: number, offset: number ): Promise; getPaymentsByDateRange( userId: number, from: Date, to: Date ): Promise; getTotalPaymentCountByUser(userId: number): Promise; } export const storage: IStorage = { // User methods async getUser(id: number): Promise { const user = await db.user.findUnique({ where: { id } }); return user ?? undefined; }, async getUserByUsername(username: string): Promise { const user = await db.user.findUnique({ where: { username } }); return user ?? undefined; }, async createUser(user: InsertUser): Promise { return await db.user.create({ data: user as User }); }, async updateUser( id: number, updates: Partial ): Promise { try { return await db.user.update({ where: { id }, data: updates }); } catch { return undefined; } }, async deleteUser(id: number): Promise { try { await db.user.delete({ where: { id } }); return true; } catch { return false; } }, // Patient methods async getPatient(id: number): Promise { const patient = await db.patient.findUnique({ where: { id } }); return patient ?? undefined; }, async getPatientsByUserId(userId: number): Promise { return await db.patient.findMany({ where: { userId } }); }, async getPatientByInsuranceId(insuranceId: string): Promise { return db.patient.findFirst({ where: { insuranceId }, }); }, async getRecentPatients(limit: number, offset: number): Promise { return db.patient.findMany({ skip: offset, take: limit, orderBy: { createdAt: "desc" }, }); }, async searchPatients({ filters, limit, offset, }: { filters: any; limit: number; offset: number; }) { return db.patient.findMany({ where: filters, orderBy: { createdAt: "desc" }, take: limit, skip: offset, select: { id: true, firstName: true, lastName: true, phone: true, gender: true, dateOfBirth: true, insuranceId: true, insuranceProvider: true, status: true, }, }); }, async getTotalPatientCount(): Promise { return db.patient.count(); }, async countPatients(filters: any) { return db.patient.count({ where: filters }); }, async createPatient(patient: InsertPatient): Promise { return await db.patient.create({ data: patient as Patient }); }, async updatePatient(id: number, updateData: UpdatePatient): Promise { try { return await db.patient.update({ where: { id }, data: updateData, }); } catch (err) { throw new Error(`Patient with ID ${id} not found`); } }, async deletePatient(id: number): Promise { try { await db.patient.delete({ where: { id } }); } catch (err) { console.error("Error deleting patient:", err); throw new Error(`Failed to delete patient: ${err}`); } }, // Appointment methods async getAppointment(id: number): Promise { const appointment = await db.appointment.findUnique({ where: { id } }); return appointment ?? undefined; }, async getAllAppointments(): Promise { return await db.appointment.findMany(); }, async getAppointmentsByUserId(userId: number): Promise { return await db.appointment.findMany({ where: { userId } }); }, async getAppointmentsByPatientId(patientId: number): Promise { return await db.appointment.findMany({ where: { patientId } }); }, async getAppointmentsOn(date: Date): Promise { const start = new Date(date); start.setHours(0, 0, 0, 0); const end = new Date(date); end.setHours(23, 59, 59, 999); return db.appointment.findMany({ where: { date: { gte: start, lte: end, }, }, orderBy: { date: "asc" }, }); }, async getRecentAppointments( limit: number, offset: number ): Promise { return db.appointment.findMany({ skip: offset, take: limit, orderBy: { date: "desc" }, }); }, async createAppointment( appointment: InsertAppointment ): Promise { return await db.appointment.create({ data: appointment as Appointment }); }, async updateAppointment( id: number, updateData: UpdateAppointment ): Promise { try { return await db.appointment.update({ where: { id }, data: updateData, }); } catch (err) { throw new Error(`Appointment with ID ${id} not found`); } }, async deleteAppointment(id: number): Promise { try { await db.appointment.delete({ where: { id } }); } catch (err) { throw new Error(`Appointment with ID ${id} not found`); } }, async getPatientAppointmentByDateTime( patientId: number, date: Date, startTime: string ): Promise { return ( (await db.appointment.findFirst({ where: { patientId, date, startTime, }, })) ?? undefined ); }, async getStaffAppointmentByDateTime( staffId: number, date: Date, startTime: string, excludeId?: number ): Promise { return ( (await db.appointment.findFirst({ where: { staffId, date, startTime, NOT: excludeId ? { id: excludeId } : undefined, }, })) ?? undefined ); }, async getPatientConflictAppointment( patientId: number, date: Date, startTime: string, excludeId: number ): Promise { return ( (await db.appointment.findFirst({ where: { patientId, date, startTime, NOT: { id: excludeId }, }, })) ?? undefined ); }, async getStaffConflictAppointment( staffId: number, date: Date, startTime: string, excludeId: number ): Promise { return ( (await db.appointment.findFirst({ where: { staffId, date, startTime, NOT: { id: excludeId }, }, })) ?? undefined ); }, // Staff methods async getStaff(id: number): Promise { const staff = await db.staff.findUnique({ where: { id } }); return staff ?? undefined; }, async getAllStaff(): Promise { const staff = await db.staff.findMany(); return staff; }, async createStaff(staff: Staff): Promise { const createdStaff = await db.staff.create({ data: staff, }); return createdStaff; }, async updateStaff( id: number, updates: Partial ): Promise { const updatedStaff = await db.staff.update({ where: { id }, data: updates, }); return updatedStaff ?? undefined; }, async deleteStaff(id: number): Promise { try { await db.staff.delete({ where: { id } }); return true; } catch (error) { console.error("Error deleting staff:", error); return false; } }, // Claim methods implementation async getClaim(id: number): Promise { const claim = await db.claim.findUnique({ where: { id } }); return claim ?? undefined; }, async getRecentClaimsByPatientId( patientId: number, limit: number, offset: number ): Promise { return db.claim.findMany({ where: { patientId }, orderBy: { createdAt: "desc" }, skip: offset, take: limit, include: { serviceLines: true, staff: true, }, }); }, async getTotalClaimCountByPatient(patientId: number): Promise { return db.claim.count({ where: { patientId }, }); }, async getClaimsByAppointmentId(appointmentId: number): Promise { return await db.claim.findMany({ where: { appointmentId } }); }, async getRecentClaimsByUser( userId: number, limit: number, offset: number ): Promise { return db.claim.findMany({ where: { userId }, orderBy: { createdAt: "desc" }, skip: offset, take: limit, include: { serviceLines: true, staff: true }, }); }, async getTotalClaimCountByUser(userId: number): Promise { return db.claim.count({ where: { userId } }); }, async createClaim(claim: InsertClaim): Promise { return await db.claim.create({ data: claim as Claim }); }, async updateClaim(id: number, updates: UpdateClaim): Promise { try { return await db.claim.update({ where: { id }, data: updates, }); } catch (err) { throw new Error(`Claim with ID ${id} not found`); } }, async deleteClaim(id: number): Promise { try { await db.claim.delete({ where: { id } }); } catch (err) { throw new Error(`Claim with ID ${id} not found`); } }, // Insurance Creds async getInsuranceCredentialsByUser(userId: number) { return await db.insuranceCredential.findMany({ where: { userId } }); }, async createInsuranceCredential(data: InsertInsuranceCredential) { return await db.insuranceCredential.create({ data: data as InsuranceCredential, }); }, async updateInsuranceCredential( id: number, updates: Partial ) { return await db.insuranceCredential.update({ where: { id }, data: updates, }); }, async deleteInsuranceCredential(id: number) { await db.insuranceCredential.delete({ where: { id } }); }, async getInsuranceCredentialByUserAndSiteKey( userId: number, siteKey: string ): Promise { return await db.insuranceCredential.findFirst({ where: { userId, siteKey }, }); }, // PDF Files async createPdfFile(groupId, filename, pdfData) { return db.pdfFile.create({ data: { groupId, filename, pdfData, }, }); }, async getAllPdfGroups(): Promise { return db.pdfGroup.findMany({ orderBy: { createdAt: "desc", }, }); }, async getPdfFileById(id) { return (await db.pdfFile.findUnique({ where: { id } })) ?? undefined; }, async getPdfFilesByGroupId(groupId) { return db.pdfFile.findMany({ where: { groupId }, orderBy: { uploadedAt: "desc" }, }); }, async getRecentPdfFiles(limit: number, offset: number): Promise { return db.pdfFile.findMany({ skip: offset, take: limit, orderBy: { uploadedAt: "desc" }, include: { group: true }, }); }, async updatePdfFile(id, updates) { try { return await db.pdfFile.update({ where: { id }, data: updates, }); } catch { return undefined; } }, async deletePdfFile(id) { try { await db.pdfFile.delete({ where: { id } }); return true; } catch { return false; } }, // ---------------------- // PdfGroup CRUD // ---------------------- async createPdfGroup(patientId, title, category) { return db.pdfGroup.create({ data: { patientId, title, category, }, }); }, async findPdfGroupByPatientTitleAndCategory(patientId, title, category) { return ( (await db.pdfGroup.findFirst({ where: { patientId, title, category, }, })) ?? undefined ); }, async getPdfGroupById(id) { return (await db.pdfGroup.findUnique({ where: { id } })) ?? undefined; }, async getPdfGroupsByPatientId(patientId) { return db.pdfGroup.findMany({ where: { patientId }, orderBy: { createdAt: "desc" }, }); }, async updatePdfGroup(id, updates) { try { return await db.pdfGroup.update({ where: { id }, data: updates, }); } catch { return undefined; } }, async deletePdfGroup(id) { try { await db.pdfGroup.delete({ where: { id } }); return true; } catch { return false; } }, // Payment Methods async createPayment(payment: InsertPayment): Promise { return db.payment.create({ data: payment as Payment }); }, async updatePayment( id: number, updates: UpdatePayment, userId: number ): Promise { const existing = await db.payment.findFirst({ where: { id, userId } }); if (!existing) { throw new Error("Not authorized or payment not found"); } return db.payment.update({ where: { id }, data: updates, }); }, async deletePayment(id: number, userId: number): Promise { const existing = await db.payment.findFirst({ where: { id, userId } }); if (!existing) { throw new Error("Not authorized or payment not found"); } await db.payment.delete({ where: { id } }); }, async getPaymentById( id: number, userId: number ): Promise { const payment = await db.payment.findFirst({ where: { id, userId }, include: { claim: { include: { serviceLines: true, }, }, serviceLineTransactions: { include: { serviceLine: true, }, }, updatedBy: true, }, }); if (!payment) return null; return { ...payment, patientName: payment.claim?.patientName ?? "", paymentDate: payment.createdAt, paymentMethod: payment.serviceLineTransactions[0]?.method ?? "OTHER", }; }, async getPaymentsByClaimId( claimId: number, userId: number ): Promise { const payment = await db.payment.findFirst({ where: { claimId, userId }, include: { claim: { include: { serviceLines: true, }, }, serviceLineTransactions: { include: { serviceLine: true, }, }, updatedBy: true, }, }); if (!payment) return null; return { ...payment, patientName: payment.claim?.patientName ?? "", paymentDate: payment.createdAt, paymentMethod: payment.serviceLineTransactions[0]?.method ?? "OTHER", }; }, async getPaymentsByPatientId( patientId: number, userId: number ): Promise { const payments = await db.payment.findMany({ where: { patientId, userId }, include: { claim: { include: { serviceLines: true, }, }, serviceLineTransactions: { include: { serviceLine: true, }, }, updatedBy: true, }, }); return payments.map((payment) => ({ ...payment, patientName: payment.claim?.patientName ?? "", paymentDate: payment.createdAt, paymentMethod: payment.serviceLineTransactions[0]?.method ?? "OTHER", })); }, async getRecentPaymentsByUser( userId: number, limit: number, offset: number ): Promise { const payments = await db.payment.findMany({ where: { userId }, orderBy: { createdAt: "desc" }, skip: offset, take: limit, include: { claim: { include: { serviceLines: true, }, }, serviceLineTransactions: { include: { serviceLine: true, }, }, updatedBy: true, }, }); return payments.map((payment) => ({ ...payment, patientName: payment.claim?.patientName ?? "", paymentDate: payment.createdAt, paymentMethod: payment.serviceLineTransactions[0]?.method ?? "OTHER", })); }, async getPaymentsByDateRange( userId: number, from: Date, to: Date ): Promise { const payments = await db.payment.findMany({ where: { userId, createdAt: { gte: from, lte: to, }, }, orderBy: { createdAt: "desc" }, include: { claim: { include: { serviceLines: true, }, }, serviceLineTransactions: { include: { serviceLine: true, }, }, updatedBy: true, }, }); return payments.map((payment) => ({ ...payment, patientName: payment.claim?.patientName ?? "", paymentDate: payment.createdAt, paymentMethod: payment.serviceLineTransactions[0]?.method ?? "OTHER", })); }, async getTotalPaymentCountByUser(userId: number): Promise { return db.payment.count({ where: { userId } }); }, };