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' // Hardcoded VPC as requested const K8S_VPC = '81b2bd94-61dc-424b-a1ca-ca4c810ed4c4' export async function POST(request: NextRequest) { try { // Check authentication 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 }) } // Validate required fields if (!input.cluster_label || !input.nodepools) { return NextResponse.json( { status: 'error', message: 'Cluster label and nodepools are required' }, { 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 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 } ) } } // Prepare Utho payload for Kubernetes const uthoPayload = { dcslug: 'inmumbaizone2', // Hardcoded as requested cluster_label: input.cluster_label, cluster_version: input.cluster_version || '1.30.0-utho', nodepools: input.nodepools, vpc: K8S_VPC, // Hardcoded VPC network_type: 'publicprivate', cpumodel: 'amd', } console.log('Sending to Utho Kubernetes API:', uthoPayload) // Make API request to Utho Kubernetes const UTHO_API_URL = 'https://api.utho.com/v2/kubernetes/deploy' const response = await fetch(UTHO_API_URL, { method: 'POST', headers: { Authorization: `Bearer ${UTHO_API_KEY}`, 'Content-Type': 'application/json', Accept: 'application/json', }, body: JSON.stringify(uthoPayload), }) const httpCode = response.status const deploymentSuccess = httpCode >= 200 && httpCode < 300 const responseData = await response.json() // Add status field and clusterId for consistency responseData.status = deploymentSuccess ? 'success' : 'error' if (deploymentSuccess && responseData.id) { responseData.clusterId = responseData.id } console.log('Utho Kubernetes 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: `Kubernetes Cluster - ${input.cluster_label}`, type: 'kubernetes', id: responseData.clusterId || responseData.id, clusterId: responseData.clusterId || responseData.id, config: { cluster_label: input.cluster_label, cluster_version: input.cluster_version, nodepools: input.nodepools, dcslug: 'inmumbaizone2', vpc: K8S_VPC, network_type: 'publicprivate', cpumodel: 'amd', }, }, 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 NextResponse.json(responseData, { status: httpCode }) } catch (error) { console.error('Kubernetes deployment error:', error) return NextResponse.json( { status: 'error', message: 'Internal server error', details: error instanceof Error ? error.message : 'Unknown error', }, { status: 500 } ) } } // GET endpoint for downloading kubeconfig export async function GET(request: NextRequest) { try { // Check authentication const user = await authMiddleware(request) if (!user) { return NextResponse.json( { status: 'error', message: 'Unauthorized: Please login to continue' }, { status: 401 } ) } const { searchParams } = new URL(request.url) const clusterId = searchParams.get('clusterId') if (!clusterId) { return NextResponse.json( { status: 'error', message: 'Cluster ID is required' }, { 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 } ) } // Download kubeconfig const KUBECONFIG_URL = `https://api.utho.com/v2/kubernetes/${clusterId}/download` const response = await fetch(KUBECONFIG_URL, { headers: { Authorization: `Bearer ${UTHO_API_KEY}`, Accept: 'application/yaml', }, }) if (response.ok) { const kubeconfig = await response.text() // Return as downloadable file return new NextResponse(kubeconfig, { status: 200, headers: { 'Content-Type': 'application/yaml', 'Content-Disposition': `attachment; filename="kubeconfig-${clusterId}.yaml"`, }, }) } else { const errorText = await response.text() console.error('Kubeconfig download failed:', response.status, errorText) return NextResponse.json( { status: 'error', message: 'Failed to download kubeconfig' }, { status: response.status } ) } } catch (error) { console.error('Kubeconfig download error:', error) return NextResponse.json( { status: 'error', message: 'Internal server error', details: error instanceof Error ? error.message : 'Unknown error', }, { status: 500 } ) } }