import {
  Controller,
  Get,
  Post,
  Patch,
  Body,
  Param,
  Query,
  HttpCode,
  HttpStatus,
  Logger,
  UseGuards,
} from "@nestjs/common";
import {
  ApiTags,
  ApiOperation,
  ApiQuery,
  ApiResponse,
  ApiParam,
  ApiBody,
  ApiBearerAuth,
} from "@nestjs/swagger";
import { SporTotoService } from "./spor-toto.service";
import {
  CreateBulletinDto,
  UpdateResultsDto,
  GenerateColumnsDto,
  GenerateSporTotoPredictionDto,
  EvaluateColumnsDto,
} from "./dto/spor-toto.dto";
import { Public, Roles } from "../../common/decorators";
import { JwtAuthGuard } from "../auth/guards/auth.guards";
import { TotoBulletinStatus } from "@prisma/client";

@ApiTags("Spor Toto")
@Controller("spor-toto")
export class SporTotoController {
  private readonly logger = new Logger(SporTotoController.name);

  constructor(private readonly sporTotoService: SporTotoService) {}

  // ═══════════ BULLETINS ═══════════

  @Post("sync")
  @UseGuards(JwtAuthGuard)
  @Roles("superadmin")
  @ApiBearerAuth()
  @HttpCode(HttpStatus.OK)
  @ApiOperation({
    summary: "Sync current bulletin from Spor Toto API",
    description:
      "Fetches the latest bulletin from sportotov2.iddaa.com and upserts it into the database. Updates match results and dividends if already exists.",
  })
  @ApiResponse({
    status: 200,
    description: "Sync result with action (created/updated/unchanged)",
    schema: { type: "object" },
  })
  async syncFromApi() {
    const result = await this.sporTotoService.syncFromApi();
    return { success: true, data: result };
  }

  @Get("bulletins")
  @Public()
  @ApiOperation({
    summary: "List Spor Toto bulletins",
    description:
      "Returns a paginated list of bulletins, optionally filtered by status.",
  })
  @ApiQuery({
    name: "status",
    required: false,
    enum: TotoBulletinStatus,
    description: "Filter by bulletin status",
  })
  @ApiQuery({
    name: "limit",
    required: false,
    type: Number,
    description: "Max results (default: 10)",
  })
  @ApiResponse({
    status: 200,
    description: "Array of bulletins with matches and results",
    schema: { type: "object" },
  })
  async listBulletins(
    @Query("status") status?: TotoBulletinStatus,
    @Query("limit") limit?: string,
  ) {
    const bulletins = await this.sporTotoService.listBulletins(
      status,
      Number(limit) || 10,
    );
    return { success: true, data: bulletins };
  }

  @Get("bulletins/:id")
  @Public()
  @ApiOperation({
    summary: "Get bulletin details",
    description:
      "Returns a single bulletin with all 15 matches, results, and dividend info.",
  })
  @ApiParam({ name: "id", description: "Bulletin UUID" })
  @ApiResponse({
    status: 200,
    description: "Bulletin with matches and results",
    schema: { type: "object" },
  })
  @ApiResponse({ status: 404, description: "Bulletin not found" })
  async getBulletin(@Param("id") id: string) {
    const bulletin = await this.sporTotoService.getBulletinById(id);
    return { success: true, data: bulletin };
  }

  @Post("bulletins")
  @UseGuards(JwtAuthGuard)
  @Roles("superadmin")
  @ApiBearerAuth()
  @HttpCode(HttpStatus.CREATED)
  @ApiOperation({
    summary: "Create a bulletin manually",
    description:
      "Creates a new bulletin with 15 matches. Fails if gameCycleNo already exists.",
  })
  @ApiBody({ type: CreateBulletinDto })
  @ApiResponse({
    status: 201,
    description: "Created bulletin with matches",
    schema: { type: "object" },
  })
  @ApiResponse({
    status: 409,
    description: "Bulletin with this gameCycleNo already exists",
  })
  async createBulletin(@Body() dto: CreateBulletinDto) {
    const bulletin = await this.sporTotoService.createBulletin(dto);
    return { success: true, data: bulletin };
  }

  @Patch("bulletins/:id/results")
  @UseGuards(JwtAuthGuard)
  @Roles("superadmin")
  @ApiBearerAuth()
  @HttpCode(HttpStatus.OK)
  @ApiOperation({
    summary: "Update bulletin match results",
    description:
      "Updates individual match results and optionally upserts dividend/prize data. Marks bulletin COMPLETED when all 15 results are entered.",
  })
  @ApiParam({ name: "id", description: "Bulletin UUID" })
  @ApiBody({ type: UpdateResultsDto })
  @ApiResponse({
    status: 200,
    description: "Updated bulletin with results",
    schema: { type: "object" },
  })
  @ApiResponse({ status: 404, description: "Bulletin not found" })
  async updateResults(@Param("id") id: string, @Body() dto: UpdateResultsDto) {
    const bulletin = await this.sporTotoService.updateResults(id, dto);
    return { success: true, data: bulletin };
  }

  // ═══════════ STATS & ANALYTICS ═══════════

  @Get("bulletins/:id/stats")
  @Public()
  @ApiOperation({
    summary: "Get bulletin pool & EV statistics",
    description:
      "Returns pool distribution (35/20/20/25), expected value calculations, and rollover analysis for a bulletin.",
  })
  @ApiParam({ name: "id", description: "Bulletin UUID" })
  @ApiResponse({
    status: 200,
    description: "Pool distribution and EV stats",
    schema: { type: "object" },
  })
  async getBulletinStats(@Param("id") id: string) {
    const stats = await this.sporTotoService.getBulletinStats(id);
    return { success: true, data: stats };
  }

  @Get("history")
  @Public()
  @ApiOperation({
    summary: "Get rollover history and trends",
    description:
      "Returns the last N bulletins with rollover amounts and consecutive rollover streak.",
  })
  @ApiQuery({
    name: "limit",
    required: false,
    type: Number,
    description: "Number of results (default: 20)",
  })
  @ApiResponse({
    status: 200,
    description: "Rollover history with trend data",
    schema: { type: "object" },
  })
  async getRolloverHistory(@Query("limit") limit?: string) {
    const history = await this.sporTotoService.getRolloverHistory(
      Number(limit) || 20,
    );
    return { success: true, data: history };
  }

  // ═══════════ COLUMNS ═══════════

  @Post("columns/generate")
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth()
  @HttpCode(HttpStatus.OK)
  @ApiOperation({
    summary: "Generate Spor Toto columns (full or reduced system)",
    description:
      "Takes match selections (1/X/2 per match) and generates columns via Cartesian product (full) or random sampling (reduced). Returns columns with cost calculation.",
  })
  @ApiBody({ type: GenerateColumnsDto })
  @ApiResponse({
    status: 200,
    description: "Generated columns with strategy, cost, and column strings",
    schema: { type: "object" },
  })
  async generateColumns(@Body() dto: GenerateColumnsDto) {
    const result = await this.sporTotoService.generateColumns(dto);
    return { success: true, data: result };
  }

  @Post("columns/evaluate")
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth()
  @HttpCode(HttpStatus.OK)
  @ApiOperation({
    summary: "Evaluate columns against results",
    description:
      "Compares generated column strings against actual match results. Returns correct count per column and summary (15/14/13/12 bilen).",
  })
  @ApiBody({ type: EvaluateColumnsDto })
  @ApiResponse({
    status: 200,
    description: "Evaluation results with correct counts per column",
    schema: { type: "object" },
  })
  async evaluateColumns(@Body() dto: EvaluateColumnsDto) {
    const result = await this.sporTotoService.evaluateColumns(
      dto.bulletinId,
      dto.columns,
    );
    return { success: true, data: result };
  }

  // ═══════════ AI PREDICTION ═══════════

  @Post("predict")
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth()
  @HttpCode(HttpStatus.OK)
  @ApiOperation({
    summary: "Generate AI predictions with contrarian strategy",
    description:
      "Analyzes bulletin matches via AI Engine V20+, applies contrarian parimutüel strategy, and generates optimized system coupons. Supports 4 strategies: CONSERVATIVE (100 cols), BALANCED (500), AGGRESSIVE (2500), FORMULA_6PCT (6% sampling).",
  })
  @ApiBody({ type: GenerateSporTotoPredictionDto })
  @ApiResponse({
    status: 200,
    description:
      "Prediction result with per-match analysis, system coupon, and EV report with play recommendation",
    schema: { type: "object" },
  })
  async generatePrediction(@Body() dto: GenerateSporTotoPredictionDto) {
    this.logger.log(
      `Generating prediction for bulletin ${dto.bulletinId} with strategy ${dto.strategy || "BALANCED"}`,
    );
    const result = await this.sporTotoService.generatePrediction(dto);
    return { success: true, data: result };
  }
}
