import { prisma } from './prisma' import { requireAuth } from './auth' // Using type from Prisma for now type UploadSession = any const DEFAULT_CHUNK_SIZE = 1024 * 1024 * 5 // 5MB chunks const UPLOAD_SESSION_EXPIRY = 24 * 60 * 60 * 1000 // 24 hours in ms export async function createUploadSession( userId: string, fileName: string, fileSize: number, mimeType: string, chunkSize?: number, metadata?: Record ): Promise { const actualChunkSize = chunkSize || DEFAULT_CHUNK_SIZE const totalChunks = Math.ceil(fileSize / actualChunkSize) const expiresAt = new Date(Date.now() + UPLOAD_SESSION_EXPIRY) const session = await prisma.uploadSession.create({ data: { userId, fileName, fileSize, mimeType, chunkSize: actualChunkSize, totalChunks, metadata: metadata ? JSON.stringify(metadata) : undefined, expiresAt, }, }) return { ...session, uploadedChunks: session.uploadedChunks ? JSON.parse(session.uploadedChunks) : [], metadata: session.metadata ? JSON.parse(session.metadata) : undefined, } } export async function getUploadSession(uploadId: string, userId: string): Promise { const session = await prisma.uploadSession.findFirst({ where: { id: uploadId, userId, expiresAt: { gt: new Date(), }, }, }) if (!session) { return null } return { ...session, uploadedChunks: session.uploadedChunks ? JSON.parse(session.uploadedChunks) : [], metadata: session.metadata ? JSON.parse(session.metadata) : undefined, } } export async function markChunkUploaded(uploadId: string, chunkIndex: number): Promise { const session = await prisma.uploadSession.findUnique({ where: { id: uploadId }, }) if (!session) { throw new Error('Upload session not found') } const uploadedChunks = session.uploadedChunks ? JSON.parse(session.uploadedChunks) : [] if (!uploadedChunks.includes(chunkIndex)) { uploadedChunks.push(chunkIndex) } const updatedSession = await prisma.uploadSession.update({ where: { id: uploadId }, data: { uploadedChunks: JSON.stringify(uploadedChunks), status: uploadedChunks.length >= session.totalChunks ? 'completed' : 'uploading', }, }) return { ...updatedSession, uploadedChunks: JSON.parse(updatedSession.uploadedChunks || '[]'), metadata: updatedSession.metadata ? JSON.parse(updatedSession.metadata) : undefined, } } export async function completeUploadSession(uploadId: string, fileId: string): Promise { const session = await prisma.uploadSession.update({ where: { id: uploadId }, data: { status: 'completed', fileId, }, }) return { ...session, uploadedChunks: session.uploadedChunks ? JSON.parse(session.uploadedChunks) : [], metadata: session.metadata ? JSON.parse(session.metadata) : undefined, } } export async function failUploadSession(uploadId: string): Promise { await prisma.uploadSession.update({ where: { id: uploadId }, data: { status: 'failed', }, }) } export async function generatePresignedUrl( fileName: string, mimeType: string, expiresIn: number = 3600 ): Promise<{ url: string; key: string }> { // This is a placeholder for actual S3/CloudStorage presigned URL generation // In a real implementation, you would use AWS SDK, Google Cloud Storage SDK, etc. const key = `uploads/${Date.now()}-${fileName}` // For now, return a mock URL - in production, generate a real presigned URL const url = `${process.env.NEXT_PUBLIC_APP_URL}/api/upload/presigned-upload?key=${encodeURIComponent(key)}` return { url, key } } export async function cleanupExpiredSessions(): Promise { await prisma.uploadSession.deleteMany({ where: { expiresAt: { lt: new Date(), }, status: { in: ['pending', 'uploading'], }, }, }) } // Helper function to validate file type export function validateFileType(mimeType: string, allowedTypes: string[]): boolean { return allowedTypes.some(type => { if (type.endsWith('/*')) { return mimeType.startsWith(type.slice(0, -1)) } return mimeType === type }) } // Helper function to validate file size export function validateFileSize(fileSize: number, maxSize: number): boolean { return fileSize <= maxSize }