import { NextRequest, NextResponse } from 'next/server' import { prisma } from '@/lib/prisma' import { WebhookPayloadSchema, ProjectInputSchema, type WebhookPayload, type ProjectInput, } from '@/lib/validations' export async function POST(request: NextRequest) { const startTime = Date.now() try { const body = await request.json() // Validate payload const validationResult = WebhookPayloadSchema.safeParse(body) if (!validationResult.success) { return NextResponse.json( { success: false, error: 'Validation error', details: validationResult.error.errors.map((e) => e.message), }, { status: 400 } ) } const payload = validationResult.data as WebhookPayload // Verify API Key const apiKey = process.env.WEBHOOK_API_KEY if (payload.apiKey !== apiKey) { return NextResponse.json( { success: false, error: 'Unauthorized', details: ['Invalid or missing API Key'], }, { status: 401 } ) } // Process projects with partial success mode const results = { processed: payload.projects.length, created: 0, updated: 0, failed: 0, errors: [] as Array<{ index: number field: string message: string value: any }>, } for (let i = 0; i < payload.projects.length; i++) { const projectData = payload.projects[i] // Validate individual project const projectValidation = ProjectInputSchema.safeParse(projectData) if (!projectValidation.success) { results.failed++ results.errors.push({ index: i, field: projectValidation.error.errors[0].path.join('.'), message: projectValidation.error.errors[0].message, value: projectData, }) continue } try { const validProject = projectValidation.data as ProjectInput // Upsert tags const tagConnections = await Promise.all( validProject.tags.map(async (tag) => { const slug = tag.nameEn?.toLowerCase().replace(/\s+/g, '-') || tag.name.toLowerCase().replace(/\s+/g, '-') return prisma.tag.upsert({ where: { slug }, update: {}, create: { name: tag.name, nameEn: tag.nameEn || null, slug, }, }) }) ) // Generate slug for project const slug = validProject.nameEn?.toLowerCase().replace(/\s+/g, '-') || validProject.name.toLowerCase().replace(/\s+/g, '-') // Upsert project const existingProject = await prisma.project.findUnique({ where: { slug }, }) if (existingProject) { // Update existing project await prisma.project.update({ where: { id: existingProject.id }, data: { name: validProject.name, nameEn: validProject.nameEn || null, description: validProject.description, descriptionEn: validProject.descriptionEn || null, content: validProject.content || null, contentEn: validProject.contentEn || null, status: validProject.status as any, source: validProject.source || null, tags: { set: tagConnections.map((t) => ({ id: t.id })), }, }, }) // Update links (delete old ones, create new ones) await prisma.externalLink.deleteMany({ where: { projectId: existingProject.id }, }) await prisma.externalLink.createMany({ data: validProject.links.map((link) => ({ type: link.type as any, url: link.url, title: link.title || null, projectId: existingProject.id, })), }) results.updated++ } else { // Create new project await prisma.project.create({ data: { name: validProject.name, nameEn: validProject.nameEn || null, slug, description: validProject.description, descriptionEn: validProject.descriptionEn || null, content: validProject.content || null, contentEn: validProject.contentEn || null, status: validProject.status as any, source: validProject.source || null, tags: { connect: tagConnections.map((t) => ({ id: t.id })), }, links: { create: validProject.links.map((link) => ({ type: link.type as any, url: link.url, title: link.title || null, })), }, }, }) results.created++ } } catch (error) { results.failed++ results.errors.push({ index: i, field: 'general', message: error instanceof Error ? error.message : 'Unknown error', value: projectData, }) } } const duration = Date.now() - startTime // Log request console.log( `[Webhook] Processed ${results.processed} projects in ${duration}ms: ${results.created} created, ${results.updated} updated, ${results.failed} failed` ) return NextResponse.json({ success: true, ...results, }) } catch (error) { console.error('[Webhook] Error:', error) return NextResponse.json( { success: false, error: 'Internal server error', details: [error instanceof Error ? error.message : 'Unknown error'], }, { status: 500 } ) } }