import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import {
  ArrayMaxSize,
  ArrayMinSize,
  IsArray,
  IsInt,
  IsUUID,
  Max,
  Min,
  ValidateNested,
} from 'class-validator';

/** Limite superior de gols. Alto o bastante para o futebol real, baixo o
 *  bastante para o valor não virar custo nem absurdo na tela. */
export const MAX_GOLS = 20;

export class PalpiteItemDto {
  @ApiProperty()
  @IsUUID()
  matchId!: string;

  @ApiProperty({ minimum: 0, maximum: MAX_GOLS })
  @IsInt({ message: 'o placar precisa ser um número inteiro' })
  @Min(0, { message: 'o placar não pode ser negativo' })
  @Max(MAX_GOLS, { message: `o placar não pode passar de ${MAX_GOLS}` })
  homeScore!: number;

  @ApiProperty({ minimum: 0, maximum: MAX_GOLS })
  @IsInt({ message: 'o placar precisa ser um número inteiro' })
  @Min(0, { message: 'o placar não pode ser negativo' })
  @Max(MAX_GOLS, { message: `o placar não pode passar de ${MAX_GOLS}` })
  awayScore!: number;
}

/**
 * Envio em lote. O casual palpita a rodada inteira de uma vez — mandar jogo
 * por jogo seria dez requisições com o prazo estourando.
 */
export class PalpitarDto {
  @ApiProperty({ type: [PalpiteItemDto] })
  @IsArray()
  @ArrayMinSize(1)
  @ArrayMaxSize(20)
  @ValidateNested({ each: true })
  @Type(() => PalpiteItemDto)
  predictions!: PalpiteItemDto[];
}

export type MotivoRecusa = 'PRAZO_FECHADO' | 'JOGO_FORA_DO_BOLAO';

export class ResultadoItemResponse {
  @ApiProperty() matchId!: string;
  @ApiProperty() saved!: boolean;
  @ApiProperty({
    nullable: true,
    enum: ['PRAZO_FECHADO', 'JOGO_FORA_DO_BOLAO'],
  })
  reason!: MotivoRecusa | null;
}

/**
 * Resultado item a item, de propósito.
 *
 * Se um jogo fechou entre abrir a tela e enviar, falhar o lote inteiro faria o
 * participante perder os outros nove palpites bons. Cada item responde por si.
 */
export class PalpitarResponse {
  @ApiProperty({ type: [ResultadoItemResponse] })
  results!: ResultadoItemResponse[];

  @ApiProperty() savedCount!: number;
  @ApiProperty() rejectedCount!: number;
}

export class JogoDaRodadaResponse {
  @ApiProperty() matchId!: string;
  @ApiProperty() matchday!: number;
  @ApiProperty() homeTeam!: string;
  @ApiProperty() awayTeam!: string;
  @ApiProperty({ description: 'horário oficial de início, em UTC' })
  kickoffAt!: Date;

  @ApiProperty({
    description: 'decidido pelo servidor, nunca pelo relógio do device',
  })
  deadlineOpen!: boolean;

  @ApiProperty({ nullable: true, description: 'meu palpite, se já enviei' })
  myPrediction!: { homeScore: number; awayScore: number } | null;

  @ApiProperty({ nullable: true, description: 'placar oficial, quando houver' })
  officialScore!: { homeScore: number; awayScore: number } | null;
}

export class RodadaResponse {
  @ApiProperty({
    description:
      'horário do servidor no momento da resposta. O app calcula a contagem a partir daqui, não do relógio do device',
  })
  serverTime!: Date;

  @ApiProperty({ type: [JogoDaRodadaResponse] })
  matches!: JogoDaRodadaResponse[];
}
