import { Component, inject, OnInit, OnDestroy, DestroyRef, Output, EventEmitter } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { finalize } from 'rxjs'; import { ChallengeService } from '../../services/challenge.service'; import { Router } from '@angular/router'; import { getErrorMessage } from '../../core/http/error-message.util'; import { PlayerColor } from '../../models/challenge.models'; type TimeMode = 'blitz' | 'rapid' | 'classical' | 'unlimited'; interface TimePreset { label: string; limitSeconds: number; incrementSeconds: number; } @Component({ selector: 'app-challenge-create-dialog', standalone: true, imports: [CommonModule, FormsModule, ReactiveFormsModule], templateUrl: './challenge-create-dialog.component.html', styleUrls: ['./challenge-create-dialog.component.css'] }) export class ChallengeCreateDialogComponent implements OnInit, OnDestroy { private readonly challengeService = inject(ChallengeService); private readonly router = inject(Router); private readonly fb = inject(FormBuilder); private readonly destroyRef = inject(DestroyRef); @Output() closeChallengeDialog = new EventEmitter(); form!: FormGroup; loading = false; errorMessage = ''; selectedTimeMode: TimeMode = 'rapid'; timePresets: Record = { blitz: [ { label: '1+0', limitSeconds: 60, incrementSeconds: 0 }, { label: '2+1', limitSeconds: 120, incrementSeconds: 1 }, { label: '3+0', limitSeconds: 180, incrementSeconds: 0 }, { label: '3+2', limitSeconds: 180, incrementSeconds: 2 }, { label: '5+0', limitSeconds: 300, incrementSeconds: 0 } ], rapid: [ { label: '10+0', limitSeconds: 600, incrementSeconds: 0 }, { label: '10+5', limitSeconds: 600, incrementSeconds: 5 }, { label: '15+10', limitSeconds: 900, incrementSeconds: 10 }, { label: '25+10', limitSeconds: 1500, incrementSeconds: 10 } ], classical: [ { label: '30+0', limitSeconds: 1800, incrementSeconds: 0 }, { label: '30+20', limitSeconds: 1800, incrementSeconds: 20 }, { label: '60+30', limitSeconds: 3600, incrementSeconds: 30 }, { label: '90+30', limitSeconds: 5400, incrementSeconds: 30 } ], unlimited: [] }; ttlOptions = [ { label: '5 minutes', seconds: 300 }, { label: '1 hour', seconds: 3600 }, { label: '1 day', seconds: 86400 }, { label: 'No expiry', seconds: 0 } ]; ngOnInit(): void { this.initializeForm(); } ngOnDestroy(): void { } private initializeForm(): void { this.form = this.fb.group({ targetUsername: ['', [Validators.required, Validators.minLength(1)]], color: ['random', Validators.required], timeMode: ['rapid'], limitMinutes: [10, [Validators.required, Validators.min(1), Validators.max(1000)]], incrementSeconds: [5, [Validators.required, Validators.min(0), Validators.max(300)]], ttlSeconds: [3600, Validators.required] }); this.form.get('timeMode')?.valueChanges .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((mode: unknown) => { const timeMode = mode as TimeMode; this.selectedTimeMode = timeMode; if (timeMode !== 'unlimited') { const firstPreset = this.timePresets[timeMode][0]; if (firstPreset) { this.form.patchValue({ limitMinutes: firstPreset.limitSeconds / 60, incrementSeconds: firstPreset.incrementSeconds }); } } }); } selectPreset(preset: TimePreset): void { this.form.patchValue({ limitMinutes: preset.limitSeconds / 60, incrementSeconds: preset.incrementSeconds }); } getAvailablePresets(): TimePreset[] { return this.timePresets[this.selectedTimeMode] || []; } submit(): void { if (this.form.invalid || this.loading) { return; } const targetUsername = this.form.get('targetUsername')?.value?.trim(); if (!targetUsername) { this.errorMessage = 'Please enter a valid username'; return; } this.errorMessage = ''; this.loading = true; this.form.disable(); const limitSeconds = Math.round((this.form.getRawValue().limitMinutes || 0) * 60); const { incrementSeconds, ttlSeconds, color: rawColor } = this.form.getRawValue(); const color = (rawColor || 'random') as PlayerColor; this.challengeService.sendChallenge(targetUsername, { timeControl: { limitSeconds, incrementSeconds }, color, ttlSeconds: ttlSeconds > 0 ? ttlSeconds : undefined }) .pipe(finalize(() => { this.loading = false; this.form.enable(); })) .subscribe({ next: (challenge) => { // Challenge sent successfully - navigate to challenges page to view status this.form.reset(); this.closeChallengeDialog.emit(); void this.router.navigate(['/challenges']); }, error: (error) => { this.errorMessage = getErrorMessage(error, 'Failed to send challenge. Please try again.'); } }); } cancel(): void { this.form.reset(); this.closeChallengeDialog.emit(); } }