import { and, desc, eq } from 'drizzle-orm'; import { db } from '@/lib/db'; import { formTemplates } from '@/lib/db/schema/documents'; import { createAuditLog } from '@/lib/audit'; import { NotFoundError } from '@/lib/errors'; import type { CreateFormTemplateInput, UpdateFormTemplateInput, } from '@/lib/validators/form-templates'; interface AuditMeta { userId: string; portId: string; ipAddress?: string; userAgent?: string; } export async function listFormTemplates(portId: string) { return db .select() .from(formTemplates) .where(eq(formTemplates.portId, portId)) .orderBy(desc(formTemplates.updatedAt)); } export async function getFormTemplateById(id: string, portId: string) { const tpl = await db.query.formTemplates.findFirst({ where: and(eq(formTemplates.id, id), eq(formTemplates.portId, portId)), }); if (!tpl) throw new NotFoundError('Form template'); return tpl; } export async function createFormTemplate( portId: string, data: CreateFormTemplateInput, meta: AuditMeta, ) { const [tpl] = await db .insert(formTemplates) .values({ portId, name: data.name, description: data.description ?? null, fields: data.fields, branding: data.branding ?? {}, isActive: data.isActive ?? true, createdBy: meta.userId, }) .returning(); if (!tpl) throw new Error('Insert failed'); void createAuditLog({ userId: meta.userId, portId, action: 'create', entityType: 'form_template', entityId: tpl.id, newValue: { name: data.name }, ipAddress: meta.ipAddress ?? '', userAgent: meta.userAgent ?? '', }); return tpl; } export async function updateFormTemplate( id: string, portId: string, data: UpdateFormTemplateInput, meta: AuditMeta, ) { const existing = await getFormTemplateById(id, portId); const [updated] = await db .update(formTemplates) .set({ ...(data.name !== undefined && { name: data.name }), ...(data.description !== undefined && { description: data.description ?? null }), ...(data.fields !== undefined && { fields: data.fields }), ...(data.branding !== undefined && { branding: data.branding }), ...(data.isActive !== undefined && { isActive: data.isActive }), updatedAt: new Date(), }) .where(eq(formTemplates.id, id)) .returning(); if (!updated) throw new NotFoundError('Form template'); void createAuditLog({ userId: meta.userId, portId, action: 'update', entityType: 'form_template', entityId: id, oldValue: { name: existing.name }, newValue: data, ipAddress: meta.ipAddress ?? '', userAgent: meta.userAgent ?? '', }); return updated; } export async function deleteFormTemplate(id: string, portId: string, meta: AuditMeta) { await getFormTemplateById(id, portId); await db.delete(formTemplates).where(eq(formTemplates.id, id)); void createAuditLog({ userId: meta.userId, portId, action: 'delete', entityType: 'form_template', entityId: id, ipAddress: meta.ipAddress ?? '', userAgent: meta.userAgent ?? '', }); }