import { NextRequest, NextResponse } from 'next/server' import { supabase } from '@/lib/supabase' import nodemailer from 'nodemailer' import { requireAuth } from '@/lib/api-auth' // API route configuration - dynamic for POST requests export const dynamic = 'force-dynamic' export const runtime = 'nodejs' // Initialize nodemailer transporter with Supabase SMTP configuration const createTransporter = () => { const smtpHost = process.env.SMTP_HOST const smtpPort = process.env.SMTP_PORT ? parseInt(process.env.SMTP_PORT) : 587 const smtpUser = process.env.SMTP_USER const smtpPassword = process.env.SMTP_PASSWORD const smtpFromEmail = process.env.SMTP_FROM_EMAIL || 'BUILDMATE ' const smtpFromName = process.env.SMTP_FROM_NAME || 'BUILDMATE' // Validate for placeholders if (smtpHost === 'your_smtp_host' || smtpUser === 'your_smtp_user' || smtpPassword === 'your_smtp_password') { throw new Error('SMTP credentials in .env.local are still placeholders. Please replace them with actual values.') } if (!smtpHost || !smtpUser || !smtpPassword) { throw new Error('SMTP credentials (host, user, password) are missing in environment variables.') } return nodemailer.createTransport({ host: smtpHost, port: smtpPort, secure: smtpPort === 465, // true for 465, false for other ports auth: { user: smtpUser, pass: smtpPassword, }, }) } export async function POST(request: NextRequest) { const auth = await requireAuth(request) if (auth.error) return auth.error try { const { buildId, userEmail } = await request.json() if (!buildId || !userEmail) { return NextResponse.json( { error: 'Build ID and user email are required' }, { status: 400 } ) } // Validate email format const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ if (!emailRegex.test(userEmail)) { return NextResponse.json( { error: 'Invalid email format' }, { status: 400 } ) } // Only allow sending to the authenticated user's email if (userEmail.toLowerCase() !== auth.profile.email?.toLowerCase()) { return NextResponse.json( { error: 'Can only send to your own email' }, { status: 403 } ) } // Fetch build data with components const { data: buildData, error: buildError } = await supabase .from('builds') .select(` build_id, build_name, total_price, date_created, build_types(type_name), users(email, user_name), build_components( components( component_id, component_name, component_price, component_categories(category_name), retailers( retailer_name, retailer_address, retailer_phone, email ) ) ) `) .eq('build_id', buildId) .single() if (buildError || !buildData) { return NextResponse.json( { error: 'Build not found' }, { status: 404 } ) } // Verify that the email matches the build owner's email const buildOwnerEmail = (buildData.users as any)?.email if (buildOwnerEmail !== userEmail) { return NextResponse.json( { error: 'Email does not match the build owner. For security, purchase details can only be sent to the verified email address.' }, { status: 403 } ) } // Prepare email content const components = (buildData.build_components as any[]).map((bc: any) => bc.components) const buildName = buildData.build_name const totalPrice = buildData.total_price const buildType = (buildData.build_types as any)?.type_name || 'Custom' const userName = (buildData.users as any)?.user_name || 'User' // Collect unique retailers with their components const retailerMap = new Map() const CENTRAL_JUAN_EMAIL = 'dummy.dumm.acc001@gmail.com' components.forEach((component: any) => { const retailer = component.retailers // Always send to Central Juan Solution email for all purchases if (!retailerMap.has(CENTRAL_JUAN_EMAIL)) { retailerMap.set(CENTRAL_JUAN_EMAIL, { retailer: { retailer_name: 'Central Juan Solution', email: CENTRAL_JUAN_EMAIL, retailer_address: null, retailer_phone: null }, components: [] }) } retailerMap.get(CENTRAL_JUAN_EMAIL)!.components.push(component) // Also send to retailer's email if they have one (for backward compatibility) if (retailer && retailer.email && retailer.email.trim().toLowerCase() !== CENTRAL_JUAN_EMAIL) { const retailerEmail = retailer.email.trim().toLowerCase() if (!retailerMap.has(retailerEmail)) { retailerMap.set(retailerEmail, { retailer, components: [] }) } retailerMap.get(retailerEmail)!.components.push(component) } }) console.log(`📧 Found ${retailerMap.size} retailer(s) with email addresses to notify`) if (retailerMap.size > 0) { retailerMap.forEach(({ retailer }, email) => { console.log(` - ${retailer.retailer_name}: ${email} (${retailerMap.get(email)!.components.length} component(s))`) }) } // Create HTML email content const emailHtml = ` Purchase Details - ${buildName}

BUILDMATE

Purchase Details

Hello ${userName},

Thank you for using BUILDMATE! Here are the purchase details for your build: ${buildName}

Build Information

Build Name: ${buildName}

Build Type: ${buildType}

Total Price: ₱${totalPrice.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}

Date Created: ${new Date(buildData.date_created).toLocaleDateString()}

Components (${components.length})

${components.map((component: any, index: number) => { const category = component.component_categories?.category_name || 'Unknown' const retailer = component.retailers return `

${component.component_name}

Category: ${category}

Price: ₱${component.component_price.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}

${retailer ? `

Retailer: ${retailer.retailer_name}

${retailer.retailer_address ? `

Address: ${retailer.retailer_address}

` : ''} ${retailer.retailer_phone ? `

Phone: ${retailer.retailer_phone}

` : ''} ${retailer.email ? `

Email: ${retailer.email}

` : ''}
` : ''}
` }).join('')}

Security Notice: This email was sent to your verified email address (${userEmail}) for security purposes. Please keep this information confidential.

This is an automated email from BUILDMATE. Please do not reply to this email.

© ${new Date().getFullYear()} BUILDMATE. All rights reserved.

` // Send email to user using Nodemailer with Supabase SMTP let transporter try { transporter = createTransporter() } catch (transporterError: any) { console.error('❌ SMTP configuration error:', transporterError.message) if (process.env.NODE_ENV === 'development') { return NextResponse.json({ success: false, error: transporterError.message, message: 'Please configure SMTP in .env.local' }) } return NextResponse.json( { error: 'Email service not configured. Please configure SMTP settings.' }, { status: 500 } ) } if (!transporter) { return NextResponse.json( { error: 'Email service not configured. Please configure SMTP settings.' }, { status: 500 } ) } // Parse from email const fromEmailRaw = process.env.SMTP_FROM_EMAIL || 'noreply@buildmate.com' const fromName = process.env.SMTP_FROM_NAME || 'BUILDMATE' const fromEmail = fromEmailRaw.includes('<') ? fromEmailRaw.match(/<(.+)>/)?.[1] || fromEmailRaw : fromEmailRaw const emailResults = { userEmailSent: false, retailerEmailsSent: 0, retailerEmailsFailed: 0, errors: [] as string[] } // Send email to user try { await transporter.verify() console.log('✅ SMTP connection verified') const userMailOptions = { from: `${fromName} <${fromEmail}>`, to: userEmail, subject: `Purchase Details - ${buildName}`, html: emailHtml, } const userEmailInfo = await transporter.sendMail(userMailOptions) console.log('✅ Purchase details email sent to user:', userEmailInfo.messageId) emailResults.userEmailSent = true } catch (userEmailError: any) { console.error('❌ Error sending email to user:', userEmailError) emailResults.errors.push(`Failed to send email to user: ${userEmailError.message}`) } // Send emails to retailers console.log(`📧 Starting to send emails to ${retailerMap.size} retailer(s)...`) const retailerEmailPromises = Array.from(retailerMap.entries()).map(async ([retailerEmail, { retailer, components: retailerComponents }]) => { try { // Create retailer-specific email content const retailerEmailHtml = ` New Purchase Order - ${buildName}

BUILDMATE

New Purchase Order

Hello ${retailer.retailer_name},

A customer has created a build that includes components from your store. Here are the details:

Customer Information

Customer Name: ${userName}

Build Name: ${buildName}

Build Type: ${buildType}

Date Created: ${new Date(buildData.date_created).toLocaleDateString()}

Components from Your Store (${retailerComponents.length})

${retailerComponents.map((component: any, index: number) => { const category = component.component_categories?.category_name || 'Unknown' const componentTotal = retailerComponents.reduce((sum: number, c: any) => sum + (parseFloat(c.component_price) || 0), 0) return `

${component.component_name}

Category: ${category}

Price: ₱${component.component_price.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}

` }).join('')}

Subtotal: ₱${retailerComponents.reduce((sum: number, c: any) => sum + (parseFloat(c.component_price) || 0), 0).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}

Next Steps: Please prepare the components listed above. The customer will be notified once the order is ready for pickup or delivery.

Contact Customer

You can send a message to the customer by replying to this email. Your reply will be forwarded to the customer.

To send a message:

  • Simply reply to this email
  • Your message will be sent to: ${userEmail}
  • The customer can reply directly to continue the conversation
Reply via Email

Or simply reply to this email to send a message to the customer.

This is an automated email from BUILDMATE. You can contact the customer using the form above.

© ${new Date().getFullYear()} BUILDMATE. All rights reserved.

` const retailerMailOptions = { from: `${fromName} <${fromEmail}>`, to: retailerEmail, subject: `New Purchase Order - ${buildName} (${retailerComponents.length} items)`, html: retailerEmailHtml, } const retailerEmailInfo = await transporter.sendMail(retailerMailOptions) console.log(`✅ Purchase order email sent to retailer ${retailer.retailer_name}:`, retailerEmailInfo.messageId) emailResults.retailerEmailsSent++ return { success: true, retailer: retailer.retailer_name } } catch (retailerEmailError: any) { console.error(`❌ Error sending email to retailer ${retailer.retailer_name}:`, retailerEmailError) emailResults.retailerEmailsFailed++ emailResults.errors.push(`Failed to send email to ${retailer.retailer_name}: ${retailerEmailError.message}`) return { success: false, retailer: retailer.retailer_name, error: retailerEmailError.message } } }) // Wait for all retailer emails to be sent await Promise.all(retailerEmailPromises) // Return response if (emailResults.userEmailSent && emailResults.retailerEmailsSent > 0) { return NextResponse.json({ success: true, message: `Purchase details sent to your email and ${emailResults.retailerEmailsSent} retailer(s)`, userEmailSent: emailResults.userEmailSent, retailerEmailsSent: emailResults.retailerEmailsSent, retailerEmailsFailed: emailResults.retailerEmailsFailed, errors: emailResults.errors.length > 0 ? emailResults.errors : undefined }) } else if (emailResults.userEmailSent) { return NextResponse.json({ success: true, message: 'Purchase details sent to your email. No retailer emails were sent (retailers may not have email addresses).', userEmailSent: emailResults.userEmailSent, retailerEmailsSent: emailResults.retailerEmailsSent, warnings: emailResults.errors }) } else { return NextResponse.json( { success: false, error: 'Failed to send purchase details email', details: emailResults.errors }, { status: 500 } ) } } catch (error: any) { console.error('Send purchase email error:', error) return NextResponse.json( { error: error.message || 'Internal server error' }, { status: 500 } ) } }