import { Controller, Get, Post, Param, Query, Body, Request, ParseIntPipe, BadRequestException, UsePipes, } from "@nestjs/common"; import { SubscriptionsService } from "./subscriptions.service"; import { SimManagementService } from "./sim-management.service"; import { Subscription, SubscriptionList, InvoiceList, simTopupRequestSchema, simChangePlanRequestSchema, simCancelRequestSchema, simFeaturesRequestSchema, subscriptionQuerySchema, invoiceListQuerySchema, type SimTopupRequest, type SimChangePlanRequest, type SimCancelRequest, type SimFeaturesRequest, type SubscriptionQuery, type InvoiceListQuery, } from "@customer-portal/domain"; import { ZodValidationPipe } from "@bff/core/validation"; import type { RequestWithUser } from "@bff/modules/auth/auth.types"; @Controller("subscriptions") export class SubscriptionsController { constructor( private readonly subscriptionsService: SubscriptionsService, private readonly simManagementService: SimManagementService ) {} @Get() @UsePipes(new ZodValidationPipe(subscriptionQuerySchema)) async getSubscriptions( @Request() req: RequestWithUser, @Query() query: SubscriptionQuery ): Promise { if (query.status) { return this.subscriptionsService.getSubscriptionsByStatus(req.user.id, query.status); } return this.subscriptionsService.getSubscriptions(req.user.id); } @Get("active") async getActiveSubscriptions(@Request() req: RequestWithUser): Promise { return this.subscriptionsService.getActiveSubscriptions(req.user.id); } @Get("stats") async getSubscriptionStats(@Request() req: RequestWithUser): Promise<{ total: number; active: number; suspended: number; cancelled: number; pending: number; }> { return this.subscriptionsService.getSubscriptionStats(req.user.id); } @Get(":id") async getSubscriptionById( @Request() req: RequestWithUser, @Param("id", ParseIntPipe) subscriptionId: number ): Promise { if (subscriptionId <= 0) { throw new BadRequestException("Subscription ID must be a positive number"); } return this.subscriptionsService.getSubscriptionById(req.user.id, subscriptionId); } @Get(":id/invoices") @UsePipes(new ZodValidationPipe(invoiceListQuerySchema)) async getSubscriptionInvoices( @Request() req: RequestWithUser, @Param("id", ParseIntPipe) subscriptionId: number, @Query() query: InvoiceListQuery ): Promise { if (subscriptionId <= 0) { throw new BadRequestException("Subscription ID must be a positive number"); } return this.subscriptionsService.getSubscriptionInvoices(req.user.id, subscriptionId, query); } // ==================== SIM Management Endpoints ==================== @Get(":id/sim/debug") async debugSimSubscription( @Request() req: RequestWithUser, @Param("id", ParseIntPipe) subscriptionId: number ): Promise> { return this.simManagementService.debugSimSubscription(req.user.id, subscriptionId); } @Get(":id/sim") async getSimInfo( @Request() req: RequestWithUser, @Param("id", ParseIntPipe) subscriptionId: number ) { return this.simManagementService.getSimInfo(req.user.id, subscriptionId); } @Get(":id/sim/details") async getSimDetails( @Request() req: RequestWithUser, @Param("id", ParseIntPipe) subscriptionId: number ) { return this.simManagementService.getSimDetails(req.user.id, subscriptionId); } @Get(":id/sim/usage") async getSimUsage( @Request() req: RequestWithUser, @Param("id", ParseIntPipe) subscriptionId: number ) { return this.simManagementService.getSimUsage(req.user.id, subscriptionId); } @Get(":id/sim/top-up-history") async getSimTopUpHistory( @Request() req: RequestWithUser, @Param("id", ParseIntPipe) subscriptionId: number, @Query("fromDate") fromDate: string, @Query("toDate") toDate: string ) { if (!fromDate || !toDate) { throw new BadRequestException("fromDate and toDate are required"); } return this.simManagementService.getSimTopUpHistory(req.user.id, subscriptionId, { fromDate, toDate, }); } @Post(":id/sim/top-up") @UsePipes(new ZodValidationPipe(simTopupRequestSchema)) async topUpSim( @Request() req: RequestWithUser, @Param("id", ParseIntPipe) subscriptionId: number, @Body() body: SimTopupRequest ) { await this.simManagementService.topUpSim(req.user.id, subscriptionId, body); return { success: true, message: "SIM top-up completed successfully" }; } @Post(":id/sim/change-plan") @UsePipes(new ZodValidationPipe(simChangePlanRequestSchema)) async changeSimPlan( @Request() req: RequestWithUser, @Param("id", ParseIntPipe) subscriptionId: number, @Body() body: SimChangePlanRequest ) { const result = await this.simManagementService.changeSimPlan(req.user.id, subscriptionId, body); return { success: true, message: "SIM plan change completed successfully", ...result, }; } @Post(":id/sim/cancel") @UsePipes(new ZodValidationPipe(simCancelRequestSchema)) async cancelSim( @Request() req: RequestWithUser, @Param("id", ParseIntPipe) subscriptionId: number, @Body() body: SimCancelRequest ) { await this.simManagementService.cancelSim(req.user.id, subscriptionId, body); return { success: true, message: "SIM cancellation completed successfully" }; } @Post(":id/sim/reissue-esim") async reissueEsimProfile( @Request() req: RequestWithUser, @Param("id", ParseIntPipe) subscriptionId: number, @Body() body: { newEid?: string } = {} ) { await this.simManagementService.reissueEsimProfile(req.user.id, subscriptionId, body.newEid); return { success: true, message: "eSIM profile reissue completed successfully" }; } @Post(":id/sim/features") @UsePipes(new ZodValidationPipe(simFeaturesRequestSchema)) async updateSimFeatures( @Request() req: RequestWithUser, @Param("id", ParseIntPipe) subscriptionId: number, @Body() body: SimFeaturesRequest ) { await this.simManagementService.updateSimFeatures(req.user.id, subscriptionId, body); return { success: true, message: "SIM features updated successfully" }; } }