import { randomUUID } from 'crypto'; import type { CreateDocumentBody, DocumentRecord, DocumentType, UpdateDocumentBody } from './documents.types'; import { DocumentsRepository } from '../data/documents.repository'; import pool from '../../../core/config/database'; export class DocumentsService { private readonly repo = new DocumentsRepository(pool); async createDocument(userId: string, body: CreateDocumentBody): Promise { await this.assertVehicleOwnership(userId, body.vehicleId); const id = randomUUID(); return this.repo.insert({ id, userId, vehicleId: body.vehicleId, documentType: body.documentType as DocumentType, title: body.title, notes: body.notes ?? null, details: body.details ?? null, issuedDate: body.issuedDate ?? null, expirationDate: body.expirationDate ?? null, emailNotifications: body.emailNotifications ?? false, scanForMaintenance: body.scanForMaintenance ?? false, }); } async getDocument(userId: string, id: string): Promise { return this.repo.findById(id, userId); } async listDocuments(userId: string, filters?: { vehicleId?: string; type?: DocumentType; expiresBefore?: string }) { return this.repo.listByUser(userId, filters); } async updateDocument(userId: string, id: string, patch: UpdateDocumentBody) { const existing = await this.repo.findById(id, userId); if (!existing) return null; if (patch && typeof patch === 'object') { return this.repo.updateMetadata(id, userId, patch as any); } return existing; } async deleteDocument(userId: string, id: string): Promise { await this.repo.softDelete(id, userId); } private async assertVehicleOwnership(userId: string, vehicleId: string) { const res = await pool.query('SELECT id FROM vehicles WHERE id = $1 AND user_id = $2', [vehicleId, userId]); if (!res.rows[0]) { const err: any = new Error('Vehicle not found or not owned by user'); err.statusCode = 403; throw err; } } }