import { NextRequest, NextResponse } from 'next/server' import { supabase } from '@/lib/supabase' import nodemailer from 'nodemailer' // API route configuration - dynamic for POST requests export const dynamic = 'force-dynamic' export const runtime = 'nodejs' // Initialize nodemailer transporter 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' // Check for placeholders if (smtpHost === 'your_smtp_host' || smtpUser === 'your_smtp_user' || smtpPassword === 'your_smtp_password') { throw new Error('SMTP credentials in environment variables are still placeholders. Please configure them in Render/Vercel dashboard.') } if (!smtpHost || !smtpUser || !smtpPassword) { console.error('❌ SMTP Configuration Missing:') console.error(' SMTP_HOST:', smtpHost ? '✅ Set' : '❌ Missing') console.error(' SMTP_USER:', smtpUser ? '✅ Set' : '❌ Missing') console.error(' SMTP_PASSWORD:', smtpPassword ? '✅ Set' : '❌ Missing') throw new Error('SMTP credentials are missing in environment variables. Please configure SMTP_HOST, SMTP_USER, and SMTP_PASSWORD in Render/Vercel dashboard.') } console.log('📧 SMTP Configuration:') console.log(' Host:', smtpHost) console.log(' Port:', smtpPort) console.log(' User:', smtpUser) console.log(' From:', smtpFromEmail) return nodemailer.createTransport({ host: smtpHost, port: smtpPort, secure: smtpPort === 465, auth: { user: smtpUser, pass: smtpPassword, }, }) } export async function POST(request: NextRequest) { try { const { email, userId } = await request.json() if (!email || !userId) { return NextResponse.json( { error: 'Email and user ID are required' }, { status: 400 } ) } // Validate email format const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ if (!emailRegex.test(email)) { return NextResponse.json( { error: 'Invalid email format' }, { status: 400 } ) } // Check if user exists (verify by user_id and email match) const { data: user, error: userError } = await supabase .from('users') .select('email, user_name, user_id') .eq('user_id', userId) .eq('email', email.trim().toLowerCase()) .single() if (userError || !user) { return NextResponse.json( { error: 'User not found or email mismatch' }, { status: 404 } ) } // Check if there's an existing code that hasn't expired yet const emailKey = email.trim().toLowerCase() const { data: existingCode, error: existingError } = await supabase .from('login_verification_codes') .select('*') .eq('email', emailKey) .maybeSingle() if (!existingError && existingCode && existingCode.expires_at > Date.now()) { const timeRemaining = Math.ceil( (existingCode.expires_at - Date.now()) / 1000 / 60 ) return NextResponse.json({ success: true, message: `A verification code was already sent. Please check your email. The code expires in ${timeRemaining} minute(s).`, codeAlreadySent: true }) } // Generate 6-digit verification code const code = Math.floor(100000 + Math.random() * 900000).toString() const expiresAt = Date.now() + 5 * 60 * 1000 // 5 minutes // Store code with email as key await supabase .from('login_verification_codes') .delete() .eq('email', email.trim().toLowerCase()) await supabase .from('login_verification_codes') .insert({ email: email.trim().toLowerCase(), code, expires_at: expiresAt, verified: false }) console.log(`✅ New login verification code generated for ${email}, expires at ${new Date(expiresAt).toISOString()}`) // Send email with verification code let transporter try { transporter = createTransporter() } catch (transporterError: any) { console.error('❌ SMTP configuration error:', transporterError.message) return NextResponse.json( { error: 'Email service not configured' }, { status: 500 } ) } 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 emailHtml = ` Login Verification Code

BUILDMATE

Login Verification Code

Hello ${user.user_name},

You've requested to login to your BUILDMATE account. Please use the verification code below:

${code}

This code will expire in 5 minutes

Security Notice: If you didn't request this code, please ignore this email or contact support if you're concerned about your account security.

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

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

` try { // Verify SMTP connection first await transporter.verify() console.log('✅ SMTP connection verified') const emailInfo = await transporter.sendMail({ from: `${fromName} <${fromEmail}>`, to: email.trim().toLowerCase(), subject: `BUILDMATE Login Verification Code: ${code}`, html: emailHtml, }) console.log('✅ Login verification code sent to:', email.trim().toLowerCase()) console.log(' Message ID:', emailInfo.messageId) return NextResponse.json({ success: true, message: 'Verification code sent to your email' }) } catch (emailError: any) { console.error('❌ Error sending login verification email:', emailError) console.error(' Error details:', { code: emailError.code, command: emailError.command, response: emailError.response, responseCode: emailError.responseCode }) // Provide more helpful error messages let errorMessage = 'Failed to send verification code email' if (emailError.code === 'EAUTH') { errorMessage = 'SMTP authentication failed. Please check SMTP_USER and SMTP_PASSWORD in environment variables.' } else if (emailError.code === 'ECONNECTION') { errorMessage = 'Cannot connect to SMTP server. Please check SMTP_HOST and SMTP_PORT in environment variables.' } else if (emailError.message) { errorMessage = `Email sending failed: ${emailError.message}` } return NextResponse.json( { error: errorMessage }, { status: 500 } ) } } catch (error: any) { console.error('Send login verification code error:', error) return NextResponse.json( { error: error.message || 'Internal server error' }, { status: 500 } ) } }