/** * Investment Controller * Handles investment-related endpoints */ import { Request, Response, NextFunction } from 'express'; import { productService, RiskProfile } from '../services/product.service'; import { accountService, CreateAccountInput } from '../services/account.service'; import { transactionService, TransactionType, TransactionStatus, WithdrawalStatus, } from '../services/transaction.service'; // ============================================================================ // Types // ============================================================================ // Use Request directly - user is already declared globally in auth.middleware.ts type AuthRequest = Request; // ============================================================================ // Product Controllers // ============================================================================ /** * Get all investment products */ export async function getProducts(req: Request, res: Response, next: NextFunction): Promise { try { const { riskProfile } = req.query; let products; if (riskProfile) { products = await productService.getProductsByRiskProfile(riskProfile as RiskProfile); } else { products = await productService.getProducts(); } res.json({ success: true, data: products, }); } catch (error) { next(error); } } /** * Get product by ID */ export async function getProductById(req: Request, res: Response, next: NextFunction): Promise { try { const { productId } = req.params; const product = await productService.getProductById(productId); if (!product) { res.status(404).json({ success: false, error: { message: 'Product not found', code: 'NOT_FOUND' }, }); return; } // Get additional stats const stats = await productService.getProductStats(productId); res.json({ success: true, data: { ...product, stats }, }); } catch (error) { next(error); } } /** * Get product performance */ export async function getProductPerformance(req: Request, res: Response, next: NextFunction): Promise { try { const { productId } = req.params; const { period = 'month' } = req.query; const performance = await productService.getProductPerformance( productId, period as 'week' | 'month' | '3months' | 'year' ); res.json({ success: true, data: performance, }); } catch (error) { next(error); } } // ============================================================================ // Account Controllers // ============================================================================ /** * Get user accounts */ export async function getUserAccounts(req: AuthRequest, res: Response, next: NextFunction): Promise { try { const userId = req.user?.id; if (!userId) { res.status(401).json({ success: false, error: { message: 'Unauthorized', code: 'UNAUTHORIZED' }, }); return; } const accounts = await accountService.getUserAccounts(userId); res.json({ success: true, data: accounts, }); } catch (error) { next(error); } } /** * Get account summary */ export async function getAccountSummary(req: AuthRequest, res: Response, next: NextFunction): Promise { try { const userId = req.user?.id; if (!userId) { res.status(401).json({ success: false, error: { message: 'Unauthorized', code: 'UNAUTHORIZED' }, }); return; } const summary = await accountService.getAccountSummary(userId); res.json({ success: true, data: summary, }); } catch (error) { next(error); } } /** * Get account by ID */ export async function getAccountById(req: AuthRequest, res: Response, next: NextFunction): Promise { try { const userId = req.user?.id; if (!userId) { res.status(401).json({ success: false, error: { message: 'Unauthorized', code: 'UNAUTHORIZED' }, }); return; } const { accountId } = req.params; const account = await accountService.getAccountById(accountId); if (!account) { res.status(404).json({ success: false, error: { message: 'Account not found', code: 'NOT_FOUND' }, }); return; } if (account.userId !== userId) { res.status(403).json({ success: false, error: { message: 'Forbidden', code: 'FORBIDDEN' }, }); return; } // Get performance history const performance = await accountService.getAccountPerformance(accountId, 30); res.json({ success: true, data: { ...account, performance }, }); } catch (error) { next(error); } } /** * Create investment account */ export async function createAccount(req: AuthRequest, res: Response, next: NextFunction): Promise { try { const userId = req.user?.id; if (!userId) { res.status(401).json({ success: false, error: { message: 'Unauthorized', code: 'UNAUTHORIZED' }, }); return; } const { productId, initialDeposit } = req.body; if (!productId || !initialDeposit) { res.status(400).json({ success: false, error: { message: 'Product ID and initial deposit are required', code: 'VALIDATION_ERROR' }, }); return; } const input: CreateAccountInput = { userId, productId, initialDeposit: Number(initialDeposit), }; const account = await accountService.createAccount(input); res.status(201).json({ success: true, data: account, }); } catch (error) { next(error); } } /** * Close account */ export async function closeAccount(req: AuthRequest, res: Response, next: NextFunction): Promise { try { const userId = req.user?.id; if (!userId) { res.status(401).json({ success: false, error: { message: 'Unauthorized', code: 'UNAUTHORIZED' }, }); return; } const { accountId } = req.params; const account = await accountService.getAccountById(accountId); if (!account) { res.status(404).json({ success: false, error: { message: 'Account not found', code: 'NOT_FOUND' }, }); return; } if (account.userId !== userId) { res.status(403).json({ success: false, error: { message: 'Forbidden', code: 'FORBIDDEN' }, }); return; } const closedAccount = await accountService.closeAccount(accountId); res.json({ success: true, data: closedAccount, }); } catch (error) { next(error); } } // ============================================================================ // Transaction Controllers // ============================================================================ /** * Get account transactions */ export async function getTransactions(req: AuthRequest, res: Response, next: NextFunction): Promise { try { const userId = req.user?.id; if (!userId) { res.status(401).json({ success: false, error: { message: 'Unauthorized', code: 'UNAUTHORIZED' }, }); return; } const { accountId } = req.params; const { type, status, limit = 50, offset = 0 } = req.query; const account = await accountService.getAccountById(accountId); if (!account) { res.status(404).json({ success: false, error: { message: 'Account not found', code: 'NOT_FOUND' }, }); return; } if (account.userId !== userId) { res.status(403).json({ success: false, error: { message: 'Forbidden', code: 'FORBIDDEN' }, }); return; } const { transactions, total } = await transactionService.getAccountTransactions(accountId, { type: type as TransactionType | undefined, status: status as TransactionStatus | undefined, limit: Number(limit), offset: Number(offset), }); res.json({ success: true, data: transactions, pagination: { total, limit: Number(limit), offset: Number(offset), }, }); } catch (error) { next(error); } } /** * Create deposit */ export async function createDeposit(req: AuthRequest, res: Response, next: NextFunction): Promise { try { const userId = req.user?.id; if (!userId) { res.status(401).json({ success: false, error: { message: 'Unauthorized', code: 'UNAUTHORIZED' }, }); return; } const { accountId } = req.params; const { amount } = req.body; const account = await accountService.getAccountById(accountId); if (!account) { res.status(404).json({ success: false, error: { message: 'Account not found', code: 'NOT_FOUND' }, }); return; } if (account.userId !== userId) { res.status(403).json({ success: false, error: { message: 'Forbidden', code: 'FORBIDDEN' }, }); return; } if (!amount || amount <= 0) { res.status(400).json({ success: false, error: { message: 'Valid amount is required', code: 'VALIDATION_ERROR' }, }); return; } const transaction = await transactionService.createDeposit({ accountId, amount: Number(amount), }); res.status(201).json({ success: true, data: transaction, }); } catch (error) { next(error); } } /** * Create withdrawal request */ export async function createWithdrawal(req: AuthRequest, res: Response, next: NextFunction): Promise { try { const userId = req.user?.id; if (!userId) { res.status(401).json({ success: false, error: { message: 'Unauthorized', code: 'UNAUTHORIZED' }, }); return; } const { accountId } = req.params; const { amount, bankInfo, cryptoInfo } = req.body; const account = await accountService.getAccountById(accountId); if (!account) { res.status(404).json({ success: false, error: { message: 'Account not found', code: 'NOT_FOUND' }, }); return; } if (account.userId !== userId) { res.status(403).json({ success: false, error: { message: 'Forbidden', code: 'FORBIDDEN' }, }); return; } if (!amount || amount <= 0) { res.status(400).json({ success: false, error: { message: 'Valid amount is required', code: 'VALIDATION_ERROR' }, }); return; } const withdrawal = await transactionService.createWithdrawal(userId, { accountId, amount: Number(amount), bankInfo, cryptoInfo, }); res.status(201).json({ success: true, data: withdrawal, message: 'Withdrawal request submitted. Processing time: 72 hours.', }); } catch (error) { next(error); } } /** * Get user withdrawals */ export async function getWithdrawals(req: AuthRequest, res: Response, next: NextFunction): Promise { try { const userId = req.user?.id; if (!userId) { res.status(401).json({ success: false, error: { message: 'Unauthorized', code: 'UNAUTHORIZED' }, }); return; } const { status } = req.query; const withdrawals = await transactionService.getUserWithdrawals( userId, status as WithdrawalStatus | undefined ); res.json({ success: true, data: withdrawals, }); } catch (error) { next(error); } } /** * Get account distributions */ export async function getDistributions(req: AuthRequest, res: Response, next: NextFunction): Promise { try { const userId = req.user?.id; if (!userId) { res.status(401).json({ success: false, error: { message: 'Unauthorized', code: 'UNAUTHORIZED' }, }); return; } const { accountId } = req.params; const account = await accountService.getAccountById(accountId); if (!account) { res.status(404).json({ success: false, error: { message: 'Account not found', code: 'NOT_FOUND' }, }); return; } if (account.userId !== userId) { res.status(403).json({ success: false, error: { message: 'Forbidden', code: 'FORBIDDEN' }, }); return; } const distributions = await transactionService.getAccountDistributions(accountId); res.json({ success: true, data: distributions, }); } catch (error) { next(error); } }