import { Controller, Post, Get, Body, Query, Req, UseGuards, RawBodyRequest, BadRequestException, Request, } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger'; import { Throttle } from '@nestjs/throttler'; import { Request as ExpressRequest } from 'express'; import { BillingService } from './billing.service'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; @ApiTags('billing') @Controller() export class BillingController { constructor(private billingService: BillingService) {} @Post('billing/create-checkout-session') @ApiOperation({ summary: 'Create a Stripe Checkout Session' }) @Throttle({ default: { limit: 10, ttl: 60000 } }) async createCheckout( @Body() body: { planId: string; email?: string; businessName?: string }, ) { if (!body.planId) throw new BadRequestException('planId is required'); return this.billingService.createCheckoutSession(body.planId, body.email, body.businessName); } @Post('webhooks/stripe') @ApiOperation({ summary: 'Stripe webhook endpoint' }) async handleWebhook(@Req() req: RawBodyRequest) { const signature = req.headers['stripe-signature'] as string; if (!signature) throw new BadRequestException('Missing Stripe signature'); if (!req.rawBody) throw new BadRequestException('Missing raw body'); await this.billingService.handleWebhook(req.rawBody, signature); return { received: true }; } @Get('billing/status') @ApiOperation({ summary: 'Check provisioning status for a checkout session' }) async getStatus(@Query('session_id') sessionId: string) { if (!sessionId) throw new BadRequestException('session_id required'); return this.billingService.getProvisioningStatus(sessionId); } @Post('billing/portal') @ApiOperation({ summary: 'Create Stripe Customer Portal session' }) @ApiBearerAuth() @UseGuards(JwtAuthGuard) async createPortal(@Request() req: any) { // Lookup the org's stripe_customer_id // Only allow president or superadmin const orgId = req.user.orgId; if (!orgId) throw new BadRequestException('No organization context'); // For now, we'd look this up from the org throw new BadRequestException('Portal session requires stripe_customer_id lookup — implement per org context'); } }