import { and, eq } from 'drizzle-orm'; import { db } from '@/lib/db'; import { yachts, yachtOwnershipHistory, clients } from '@/lib/db/schema'; import { companies } from '@/lib/db/schema/companies'; import { createAuditLog } from '@/lib/audit'; import { NotFoundError, ValidationError } from '@/lib/errors'; import { emitToRoom } from '@/lib/socket/server'; import { withTransaction } from '@/lib/db/utils'; import type { z } from 'zod'; import type { createYachtSchema } from '@/lib/validators/yachts'; type CreateYachtInput = z.input; interface AuditMeta { userId: string; portId: string; ipAddress: string; userAgent: string; } async function assertOwnerExists( portId: string, owner: { type: 'client' | 'company'; id: string }, tx: typeof db, ): Promise { if (owner.type === 'client') { const client = await tx.query.clients.findFirst({ where: and(eq(clients.id, owner.id), eq(clients.portId, portId)), }); if (!client) throw new ValidationError('owner not found'); } else { const company = await tx.query.companies.findFirst({ where: and(eq(companies.id, owner.id), eq(companies.portId, portId)), }); if (!company) throw new ValidationError('owner not found'); } } export async function createYacht(portId: string, data: CreateYachtInput, meta: AuditMeta) { return await withTransaction(async (tx) => { await assertOwnerExists(portId, data.owner, tx); const [yacht] = await tx .insert(yachts) .values({ portId, name: data.name, hullNumber: data.hullNumber ?? null, registration: data.registration ?? null, flag: data.flag ?? null, yearBuilt: data.yearBuilt ?? null, builder: data.builder ?? null, model: data.model ?? null, hullMaterial: data.hullMaterial ?? null, lengthFt: data.lengthFt ?? null, widthFt: data.widthFt ?? null, draftFt: data.draftFt ?? null, lengthM: data.lengthM ?? null, widthM: data.widthM ?? null, draftM: data.draftM ?? null, currentOwnerType: data.owner.type, currentOwnerId: data.owner.id, status: data.status ?? 'active', notes: data.notes ?? null, }) .returning(); await tx.insert(yachtOwnershipHistory).values({ yachtId: yacht!.id, ownerType: data.owner.type, ownerId: data.owner.id, startDate: new Date(), endDate: null, createdBy: meta.userId, }); void createAuditLog({ userId: meta.userId, portId, action: 'create', entityType: 'yacht', entityId: yacht!.id, newValue: { name: yacht!.name, owner: data.owner }, ipAddress: meta.ipAddress, userAgent: meta.userAgent, }); emitToRoom(`port:${portId}`, 'yacht:created', { yachtId: yacht!.id }); return yacht!; }); } export async function getYachtById(id: string, portId: string) { const yacht = await db.query.yachts.findFirst({ where: and(eq(yachts.id, id), eq(yachts.portId, portId)), }); if (!yacht) throw new NotFoundError('Yacht'); return yacht; }