import { NextRequest, NextResponse } from 'next/server' import { z } from 'zod' import { authMiddleware } from '@/lib/auth-middleware' import connectDB from '@/lib/mongodb' import { User as UserModel } from '@/models/user' import { Transaction } from '@/models/transaction' // Schema for balance deduction request const DeductBalanceSchema = z.object({ amount: z.number().positive('Amount must be positive'), service: z.string().min(1, 'Service name is required'), serviceId: z.string().optional(), description: z.string().optional(), transactionId: z.string().optional(), }) // Schema for balance deduction response const DeductBalanceResponseSchema = z.object({ success: z.boolean(), data: z .object({ transactionId: z.string(), previousBalance: z.number(), newBalance: z.number(), amountDeducted: z.number(), service: z.string(), timestamp: z.string(), }) .optional(), error: z .object({ message: z.string(), code: z.string(), }) .optional(), }) export async function POST(request: NextRequest) { try { // Authenticate user const user = await authMiddleware(request) if (!user) { return NextResponse.json( { success: false, error: { message: 'Authentication required', code: 'UNAUTHORIZED' }, }, { status: 401 } ) } await connectDB() // Parse and validate request body const body = await request.json() const validatedData = DeductBalanceSchema.parse(body) // Get user's current balance from database const userData = await UserModel.findOne({ email: user.email }) if (!userData) { return NextResponse.json( { success: false, error: { message: 'User not found', code: 'USER_NOT_FOUND' }, }, { status: 404 } ) } const currentBalance = userData.balance || 0 // Check if user has sufficient balance if (currentBalance < validatedData.amount) { return NextResponse.json( { success: false, error: { message: `Insufficient balance. Required: ₹${validatedData.amount}, Available: ₹${currentBalance}`, code: 'INSUFFICIENT_BALANCE', }, }, { status: 400 } ) } // Calculate new balance const newBalance = currentBalance - validatedData.amount // Update user balance in database await UserModel.updateOne( { email: user.email }, { $set: { balance: newBalance }, $inc: { __v: 1 }, // Increment version for optimistic locking } ) // Generate transaction ID if not provided const transactionId = validatedData.transactionId || `txn_${Date.now()}_${Math.random().toString(36).substr(2, 9)}` // Save transaction record to database try { const newTransaction = new Transaction({ transactionId, userId: user.id, email: user.email, type: 'debit', amount: validatedData.amount, service: validatedData.service, serviceId: validatedData.serviceId, description: validatedData.description || `Payment for ${validatedData.service}`, status: 'completed', previousBalance: currentBalance, newBalance, metadata: { userAgent: request.headers.get('user-agent'), ip: request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip'), }, }) await newTransaction.save() console.log('Transaction record saved:', transactionId) } catch (transactionError) { console.error('Failed to save transaction record:', transactionError) // Continue even if transaction record fails - balance was already deducted } const responseData = { success: true, data: { transactionId, previousBalance: currentBalance, newBalance, amountDeducted: validatedData.amount, service: validatedData.service, timestamp: new Date().toISOString(), }, } // Validate response format const validatedResponse = DeductBalanceResponseSchema.parse(responseData) return NextResponse.json(validatedResponse, { status: 200 }) } catch (error) { console.error('Balance deduction error:', error) if (error instanceof z.ZodError) { return NextResponse.json( { success: false, error: { message: 'Invalid request data', code: 'VALIDATION_ERROR', details: error.issues, }, }, { status: 400 } ) } return NextResponse.json( { success: false, error: { message: 'Failed to deduct balance', code: 'INTERNAL_ERROR' }, }, { status: 500 } ) } }