import { Controller, Get, Post, Body, Param, HttpCode, HttpStatus, NotFoundException, } from "@nestjs/common"; import { ApiTags, ApiOperation, ApiResponse, ApiParam } from "@nestjs/swagger"; import { PredictionsService } from "./predictions.service"; import { MatchPredictionDto, PredictionHistoryResponseDto, UpcomingPredictionsDto, ValueBetDto, AIHealthDto, } from "./dto"; import { GeneratePredictionDto, SmartCouponRequestDto, } from "./dto/predictions-request.dto"; import { Public } from "src/common/decorators"; @ApiTags("Predictions") @Controller("predictions") export class PredictionsController { constructor(private readonly predictionsService: PredictionsService) {} /** * GET /predictions/health * Check AI Engine health status */ @Get("health") @ApiOperation({ summary: "Check AI Engine health status" }) @ApiResponse({ status: 200, type: AIHealthDto }) async checkHealth(): Promise { return this.predictionsService.checkHealth(); } /** * GET /predictions/upcoming * Get predictions for upcoming matches */ @Get("upcoming") @ApiOperation({ summary: "Get predictions for upcoming matches" }) @ApiResponse({ status: 200, type: UpcomingPredictionsDto }) async getUpcoming(): Promise { return this.predictionsService.getUpcomingPredictions(); } /** * GET /predictions/test/:id * Refetch match data and get prediction */ @Get("test/:id") @ApiOperation({ summary: "Refetch match data and get prediction" }) @ApiParam({ name: "id", description: "Match ID" }) async getTestPrediction(@Param("id") id: string) { return this.predictionsService.testPrediction(id); } /** * GET /predictions/value-bets * Get EV+ betting opportunities */ @Get("value-bets") @ApiOperation({ summary: "Get value betting opportunities (EV+)" }) @ApiResponse({ status: 200, type: [ValueBetDto] }) async getValueBets(): Promise { return this.predictionsService.getValueBets(); } /** * GET /predictions/history * Get prediction history and accuracy stats */ @Get("history") @ApiOperation({ summary: "Get prediction history and accuracy statistics" }) @ApiResponse({ status: 200, type: PredictionHistoryResponseDto }) async getHistory(): Promise { return this.predictionsService.getPredictionHistory(); } /** * GET /predictions/:matchId * Get prediction for a specific match */ @Get(":matchId") @Public() @ApiOperation({ summary: "Get prediction for a specific match" }) @ApiParam({ name: "matchId", description: "Match ID" }) @ApiResponse({ status: 200, type: MatchPredictionDto }) @ApiResponse({ status: 404, description: "Match not found" }) async getPrediction( @Param("matchId") matchId: string, ): Promise { // Check cache first - DISABLED per user request to always fetch from scratch // const cached = await this.predictionsService.getCachedPrediction(matchId); // if (cached) { // return cached; // } // Get from AI Engine const prediction = await this.predictionsService.getPredictionById(matchId); if (!prediction) { throw new NotFoundException(`Match not found: ${matchId}`); } return prediction; } /** * POST /predictions/generate * Generate prediction with provided match data */ @Post("generate") @HttpCode(HttpStatus.OK) @ApiOperation({ summary: "Generate prediction with provided match data" }) @ApiResponse({ status: 200, type: MatchPredictionDto }) async generatePrediction( @Body() dto: GeneratePredictionDto, ): Promise { const prediction = await this.predictionsService.getPredictionWithData({ matchId: dto.matchId, }); if (!prediction) { throw new NotFoundException("Failed to generate prediction"); } return prediction; } /** * POST /predictions/smart-coupon * Generate Smart Coupon using AI Engine V20 */ @Post("smart-coupon") @HttpCode(HttpStatus.OK) @ApiOperation({ summary: "Generate Smart Coupon with V20 AI recommendations", }) @ApiResponse({ status: 200, description: "Smart coupon generated successfully", }) async generateSmartCoupon(@Body() dto: SmartCouponRequestDto): Promise { const coupon = await this.predictionsService.getSmartCoupon( dto.matchIds, dto.strategy || "BALANCED", { maxMatches: dto.maxMatches, minConfidence: dto.minConfidence, }, ); if (!coupon) { throw new NotFoundException("Failed to generate Smart Coupon"); } return coupon; } }