ai-wpa/app/api/admin/reports/route.ts

188 lines
6.6 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import { withAdminAuth } from '@/lib/admin-middleware'
import { connectDB } from '@/lib/mongodb'
import { User } from '@/models/user'
import { Transaction } from '@/models/transaction'
import { Billing } from '@/models/billing'
import { DeveloperRequest } from '@/models/developer-request'
export async function GET(request: NextRequest) {
return withAdminAuth(request, async (req, admin) => {
try {
await connectDB()
const { searchParams } = new URL(request.url)
const reportType = searchParams.get('type')
const format = searchParams.get('format') || 'json'
const dateFrom = searchParams.get('dateFrom')
const dateTo = searchParams.get('dateTo')
// Build date filter
const dateFilter: any = {}
if (dateFrom || dateTo) {
dateFilter.createdAt = {}
if (dateFrom) dateFilter.createdAt.$gte = new Date(dateFrom)
if (dateTo) dateFilter.createdAt.$lte = new Date(dateTo)
}
let data: any = {}
switch (reportType) {
case 'users':
data = await User.find(dateFilter)
.select('-password -refreshToken')
.sort({ createdAt: -1 })
break
case 'transactions':
data = await Transaction.find(dateFilter)
.populate('userId', 'name email siliconId')
.sort({ createdAt: -1 })
break
case 'billing':
data = await Billing.find(
dateFilter.createdAt ? { created_at: dateFilter.createdAt } : {}
).sort({ created_at: -1 })
break
case 'developer-requests':
const devFilter = dateFilter.createdAt ? { createdAt: dateFilter.createdAt } : {}
data = await (DeveloperRequest as any)
.find(devFilter)
.populate('userId', 'name email siliconId')
.sort({ createdAt: -1 })
break
case 'summary':
// Generate comprehensive summary report
const [users, transactions, billings, developerRequests] = await Promise.all([
User.find(dateFilter).select('-password -refreshToken'),
Transaction.find(dateFilter).populate('userId', 'name email siliconId'),
Billing.find(dateFilter.createdAt ? { created_at: dateFilter.createdAt } : {}),
(DeveloperRequest as any)
.find(dateFilter.createdAt ? { createdAt: dateFilter.createdAt } : {})
.populate('userId', 'name email siliconId'),
])
// Calculate summary statistics
const userStats = {
total: users.length,
verified: users.filter((u) => u.isVerified).length,
admins: users.filter((u) => u.role === 'admin').length,
totalBalance: users.reduce((sum, u) => sum + (u.balance || 0), 0),
}
const transactionStats = {
total: transactions.length,
totalAmount: transactions.reduce((sum, t) => sum + t.amount, 0),
credits: transactions.filter((t) => t.type === 'credit').length,
debits: transactions.filter((t) => t.type === 'debit').length,
}
const billingStats = {
total: billings.length,
totalRevenue: billings.reduce((sum, b) => sum + b.amount, 0),
completed: billings.filter((b) => b.payment_status === 'paid').length,
pending: billings.filter((b) => b.payment_status === 'pending').length,
}
const developerStats = {
total: developerRequests.length,
pending: developerRequests.filter((d) => d.status === 'pending').length,
inProgress: developerRequests.filter((d) => d.status === 'in_progress').length,
completed: developerRequests.filter((d) => d.status === 'completed').length,
}
data = {
summary: {
users: userStats,
transactions: transactionStats,
billing: billingStats,
developerRequests: developerStats,
},
users: users.slice(0, 100), // Limit for performance
transactions: transactions.slice(0, 100),
billings: billings.slice(0, 100),
developerRequests: developerRequests.slice(0, 100),
}
break
default:
return NextResponse.json({ error: 'Invalid report type' }, { status: 400 })
}
if (format === 'csv') {
// Convert to CSV format
const csv = convertToCSV(data, reportType)
return new NextResponse(csv, {
headers: {
'Content-Type': 'text/csv',
'Content-Disposition': `attachment; filename="${reportType}_report_${new Date().toISOString().split('T')[0]}.csv"`,
},
})
}
return NextResponse.json({
reportType,
generatedAt: new Date().toISOString(),
generatedBy: admin.name,
dateRange: { from: dateFrom, to: dateTo },
data,
})
} catch (error) {
console.error('Admin reports error:', error)
return NextResponse.json({ error: 'Failed to generate report' }, { status: 500 })
}
})
}
function convertToCSV(data: any, reportType: string): string {
if (!Array.isArray(data)) {
if (reportType === 'summary' && data.summary) {
// For summary reports, create a simple CSV with key metrics
const lines = [
'Metric,Value',
`Total Users,${data.summary.users.total}`,
`Verified Users,${data.summary.users.verified}`,
`Admin Users,${data.summary.users.admins}`,
`Total Balance,${data.summary.users.totalBalance}`,
`Total Transactions,${data.summary.transactions.total}`,
`Transaction Amount,${data.summary.transactions.totalAmount}`,
`Total Billing Records,${data.summary.billing.total}`,
`Total Revenue,${data.summary.billing.totalRevenue}`,
`Developer Requests,${data.summary.developerRequests.total}`,
]
return lines.join('\n')
}
return 'No data available'
}
if (data.length === 0) {
return 'No data available'
}
// Get headers from first object
const headers = Object.keys(data[0]).filter(
(key) => typeof data[0][key] !== 'object' || data[0][key] === null
)
// Create CSV content
const csvHeaders = headers.join(',')
const csvRows = data.map((row) =>
headers
.map((header) => {
const value = row[header]
if (value === null || value === undefined) return ''
if (typeof value === 'string' && value.includes(',')) {
return `"${value.replace(/"/g, '""')}"`
}
return value
})
.join(',')
)
return [csvHeaders, ...csvRows].join('\n')
}