import { NextRequest, NextResponse } from 'next/server' import { requireAuth } from '@/lib/auth' import { getUploadSession, completeUploadSession } from '@/lib/upload' import { prisma } from '@/lib/prisma' import { readFile, writeFile, mkdir, rm } from 'fs/promises' import { join } from 'path' export async function POST( request: NextRequest, { params }: { params: Promise<{ uploadId: string }> } ) { try { const user = await requireAuth() const { uploadId } = await params // Get upload session const uploadSession = await getUploadSession(uploadId, user.id) if (!uploadSession) { return NextResponse.json( { error: 'Upload session not found or expired' }, { status: 404 } ) } if (uploadSession.status !== 'completed') { return NextResponse.json( { error: 'Upload not complete. All chunks must be uploaded first.' }, { status: 400 } ) } // Combine chunks into a single file const tempDir = join(process.cwd(), 'temp', 'uploads', uploadId) const finalPath = join(process.cwd(), 'uploads', `${uploadId}-${uploadSession.fileName}`) // Ensure uploads directory exists await mkdir(join(process.cwd(), 'uploads'), { recursive: true }) // Combine all chunks const fileBuffer = Buffer.alloc(uploadSession.fileSize) let offset = 0 for (let i = 0; i < uploadSession.totalChunks; i++) { const chunkPath = join(tempDir, `chunk-${i}`) const chunkData = await readFile(chunkPath) chunkData.copy(fileBuffer, offset) offset += chunkData.length } // Write the complete file await writeFile(finalPath, fileBuffer) // Create a database record for the uploaded file const fileId = `file_${Date.now()}_${uploadId}` // In a real implementation, you would: // 1. Upload to S3/CloudStorage // 2. Store the URL/Key in the database // 3. Process the file (transcode audio, generate thumbnails, etc.) // For now, we'll create a simple record let createdRecord = null if (uploadSession.mimeType.startsWith('audio/')) { // Create a song record createdRecord = await prisma.song.create({ data: { artistId: user.id, // Assuming user is an artist title: uploadSession.fileName.replace(/\.[^/.]+$/, ''), // Remove extension slug: uploadSession.fileName.replace(/\.[^/.]+$/, '').toLowerCase().replace(/\s+/g, '-'), audioUrl: `/uploads/${uploadId}-${uploadSession.fileName}`, duration: 0, // Would be determined during processing isPublic: false, // Default to private until processed }, }) } else if (uploadSession.mimeType.startsWith('image/')) { // Could create an image record or associate with artist/album // For now, just store the file reference } // Mark upload session as complete with file ID const completedSession = await completeUploadSession(uploadId, fileId) // Clean up temporary chunks await rm(tempDir, { recursive: true, force: true }) return NextResponse.json( { success: true, fileId, fileName: uploadSession.fileName, fileSize: uploadSession.fileSize, mimeType: uploadSession.mimeType, record: createdRecord, uploadSession: completedSession, }, { status: 200 } ) } catch (error) { console.error('Upload complete error:', error) if (error instanceof Error && error.message === 'Unauthorized') { return NextResponse.json( { error: 'Unauthorized' }, { status: 401 } ) } return NextResponse.json( { error: 'Failed to complete upload' }, { status: 500 } ) } }