import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Patch,
  Post,
  Query,
  Put,
  Req,
  UseGuards,
} from '@nestjs/common';
import { UserRole } from '@prisma/client';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import type { AuthenticatedRequest } from '../auth/jwt-auth.guard';
import { Roles } from '../auth/roles.decorator';
import { RolesGuard } from '../auth/roles.guard';
import { CreateCardDto } from './dto/create-card.dto';
import {
  SetOutcomesDto,
  UpsertPredictionEntryDto,
  ValidateScoresDto,
} from './dto/prediction-value.dto';
import { UpdateCardDto } from './dto/update-card.dto';
import { PredictionsService } from './predictions.service';

@Controller('projects/:projectId/predictions')
@UseGuards(JwtAuthGuard)
export class ProjectPredictionsController {
  constructor(private readonly predictionsService: PredictionsService) {}

  @Get('cards')
  listCards(@Param('projectId') projectId: string) {
    return this.predictionsService.listCards(false, projectId);
  }

  @Get('board')
  board(
    @Req() request: AuthenticatedRequest,
    @Param('projectId') projectId: string,
    @Query('selectedBabyIndex') selectedBabyIndex?: string,
  ) {
    return this.predictionsService.getBoard(
      request.user!.sub,
      projectId,
      selectedBabyIndex ? Number(selectedBabyIndex) : undefined,
    );
  }

  @Get('activity')
  activity(@Req() request: AuthenticatedRequest, @Param('projectId') projectId: string) {
    return this.predictionsService.listActivity(request.user!.sub, projectId);
  }

  @Get('scoreboard')
  scoreboard(@Param('projectId') projectId: string) {
    return this.predictionsService.getScoreboard(projectId);
  }

  @Get('my-entries')
  myEntries(@Req() request: AuthenticatedRequest, @Param('projectId') projectId: string) {
    return this.predictionsService.listMyEntries(request.user!.sub, projectId);
  }

  @Put('cards/:cardId/my-entry')
  upsertMyEntry(
    @Req() request: AuthenticatedRequest,
    @Param('projectId') projectId: string,
    @Param('cardId') cardId: string,
    @Body() dto: UpsertPredictionEntryDto,
  ) {
    return this.predictionsService.upsertMyPrediction(request.user!.sub, cardId, dto, projectId);
  }

  @Post('game/close')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  closeGame(@Req() request: AuthenticatedRequest, @Param('projectId') projectId: string) {
    return this.predictionsService.closeGame(request.user!.sub, projectId);
  }

  @Post('game/open')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  openGame(@Req() request: AuthenticatedRequest, @Param('projectId') projectId: string) {
    return this.predictionsService.openGame(request.user!.sub, projectId);
  }

  @Post('game/finalize')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  finalizeGame(@Req() request: AuthenticatedRequest, @Param('projectId') projectId: string) {
    return this.predictionsService.finalizeGame(request.user!.sub, projectId);
  }

  @Post('cards')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  createCard(
    @Req() request: AuthenticatedRequest,
    @Param('projectId') projectId: string,
    @Body() dto: CreateCardDto,
  ) {
    return this.predictionsService.createCard(request.user!.sub, dto, projectId);
  }

  @Patch('cards/:cardId')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  updateCard(
    @Req() request: AuthenticatedRequest,
    @Param('projectId') projectId: string,
    @Param('cardId') cardId: string,
    @Body() dto: UpdateCardDto,
  ) {
    return this.predictionsService.updateCard(request.user!.sub, cardId, dto, projectId);
  }

  @Delete('cards/:cardId')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  deleteCard(
    @Req() request: AuthenticatedRequest,
    @Param('projectId') projectId: string,
    @Param('cardId') cardId: string,
  ) {
    return this.predictionsService.deleteCard(request.user!.sub, cardId, projectId);
  }

  @Post('cards/:cardId/outcomes')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  setOutcomes(
    @Req() request: AuthenticatedRequest,
    @Param('projectId') projectId: string,
    @Param('cardId') cardId: string,
    @Body() dto: SetOutcomesDto,
  ) {
    return this.predictionsService.setCardOutcomes(request.user!.sub, cardId, dto, projectId);
  }

  @Post('cards/:cardId/suggest-scores')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  suggestScores(
    @Req() request: AuthenticatedRequest,
    @Param('projectId') projectId: string,
    @Param('cardId') cardId: string,
    @Query('selectedBabyIndex') selectedBabyIndex?: string,
  ) {
    return this.predictionsService.suggestScoresForCard(
      request.user!.sub,
      cardId,
      projectId,
      selectedBabyIndex ? Number(selectedBabyIndex) : undefined,
    );
  }

  @Patch('entries/:entryId/scores')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  validateScores(
    @Req() request: AuthenticatedRequest,
    @Param('projectId') projectId: string,
    @Param('entryId') entryId: string,
    @Body() dto: ValidateScoresDto,
  ) {
    return this.predictionsService.validateScores(request.user!.sub, entryId, dto, projectId);
  }
}
