import {
  Controller,
  Get,
  Post,
  Body,
  Param,
  Query,
  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 { CurrentUser } from "src/common/decorators";
import { AnalysisService } from "../analysis/analysis.service";
import { ForbiddenException } from "@nestjs/common";

@ApiTags("Predictions")
@Controller("predictions")
export class PredictionsController {
  constructor(
    private readonly predictionsService: PredictionsService,
    private readonly analysisService: AnalysisService,
  ) {}

  /**
   * 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<AIHealthDto> {
    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<UpcomingPredictionsDto> {
    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" })
  @ApiResponse({
    status: 200,
    description: "Prediction details",
    schema: { type: "object" },
  })
  @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<ValueBetDto[]> {
    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<PredictionHistoryResponseDto> {
    return this.predictionsService.getPredictionHistory();
  }

  /**
   * GET /predictions/:matchId
   * Get prediction for a specific match
   */
  @Get(":matchId")
  @ApiOperation({ summary: "Get prediction for a specific match" })
  @ApiParam({ name: "matchId", description: "Match ID" })
  @ApiResponse({
    status: 200,
    description: "Match prediction",
    schema: { type: "object" },
    type: MatchPredictionDto,
  })
  @ApiResponse({ status: 404, description: "Match not found" })
  @ApiResponse({ status: 403, description: "Daily limit exceeded" })
  async getPrediction(
    @Param("matchId") matchId: string,
    @CurrentUser() user: any,
    @Query("nocache") nocache?: string,
  ): Promise<MatchPredictionDto> {
    const canProceed = await this.analysisService.checkUsageLimit(
      user.id,
      false,
      1,
    );
    if (!canProceed) {
      throw new ForbiddenException("ANALYSIS_LIMIT_EXCEEDED");
    }

    const bypassCache = nocache === "true" || nocache === "1";

    if (!bypassCache) {
      const cached = await this.predictionsService.getCachedPrediction(matchId);
      if (cached) {
        return cached;
      }
    }

    // Get from AI Engine (always fresh when nocache=true)
    const prediction = await this.predictionsService.getPredictionById(matchId);

    if (!prediction) {
      throw new NotFoundException("MATCH_NOT_FOUND");
    }

    await this.analysisService.recordUsage(user.id, false);
    return prediction;
  }

  /**
   * GET /predictions/:matchId/commentary
   * Get AI expert commentary for a match (separate async call)
   */
  @Get(":matchId/commentary")
  async getCommentary(
    @Param("matchId") matchId: string,
  ): Promise<{ commentary: string | null }> {
    const commentary = await this.predictionsService.getAiCommentary(matchId);
    return { commentary };
  }

  /**
   * 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 })
  @ApiResponse({ status: 403, description: "Daily limit exceeded" })
  async generatePrediction(
    @CurrentUser() user: any,
    @Body() dto: GeneratePredictionDto,
  ): Promise<MatchPredictionDto> {
    const canProceed = await this.analysisService.checkUsageLimit(
      user.id,
      false,
      1,
    );
    if (!canProceed) {
      throw new ForbiddenException("ANALYSIS_LIMIT_EXCEEDED");
    }

    const prediction = await this.predictionsService.getPredictionWithData({
      matchId: dto.matchId,
    });

    if (!prediction) {
      throw new NotFoundException("PREDICTION_GENERATION_FAILED");
    }

    await this.analysisService.recordUsage(user.id, false);
    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",
    schema: { type: "object" },
  })
  @ApiResponse({ status: 403, description: "Daily limit exceeded" })
  async generateSmartCoupon(
    @CurrentUser() user: any,
    @Body() dto: SmartCouponRequestDto,
  ): Promise<any> {
    const canProceed = await this.analysisService.checkUsageLimit(
      user.id,
      true,
      dto.matchIds?.length || 1,
    );
    if (!canProceed) {
      throw new ForbiddenException("COUPON_LIMIT_EXCEEDED");
    }

    const coupon = await this.predictionsService.getSmartCoupon(
      dto.matchIds,
      dto.strategy || "BALANCED",
      {
        maxMatches: dto.maxMatches,
        minConfidence: dto.minConfidence,
      },
    );

    if (!coupon) {
      throw new NotFoundException("SMART_COUPON_GENERATION_FAILED");
    }

    await this.analysisService.recordUsage(user.id, true);
    return coupon;
  }
}
