import { NextRequest, NextResponse } from 'next/server' import { authMiddleware } from '@/lib/auth-middleware' import connectDB from '@/lib/mongodb' import { User as UserModel } from '@/models/user' import BillingService from '@/lib/billing-service' import { checkServiceAvailability } from '@/lib/system-settings' // VPC subnet mapping based on datacenter const VPC_SUBNET_MAP: { [key: string]: string } = { inmumbaizone2: '3889f7ca-ca19-4851-abc7-5c6b4798b3fe', // Mumbai public subnet inbangalore: 'c17032c9-3cfd-4028-8f2a-f3f5aa8c2976', // Bangalore public subnet innoida: '95c60b59-4925-4b7e-bd05-afbf940d8000', // Delhi/Noida public subnet defra1: '72ea201d-e1e7-4d30-a186-bc709efafad8', // Frankfurt public subnet uslosangeles: '0e253cd1-8ecc-4b65-ae0f-6acbc53b0fb6', // Los Angeles public subnet inbangalore3: 'f687a58b-04f0-4ebe-b583-65788a1d18bf', // Bangalore DC3 public subnet } export async function POST(request: NextRequest) { try { // Check if VPS deployment service is enabled if (!(await checkServiceAvailability('vps'))) { return NextResponse.json( { status: 'error', message: 'VPS deployment service is currently disabled by administrator', }, { status: 503 } ) } // Check authentication using your auth middleware const user = await authMiddleware(request) if (!user) { return NextResponse.json( { status: 'error', message: 'Unauthorized: Please login to continue' }, { status: 401 } ) } // Get input data from request const input = await request.json() if (!input) { return NextResponse.json({ status: 'error', message: 'Invalid JSON' }, { status: 400 }) } // Get API key from environment const UTHO_API_KEY = process.env.UTHO_API_KEY if (!UTHO_API_KEY) { return NextResponse.json( { status: 'error', message: 'API configuration missing' }, { status: 500 } ) } // Connect to MongoDB await connectDB() // Get user data for billing const userData = await UserModel.findOne({ email: user.email }) if (!userData) { return NextResponse.json({ status: 'error', message: 'User not found' }, { status: 404 }) } const requiredAmount = input.amount || 0 // Check balance only if amount > 0 (some services might be free) if (requiredAmount > 0) { const currentBalance = userData.balance || 0 if (currentBalance < requiredAmount) { return NextResponse.json( { status: 'error', message: `Insufficient balance. Required: ₹${requiredAmount}, Available: ₹${currentBalance}`, code: 'INSUFFICIENT_BALANCE', }, { status: 400 } ) } } // Get VPC subnet based on datacenter const vpcSubnet = VPC_SUBNET_MAP[input.dclocation] || VPC_SUBNET_MAP['inbangalore'] // Prepare Utho payload - use the exact format from your PHP code const uthoPayload = { dcslug: input.dclocation, planid: input.planid, billingcycle: 'hourly', auth: 'option2', enable_publicip: input.publicip !== false, subnetRequired: false, firewall: '23434645', cpumodel: 'intel', enablebackup: input.backup || false, root_password: input.password, support: 'unmanaged', vpc: vpcSubnet, cloud: [ { hostname: input.hostname, }, ], image: input.image, sshkeys: '', } console.log('Sending to Utho API:', uthoPayload) // Make API request to Utho const UTHO_API_URL = 'https://api.utho.com/v2/cloud/deploy' const response = await fetch(UTHO_API_URL, { method: 'POST', headers: { Authorization: `Bearer ${UTHO_API_KEY}`, 'Content-Type': 'application/json', Accept: '*/*', }, body: JSON.stringify(uthoPayload), }) const httpCode = response.status const deploymentSuccess = httpCode >= 200 && httpCode < 300 const responseData = await response.json() // Add status field like PHP does responseData.status = deploymentSuccess ? 'success' : 'error' console.log('Utho API response:', { httpCode, responseData }) // 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: 'VPS Server', type: 'vps', id: responseData.server_id || responseData.id, instanceId: responseData.server_id || responseData.id, config: { hostname: input.hostname, planid: input.planid, dclocation: input.dclocation, image: input.image, backup: input.backup, publicip: input.publicip, }, }, amount: requiredAmount, currency: 'INR', cycle: (input.cycle as any) || 'onetime', deploymentSuccess, deploymentResponse: responseData, metadata: { userAgent: request.headers.get('user-agent'), ip: request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip'), uthoPayload, httpCode, }, }) console.log('Billing processed:', { billingId: billingResult.billing.billing_id, transactionId: billingResult.transaction?.transactionId, balanceUpdated: billingResult.balanceUpdated, }) } catch (billingError) { console.error('Billing processing failed:', billingError) // Continue even if billing fails, but return error if it's balance-related if (billingError instanceof Error && billingError.message.includes('Insufficient balance')) { return NextResponse.json( { status: 'error', message: billingError.message, code: 'INSUFFICIENT_BALANCE', }, { status: 400 } ) } } // Return the exact same response format as PHP return NextResponse.json(responseData, { status: httpCode }) } catch (error) { console.error('Cloud deployment error:', error) return NextResponse.json( { status: 'error', message: 'Internal server error', details: error instanceof Error ? error.message : 'Unknown error', }, { status: 500 } ) } }