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 { DeveloperRequest, IDeveloperRequest } from '@/models/developer-request' import { Transaction } from '@/models/transaction' import BillingService from '@/lib/billing-service' import { checkServiceAvailability } from '@/lib/system-settings' // Schema for developer hire request const HireDeveloperSchema = z.object({ planId: z.enum(['hourly', 'daily', 'monthly']), planName: z.string().min(1), planPrice: z.number().positive(), requirements: z.string().min(10, 'Requirements must be at least 10 characters').max(5000), contactInfo: z.object({ name: z.string().min(1, 'Name is required'), email: z.string().email('Valid email is required'), phone: z.string().optional(), }), }) // Schema for response const HireDeveloperResponseSchema = z.object({ success: z.boolean(), data: z .object({ requestId: z.string(), transactionId: z.string(), status: z.string(), message: z.string(), estimatedResponse: z.string(), }) .optional(), error: z .object({ message: z.string(), code: z.string(), }) .optional(), }) export async function POST(request: NextRequest) { try { // Check if developer hire service is enabled if (!(await checkServiceAvailability('developer'))) { return NextResponse.json( { success: false, error: { message: 'Developer hire service is currently disabled by administrator', code: 'SERVICE_DISABLED', }, }, { status: 503 } ) } // 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 = HireDeveloperSchema.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 (minimum deposit required) const minimumDeposit = Math.min(validatedData.planPrice * 0.5, 10000) // 50% or max ₹10,000 if (currentBalance < minimumDeposit) { return NextResponse.json( { success: false, error: { message: `Insufficient balance. Minimum deposit required: ₹${minimumDeposit}, Available: ₹${currentBalance}`, code: 'INSUFFICIENT_BALANCE', }, }, { status: 400 } ) } // Create developer request first const developerRequest = new DeveloperRequest({ userId: userData._id, planId: validatedData.planId, planName: validatedData.planName, planPrice: validatedData.planPrice, requirements: validatedData.requirements, contactInfo: validatedData.contactInfo, status: 'pending', paymentStatus: 'pending', // Will be updated after billing transactionId: null, // Will be set after transaction is created }) // Save developer request first const savedRequest = await developerRequest.save() // Process billing using the new comprehensive billing service try { const billingResult = await BillingService.processServiceDeployment({ user: { id: user.id, email: user.email, siliconId: userData.siliconId, }, service: { name: `Developer Hire - ${validatedData.planName}`, type: 'developer_hire', id: savedRequest._id.toString(), config: { planId: validatedData.planId, planName: validatedData.planName, planPrice: validatedData.planPrice, requirements: validatedData.requirements, contactInfo: validatedData.contactInfo, }, }, amount: minimumDeposit, currency: 'INR', cycle: 'onetime', deploymentSuccess: true, // Developer hire request is always successful deploymentResponse: { requestId: savedRequest._id.toString() }, metadata: { userAgent: request.headers.get('user-agent'), ip: request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip'), depositAmount: minimumDeposit, fullPlanPrice: validatedData.planPrice, }, }) // Update developer request with billing info await (DeveloperRequest as any).updateOne( { _id: savedRequest._id }, { $set: { paymentStatus: 'paid', transactionId: billingResult.transaction?._id, }, } ) console.log('Developer hire billing processed:', { requestId: savedRequest._id, billingId: billingResult.billing.billing_id, transactionId: billingResult.transaction?.transactionId, }) } catch (billingError) { console.error('Billing processing failed:', billingError) // Rollback developer request if billing fails await (DeveloperRequest as any).deleteOne({ _id: savedRequest._id }) if (billingError instanceof Error && billingError.message.includes('Insufficient balance')) { return NextResponse.json( { success: false, error: { message: billingError.message, code: 'INSUFFICIENT_BALANCE', }, }, { status: 400 } ) } throw new Error('Failed to process payment') } const responseData = { success: true, data: { requestId: savedRequest._id.toString(), transactionId: 'processed_via_billing', status: 'pending', message: 'Your developer hire request has been submitted successfully! Our team will review your requirements and contact you within 24 hours.', estimatedResponse: '24 hours', }, } const validatedResponse = HireDeveloperResponseSchema.parse(responseData) return NextResponse.json(validatedResponse, { status: 200 }) } catch (error) { console.error('Developer hire 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 process developer hire request', code: 'INTERNAL_ERROR' }, }, { status: 500 } ) } } // GET endpoint to fetch user's developer requests export async function GET(request: NextRequest) { try { const user = await authMiddleware(request) if (!user) { return NextResponse.json( { success: false, error: { message: 'Authentication required', code: 'UNAUTHORIZED' }, }, { status: 401 } ) } await connectDB() 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 } ) } // Get user's developer requests const requests = await (DeveloperRequest as any) .find({ userId: userData._id }) .sort({ createdAt: -1 }) .populate('transactionId') .lean() return NextResponse.json({ success: true, data: { requests, total: requests.length, }, }) } catch (error) { console.error('Failed to fetch developer requests:', error) return NextResponse.json( { success: false, error: { message: 'Failed to fetch requests', code: 'INTERNAL_ERROR' }, }, { status: 500 } ) } }